glaip-sdk 0.6.19__py3-none-any.whl → 0.7.27__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/agents/base.py +283 -30
- glaip_sdk/agents/component.py +233 -0
- glaip_sdk/branding.py +113 -2
- glaip_sdk/cli/account_store.py +15 -0
- glaip_sdk/cli/auth.py +14 -8
- glaip_sdk/cli/commands/accounts.py +1 -1
- glaip_sdk/cli/commands/agents/__init__.py +116 -0
- glaip_sdk/cli/commands/agents/_common.py +562 -0
- glaip_sdk/cli/commands/agents/create.py +155 -0
- glaip_sdk/cli/commands/agents/delete.py +64 -0
- glaip_sdk/cli/commands/agents/get.py +89 -0
- glaip_sdk/cli/commands/agents/list.py +129 -0
- glaip_sdk/cli/commands/agents/run.py +264 -0
- glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
- glaip_sdk/cli/commands/agents/update.py +112 -0
- glaip_sdk/cli/commands/common_config.py +1 -1
- glaip_sdk/cli/commands/configure.py +1 -2
- glaip_sdk/cli/commands/mcps/__init__.py +94 -0
- glaip_sdk/cli/commands/mcps/_common.py +459 -0
- glaip_sdk/cli/commands/mcps/connect.py +82 -0
- glaip_sdk/cli/commands/mcps/create.py +152 -0
- glaip_sdk/cli/commands/mcps/delete.py +73 -0
- glaip_sdk/cli/commands/mcps/get.py +212 -0
- glaip_sdk/cli/commands/mcps/list.py +69 -0
- glaip_sdk/cli/commands/mcps/tools.py +235 -0
- glaip_sdk/cli/commands/mcps/update.py +190 -0
- glaip_sdk/cli/commands/models.py +2 -4
- glaip_sdk/cli/commands/shared/__init__.py +21 -0
- glaip_sdk/cli/commands/shared/formatters.py +91 -0
- glaip_sdk/cli/commands/tools/__init__.py +69 -0
- glaip_sdk/cli/commands/tools/_common.py +80 -0
- glaip_sdk/cli/commands/tools/create.py +228 -0
- glaip_sdk/cli/commands/tools/delete.py +61 -0
- glaip_sdk/cli/commands/tools/get.py +103 -0
- glaip_sdk/cli/commands/tools/list.py +69 -0
- glaip_sdk/cli/commands/tools/script.py +49 -0
- glaip_sdk/cli/commands/tools/update.py +102 -0
- glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
- glaip_sdk/cli/commands/transcripts/_common.py +9 -0
- glaip_sdk/cli/commands/transcripts/clear.py +5 -0
- glaip_sdk/cli/commands/transcripts/detail.py +5 -0
- glaip_sdk/cli/commands/{transcripts.py → transcripts_original.py} +2 -1
- glaip_sdk/cli/commands/update.py +163 -17
- glaip_sdk/cli/config.py +1 -0
- glaip_sdk/cli/entrypoint.py +20 -0
- glaip_sdk/cli/main.py +112 -35
- glaip_sdk/cli/pager.py +3 -3
- glaip_sdk/cli/resolution.py +2 -1
- glaip_sdk/cli/slash/accounts_controller.py +3 -1
- glaip_sdk/cli/slash/agent_session.py +1 -1
- glaip_sdk/cli/slash/remote_runs_controller.py +3 -1
- glaip_sdk/cli/slash/session.py +343 -20
- glaip_sdk/cli/slash/tui/__init__.py +29 -1
- glaip_sdk/cli/slash/tui/accounts.tcss +97 -6
- glaip_sdk/cli/slash/tui/accounts_app.py +1117 -126
- glaip_sdk/cli/slash/tui/clipboard.py +316 -0
- glaip_sdk/cli/slash/tui/context.py +92 -0
- glaip_sdk/cli/slash/tui/indicators.py +341 -0
- glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
- glaip_sdk/cli/slash/tui/layouts/__init__.py +14 -0
- glaip_sdk/cli/slash/tui/layouts/harlequin.py +184 -0
- glaip_sdk/cli/slash/tui/loading.py +43 -21
- glaip_sdk/cli/slash/tui/remote_runs_app.py +178 -20
- glaip_sdk/cli/slash/tui/terminal.py +407 -0
- glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
- glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
- glaip_sdk/cli/slash/tui/theme/manager.py +112 -0
- glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
- glaip_sdk/cli/slash/tui/toast.py +388 -0
- glaip_sdk/cli/transcript/history.py +1 -1
- glaip_sdk/cli/transcript/viewer.py +1 -1
- glaip_sdk/cli/tui_settings.py +125 -0
- glaip_sdk/cli/update_notifier.py +215 -7
- glaip_sdk/cli/validators.py +1 -1
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_schedule_payloads.py +89 -0
- glaip_sdk/client/agents.py +293 -17
- glaip_sdk/client/base.py +25 -0
- glaip_sdk/client/hitl.py +136 -0
- glaip_sdk/client/main.py +7 -5
- glaip_sdk/client/mcps.py +44 -13
- glaip_sdk/client/payloads/agent/__init__.py +23 -0
- glaip_sdk/client/{_agent_payloads.py → payloads/agent/requests.py} +28 -48
- glaip_sdk/client/payloads/agent/responses.py +43 -0
- glaip_sdk/client/run_rendering.py +109 -30
- glaip_sdk/client/schedules.py +439 -0
- glaip_sdk/client/tools.py +52 -23
- glaip_sdk/config/constants.py +22 -2
- glaip_sdk/guardrails/__init__.py +80 -0
- glaip_sdk/guardrails/serializer.py +91 -0
- glaip_sdk/hitl/__init__.py +35 -2
- glaip_sdk/hitl/base.py +64 -0
- glaip_sdk/hitl/callback.py +43 -0
- glaip_sdk/hitl/local.py +1 -31
- glaip_sdk/hitl/remote.py +523 -0
- glaip_sdk/models/__init__.py +47 -1
- glaip_sdk/models/_provider_mappings.py +101 -0
- glaip_sdk/models/_validation.py +97 -0
- glaip_sdk/models/agent.py +2 -1
- glaip_sdk/models/agent_runs.py +2 -1
- glaip_sdk/models/constants.py +141 -0
- glaip_sdk/models/model.py +170 -0
- glaip_sdk/models/schedule.py +224 -0
- glaip_sdk/payload_schemas/agent.py +1 -0
- glaip_sdk/payload_schemas/guardrails.py +34 -0
- glaip_sdk/ptc.py +145 -0
- glaip_sdk/registry/tool.py +270 -57
- glaip_sdk/runner/__init__.py +20 -3
- glaip_sdk/runner/deps.py +4 -1
- glaip_sdk/runner/langgraph.py +251 -27
- glaip_sdk/runner/logging_config.py +77 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +30 -9
- glaip_sdk/runner/ptc_adapter.py +98 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +25 -2
- glaip_sdk/schedules/__init__.py +22 -0
- glaip_sdk/schedules/base.py +291 -0
- glaip_sdk/tools/base.py +67 -14
- glaip_sdk/utils/__init__.py +1 -0
- glaip_sdk/utils/agent_config.py +8 -2
- glaip_sdk/utils/bundler.py +138 -2
- glaip_sdk/utils/import_resolver.py +427 -49
- glaip_sdk/utils/runtime_config.py +3 -2
- glaip_sdk/utils/sync.py +31 -11
- glaip_sdk/utils/tool_detection.py +274 -6
- {glaip_sdk-0.6.19.dist-info → glaip_sdk-0.7.27.dist-info}/METADATA +22 -8
- glaip_sdk-0.7.27.dist-info/RECORD +227 -0
- {glaip_sdk-0.6.19.dist-info → glaip_sdk-0.7.27.dist-info}/WHEEL +1 -1
- glaip_sdk-0.7.27.dist-info/entry_points.txt +2 -0
- glaip_sdk/cli/commands/agents.py +0 -1509
- glaip_sdk/cli/commands/mcps.py +0 -1356
- glaip_sdk/cli/commands/tools.py +0 -576
- glaip_sdk/cli/utils.py +0 -263
- glaip_sdk-0.6.19.dist-info/RECORD +0 -163
- glaip_sdk-0.6.19.dist-info/entry_points.txt +0 -2
- {glaip_sdk-0.6.19.dist-info → glaip_sdk-0.7.27.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Agent Component for Glaip SDK.
|
|
2
|
+
|
|
3
|
+
This module provides the AgentComponent class, which wraps an Agent
|
|
4
|
+
to be used as a reusable component in pipelines.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
from gllm_core.schema import Chunk, Component
|
|
15
|
+
from gllm_core.utils import LoggerManager
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from glaip_sdk.agents import Agent
|
|
19
|
+
|
|
20
|
+
logger = LoggerManager().get_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AgentComponent(Component):
|
|
24
|
+
"""A Component that wraps a GL Agent for pipeline integration.
|
|
25
|
+
|
|
26
|
+
This component acts as a bridge between structured pipeline state
|
|
27
|
+
and the natural language interface of an Agent. It compiles inputs
|
|
28
|
+
(query, context, history) into a prompt and executes the agent.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, agent: Agent) -> None:
|
|
32
|
+
"""Initialize the AgentComponent.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
agent: The Agent instance to wrap.
|
|
36
|
+
"""
|
|
37
|
+
super().__init__()
|
|
38
|
+
self.agent = agent
|
|
39
|
+
|
|
40
|
+
def _format_context(self, context: list[Chunk | str | dict[str, Any] | Any] | None) -> str:
|
|
41
|
+
"""Format the context list into a string.
|
|
42
|
+
|
|
43
|
+
Supports Chunk objects (extracting content), strings, and dicts.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
context: List of context items.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Formatted context string.
|
|
50
|
+
"""
|
|
51
|
+
if not context:
|
|
52
|
+
return ""
|
|
53
|
+
|
|
54
|
+
formatted_items = []
|
|
55
|
+
for item in context:
|
|
56
|
+
if isinstance(item, Chunk):
|
|
57
|
+
content = item.content
|
|
58
|
+
elif isinstance(item, dict):
|
|
59
|
+
content = str(item)
|
|
60
|
+
else:
|
|
61
|
+
content = str(item)
|
|
62
|
+
formatted_items.append(f"- {content}")
|
|
63
|
+
|
|
64
|
+
return "\n".join(formatted_items)
|
|
65
|
+
|
|
66
|
+
def _format_history(self, history: list[Any] | None) -> str:
|
|
67
|
+
"""Format the chat history into a string.
|
|
68
|
+
|
|
69
|
+
Supports gllm_inference Message objects and dicts.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
history: List of history items.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Formatted history string.
|
|
76
|
+
"""
|
|
77
|
+
if not history:
|
|
78
|
+
return "No previous history."
|
|
79
|
+
|
|
80
|
+
# Try to use gllm_inference schema if available for robust handling
|
|
81
|
+
try:
|
|
82
|
+
from gllm_inference.schema import Message # noqa: PLC0415
|
|
83
|
+
except ImportError:
|
|
84
|
+
Message = None
|
|
85
|
+
|
|
86
|
+
formatted_items = []
|
|
87
|
+
for item in history:
|
|
88
|
+
if Message and isinstance(item, Message):
|
|
89
|
+
# Message object has role and contents (list)
|
|
90
|
+
role = item.role.capitalize()
|
|
91
|
+
# Use standard content property if available, or join contents
|
|
92
|
+
content = getattr(item, "content", None)
|
|
93
|
+
if content is None and hasattr(item, "contents"):
|
|
94
|
+
content = "\n".join([str(c) for c in item.contents])
|
|
95
|
+
formatted_items.append(f"{role}: {content}")
|
|
96
|
+
elif isinstance(item, dict):
|
|
97
|
+
role = str(item.get("role", "User")).capitalize()
|
|
98
|
+
content = str(item.get("content", ""))
|
|
99
|
+
formatted_items.append(f"{role}: {content}")
|
|
100
|
+
else:
|
|
101
|
+
formatted_items.append(str(item))
|
|
102
|
+
return "\n".join(formatted_items)
|
|
103
|
+
|
|
104
|
+
def _compile_prompt(
|
|
105
|
+
self,
|
|
106
|
+
query: str,
|
|
107
|
+
context: list[Any] | None,
|
|
108
|
+
chat_history: list[Any] | None,
|
|
109
|
+
) -> str:
|
|
110
|
+
"""Compile the raw inputs into a single text prompt.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
query: The user query.
|
|
114
|
+
context: List of context items.
|
|
115
|
+
chat_history: List of conversation history items.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The compiled prompt string.
|
|
119
|
+
"""
|
|
120
|
+
parts = []
|
|
121
|
+
|
|
122
|
+
if chat_history:
|
|
123
|
+
history_str = self._format_history(chat_history)
|
|
124
|
+
parts.append(f"Conversation History:\n{history_str}\n")
|
|
125
|
+
|
|
126
|
+
if context:
|
|
127
|
+
context_str = self._format_context(context)
|
|
128
|
+
parts.append(f"Context:\n{context_str}\n")
|
|
129
|
+
|
|
130
|
+
parts.append(f"{query}\n")
|
|
131
|
+
|
|
132
|
+
return "\n".join(parts)
|
|
133
|
+
|
|
134
|
+
async def run_agent(
|
|
135
|
+
self,
|
|
136
|
+
query: str,
|
|
137
|
+
context: list[Chunk | Any] | None = None,
|
|
138
|
+
chat_history: list[Any] | None = None,
|
|
139
|
+
runtime_config: dict[str, Any] | None = None,
|
|
140
|
+
run_kwargs: dict[str, Any] | None = None,
|
|
141
|
+
) -> dict[str, Any]:
|
|
142
|
+
"""Run the agent with the provided context and history.
|
|
143
|
+
|
|
144
|
+
This method is the main entry point for the component logic.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
query: The user's input string.
|
|
148
|
+
context: List of retrieved documents/chunks or data.
|
|
149
|
+
chat_history: List of previous conversation turns.
|
|
150
|
+
runtime_config: Optional configuration.
|
|
151
|
+
run_kwargs: Optional payload for advanced agent execution parameters.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
The raw response dictionary from the agent.
|
|
155
|
+
"""
|
|
156
|
+
if not query:
|
|
157
|
+
raise ValueError("Query is required")
|
|
158
|
+
|
|
159
|
+
logger.info("Compiling prompt for agent: %s", self.agent.name)
|
|
160
|
+
|
|
161
|
+
prompt = self._compile_prompt(
|
|
162
|
+
query=query,
|
|
163
|
+
context=context,
|
|
164
|
+
chat_history=chat_history,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
params = (run_kwargs or {}).copy()
|
|
168
|
+
if runtime_config:
|
|
169
|
+
params["runtime_config"] = runtime_config
|
|
170
|
+
|
|
171
|
+
last_chunk = {}
|
|
172
|
+
|
|
173
|
+
try:
|
|
174
|
+
async for chunk in self.agent.arun(message=prompt, **params):
|
|
175
|
+
if isinstance(chunk, dict):
|
|
176
|
+
last_chunk = chunk
|
|
177
|
+
if chunk.get("event_type") == "final_response":
|
|
178
|
+
return chunk
|
|
179
|
+
except Exception as e:
|
|
180
|
+
raise RuntimeError(f"AgentComponent '{self.agent.name}' failed during execution: {e}") from e
|
|
181
|
+
|
|
182
|
+
return last_chunk
|
|
183
|
+
|
|
184
|
+
def _extract_content_string(self, result: Any) -> str:
|
|
185
|
+
"""Extract the content string from the agent response.
|
|
186
|
+
|
|
187
|
+
Assumes the result is always a string or a dictionary containing a content field.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
result: The agent response (dict or string).
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
The content string extracted from the response.
|
|
194
|
+
"""
|
|
195
|
+
if isinstance(result, dict):
|
|
196
|
+
content = result.get("content")
|
|
197
|
+
if content is not None:
|
|
198
|
+
return str(content)
|
|
199
|
+
return str(result)
|
|
200
|
+
|
|
201
|
+
return str(result) if result is not None else ""
|
|
202
|
+
|
|
203
|
+
async def _run(self, **kwargs: Any) -> str:
|
|
204
|
+
"""Execute the component logic.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
**kwargs: Keyword arguments including query, context, chat_history,
|
|
208
|
+
runtime_config, and run_kwargs. All execution control parameters
|
|
209
|
+
(e.g., local, verbose, temperature, etc.) must be provided via
|
|
210
|
+
run_kwargs dict.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
The content string extracted from the response.
|
|
214
|
+
"""
|
|
215
|
+
# Extract standard component inputs
|
|
216
|
+
query = kwargs.pop("query", None)
|
|
217
|
+
context = kwargs.pop("context", None)
|
|
218
|
+
chat_history = kwargs.pop("chat_history", None)
|
|
219
|
+
runtime_config = kwargs.pop("runtime_config", None)
|
|
220
|
+
run_kwargs = kwargs.pop("run_kwargs", None)
|
|
221
|
+
|
|
222
|
+
# Ignore any remaining unrecognized kwargs for API consistency
|
|
223
|
+
# All execution parameters must be provided via run_kwargs
|
|
224
|
+
|
|
225
|
+
result = await self.run_agent(
|
|
226
|
+
query=query, # type: ignore[arg-type]
|
|
227
|
+
context=context,
|
|
228
|
+
chat_history=chat_history,
|
|
229
|
+
runtime_config=runtime_config,
|
|
230
|
+
run_kwargs=run_kwargs,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return self._extract_content_string(result)
|
glaip_sdk/branding.py
CHANGED
|
@@ -17,6 +17,7 @@ import platform
|
|
|
17
17
|
import sys
|
|
18
18
|
|
|
19
19
|
from rich.console import Console
|
|
20
|
+
from rich.text import Text
|
|
20
21
|
|
|
21
22
|
from glaip_sdk._version import __version__ as SDK_VERSION
|
|
22
23
|
from glaip_sdk.rich_components import AIPPanel
|
|
@@ -110,9 +111,13 @@ GDP Labs AI Agents Package
|
|
|
110
111
|
return SDK_VERSION
|
|
111
112
|
|
|
112
113
|
@staticmethod
|
|
113
|
-
def _make_console() -> Console:
|
|
114
|
+
def _make_console(force_terminal: bool | None = None, *, soft_wrap: bool = True) -> Console:
|
|
114
115
|
"""Create a Rich Console instance respecting NO_COLOR environment variables.
|
|
115
116
|
|
|
117
|
+
Args:
|
|
118
|
+
force_terminal: Override terminal detection when True/False.
|
|
119
|
+
soft_wrap: Whether to enable soft wrapping in the console.
|
|
120
|
+
|
|
116
121
|
Returns:
|
|
117
122
|
Console instance with color system configured based on environment.
|
|
118
123
|
"""
|
|
@@ -124,7 +129,12 @@ GDP Labs AI Agents Package
|
|
|
124
129
|
else:
|
|
125
130
|
color_system = "auto"
|
|
126
131
|
no_color = False
|
|
127
|
-
return Console(
|
|
132
|
+
return Console(
|
|
133
|
+
color_system=color_system,
|
|
134
|
+
no_color=no_color,
|
|
135
|
+
soft_wrap=soft_wrap,
|
|
136
|
+
force_terminal=force_terminal,
|
|
137
|
+
)
|
|
128
138
|
|
|
129
139
|
# ---- public API -----------------------------------------------------------
|
|
130
140
|
def get_welcome_banner(self) -> str:
|
|
@@ -209,3 +219,104 @@ GDP Labs AI Agents Package
|
|
|
209
219
|
AIPBranding instance
|
|
210
220
|
"""
|
|
211
221
|
return cls(version=sdk_version, package_name=package_name)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class LogoAnimator:
|
|
225
|
+
"""Animated logo with pulse effect for CLI startup.
|
|
226
|
+
|
|
227
|
+
Provides a "Knight Rider" style light pulse animation that sweeps across
|
|
228
|
+
the GL AIP logo during initialization tasks. Respects NO_COLOR and non-TTY
|
|
229
|
+
environments with graceful degradation.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
# Animation colors from GDP Labs brand palette
|
|
233
|
+
BASE_BLUE = SECONDARY_MEDIUM # "#005CB8" - Medium Blue
|
|
234
|
+
HIGHLIGHT = SECONDARY_LIGHT # "#40B4E5" - Light Blue
|
|
235
|
+
WHITE = "#FFFFFF" # Bright white center
|
|
236
|
+
|
|
237
|
+
def __init__(self, console: Console | None = None) -> None:
|
|
238
|
+
"""Initialize LogoAnimator.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
console: Optional console instance. If None, creates a default console.
|
|
242
|
+
"""
|
|
243
|
+
self.console = console or AIPBranding._make_console()
|
|
244
|
+
self.logo = AIPBranding.AIP_LOGO
|
|
245
|
+
self.lines = self.logo.split("\n")
|
|
246
|
+
self.max_width = max(len(line) for line in self.lines) if self.lines else 0
|
|
247
|
+
|
|
248
|
+
def generate_frame(self, step: int, status_text: str = "") -> Text:
|
|
249
|
+
"""Generate a single animation frame with logo pulse and status.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
step: Current animation step (position of the pulse).
|
|
253
|
+
status_text: Optional status text to display below the logo.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Text object with styled logo and status.
|
|
257
|
+
"""
|
|
258
|
+
text = Text()
|
|
259
|
+
|
|
260
|
+
for line in self.lines:
|
|
261
|
+
for x, char in enumerate(line):
|
|
262
|
+
distance = abs(x - step)
|
|
263
|
+
|
|
264
|
+
if distance == 0:
|
|
265
|
+
style = f"bold {self.WHITE}" # Bright white center
|
|
266
|
+
elif distance <= 3:
|
|
267
|
+
style = f"bold {self.HIGHLIGHT}" # Light blue glow
|
|
268
|
+
else:
|
|
269
|
+
style = self.BASE_BLUE # Base blue
|
|
270
|
+
|
|
271
|
+
text.append(char, style=style)
|
|
272
|
+
text.append("\n")
|
|
273
|
+
|
|
274
|
+
# Add status area below the logo
|
|
275
|
+
if status_text:
|
|
276
|
+
text.append(f"\n{status_text}\n")
|
|
277
|
+
|
|
278
|
+
return text
|
|
279
|
+
|
|
280
|
+
def should_animate(self) -> bool:
|
|
281
|
+
"""Check if animation should be used.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
True if animation should be used (interactive TTY with colors),
|
|
285
|
+
False otherwise (NO_COLOR set or non-TTY).
|
|
286
|
+
"""
|
|
287
|
+
# Check for NO_COLOR environment variables
|
|
288
|
+
no_color = os.getenv("NO_COLOR") is not None or os.getenv("AIP_NO_COLOR") is not None
|
|
289
|
+
if no_color:
|
|
290
|
+
return False
|
|
291
|
+
|
|
292
|
+
# Check if console is a TTY
|
|
293
|
+
if not self.console.is_terminal:
|
|
294
|
+
return False
|
|
295
|
+
|
|
296
|
+
# Check if console explicitly disables colors
|
|
297
|
+
if self.console.no_color:
|
|
298
|
+
return False
|
|
299
|
+
|
|
300
|
+
# If we get here, we have a TTY without NO_COLOR set
|
|
301
|
+
# Rich will handle color detection, so we can animate
|
|
302
|
+
return True
|
|
303
|
+
|
|
304
|
+
def display_static_logo(self, status_text: str = "") -> None:
|
|
305
|
+
"""Display static logo without animation (for non-TTY or NO_COLOR).
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
status_text: Optional status text to display below the logo.
|
|
309
|
+
"""
|
|
310
|
+
self.console.print(self.static_frame(status_text))
|
|
311
|
+
|
|
312
|
+
def static_frame(self, status_text: str = "") -> Text:
|
|
313
|
+
"""Return a static logo frame for use in non-animated renders.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
status_text: Optional status text to display below the logo.
|
|
317
|
+
"""
|
|
318
|
+
logo_text = Text(self.logo, style=self.BASE_BLUE)
|
|
319
|
+
if status_text:
|
|
320
|
+
logo_text.append("\n")
|
|
321
|
+
logo_text.append(status_text)
|
|
322
|
+
return logo_text
|
glaip_sdk/cli/account_store.py
CHANGED
|
@@ -523,6 +523,21 @@ class AccountStore:
|
|
|
523
523
|
|
|
524
524
|
self._save_config(config)
|
|
525
525
|
|
|
526
|
+
def save_config_updates(self, config: dict[str, Any]) -> None:
|
|
527
|
+
"""Save config updates, preserving all existing keys.
|
|
528
|
+
|
|
529
|
+
This method allows external code to update arbitrary config keys
|
|
530
|
+
(e.g., TUI preferences) while preserving the full config structure.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
config: Complete configuration dictionary to save. This should
|
|
534
|
+
include all keys that should be preserved, not just updates.
|
|
535
|
+
|
|
536
|
+
Raises:
|
|
537
|
+
AccountStoreError: If config file cannot be written.
|
|
538
|
+
"""
|
|
539
|
+
self._save_config(config)
|
|
540
|
+
|
|
526
541
|
|
|
527
542
|
# Global instance for convenience
|
|
528
543
|
_account_store = AccountStore()
|
glaip_sdk/cli/auth.py
CHANGED
|
@@ -19,8 +19,7 @@ from rich.console import Console
|
|
|
19
19
|
|
|
20
20
|
from glaip_sdk.branding import HINT_PREFIX_STYLE, WARNING_STYLE
|
|
21
21
|
from glaip_sdk.cli.account_store import AccountNotFoundError, AccountStoreError, get_account_store
|
|
22
|
-
from glaip_sdk.cli.hints import format_command_hint
|
|
23
|
-
from glaip_sdk.cli.utils import command_hint
|
|
22
|
+
from glaip_sdk.cli.hints import command_hint, format_command_hint
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
def prepare_authentication_export(
|
|
@@ -526,12 +525,19 @@ def resolve_api_url_from_context(
|
|
|
526
525
|
elif hasattr(ctx, "obj") and isinstance(ctx.obj, dict):
|
|
527
526
|
account_name = ctx.obj.get("account_name")
|
|
528
527
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
528
|
+
if isinstance(api_url, str) and api_url.strip():
|
|
529
|
+
return api_url.strip()
|
|
530
|
+
|
|
531
|
+
try:
|
|
532
|
+
resolved_url, _, _ = resolve_credentials(
|
|
533
|
+
account_name=account_name,
|
|
534
|
+
api_url=None,
|
|
535
|
+
api_key=None,
|
|
536
|
+
ignore_env_creds=True,
|
|
537
|
+
)
|
|
538
|
+
except Exception:
|
|
539
|
+
return None
|
|
540
|
+
|
|
535
541
|
return resolved_url
|
|
536
542
|
|
|
537
543
|
|
|
@@ -33,7 +33,7 @@ from glaip_sdk.cli.commands.common_config import check_connection, render_brandi
|
|
|
33
33
|
from glaip_sdk.cli.hints import format_command_hint
|
|
34
34
|
from glaip_sdk.cli.masking import mask_api_key_display
|
|
35
35
|
from glaip_sdk.cli.slash.accounts_shared import env_credentials_present
|
|
36
|
-
from glaip_sdk.cli.
|
|
36
|
+
from glaip_sdk.cli.hints import command_hint
|
|
37
37
|
from glaip_sdk.icons import ICON_TOOL
|
|
38
38
|
from glaip_sdk.rich_components import AIPPanel, AIPTable
|
|
39
39
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Agent CLI commands package.
|
|
2
|
+
|
|
3
|
+
This package contains agent management commands split by operation.
|
|
4
|
+
The package is the canonical import surface.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# pylint: disable=duplicate-code
|
|
11
|
+
# Import from submodules
|
|
12
|
+
from glaip_sdk.cli.commands.agents._common import ( # noqa: E402
|
|
13
|
+
AGENT_NOT_FOUND_ERROR,
|
|
14
|
+
_coerce_mapping_candidate,
|
|
15
|
+
_display_agent_details,
|
|
16
|
+
_emit_verbose_guidance,
|
|
17
|
+
_fetch_full_agent_details,
|
|
18
|
+
_get_agent_for_update,
|
|
19
|
+
_get_agent_model_name,
|
|
20
|
+
_get_language_model_display_name,
|
|
21
|
+
_model_from_config,
|
|
22
|
+
_prepare_agent_output,
|
|
23
|
+
_resolve_agent,
|
|
24
|
+
_resolve_resources_by_name,
|
|
25
|
+
agents_group,
|
|
26
|
+
console,
|
|
27
|
+
)
|
|
28
|
+
from glaip_sdk.cli.commands.agents.create import create # noqa: E402
|
|
29
|
+
from glaip_sdk.cli.commands.agents.delete import delete # noqa: E402
|
|
30
|
+
from glaip_sdk.cli.commands.agents.get import get # noqa: E402
|
|
31
|
+
from glaip_sdk.cli.commands.agents.list import list_agents # noqa: E402
|
|
32
|
+
from glaip_sdk.cli.commands.agents.run import _maybe_attach_transcript_toggle, run # noqa: E402
|
|
33
|
+
from glaip_sdk.cli.commands.agents.sync_langflow import sync_langflow # noqa: E402
|
|
34
|
+
from glaip_sdk.cli.commands.agents.update import update # noqa: E402
|
|
35
|
+
|
|
36
|
+
# Import core functions for test compatibility
|
|
37
|
+
from glaip_sdk.cli.core.context import get_client # noqa: E402
|
|
38
|
+
|
|
39
|
+
# Import core output functions for test compatibility
|
|
40
|
+
from glaip_sdk.cli.core.output import ( # noqa: E402
|
|
41
|
+
handle_resource_export,
|
|
42
|
+
output_list,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Import rendering functions for test compatibility
|
|
46
|
+
from glaip_sdk.cli.core.rendering import ( # noqa: E402
|
|
47
|
+
build_renderer,
|
|
48
|
+
with_client_and_spinner, # noqa: E402
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Import display functions for test compatibility
|
|
52
|
+
# Import display functions for test compatibility
|
|
53
|
+
from glaip_sdk.cli.display import ( # noqa: E402 # noqa: E402
|
|
54
|
+
display_agent_run_suggestions,
|
|
55
|
+
handle_json_output,
|
|
56
|
+
handle_rich_output,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Import IO functions for test compatibility
|
|
60
|
+
from glaip_sdk.cli.io import ( # noqa: E402
|
|
61
|
+
fetch_raw_resource_details,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Import rich helpers for test compatibility
|
|
65
|
+
from glaip_sdk.cli.rich_helpers import ( # noqa: E402
|
|
66
|
+
markup_text,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Import transcript functions for test compatibility
|
|
70
|
+
from glaip_sdk.cli.transcript import ( # noqa: E402
|
|
71
|
+
maybe_launch_post_run_viewer,
|
|
72
|
+
store_transcript_for_session,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Import utils for test compatibility
|
|
76
|
+
from glaip_sdk.utils import ( # noqa: E402
|
|
77
|
+
is_uuid,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
__all__ = [
|
|
81
|
+
"AGENT_NOT_FOUND_ERROR",
|
|
82
|
+
"agents_group",
|
|
83
|
+
"create",
|
|
84
|
+
"delete",
|
|
85
|
+
"get",
|
|
86
|
+
"list_agents",
|
|
87
|
+
"run",
|
|
88
|
+
"sync_langflow",
|
|
89
|
+
"update",
|
|
90
|
+
"_get_agent_for_update",
|
|
91
|
+
"_resolve_agent",
|
|
92
|
+
"_coerce_mapping_candidate",
|
|
93
|
+
"_display_agent_details",
|
|
94
|
+
"_emit_verbose_guidance",
|
|
95
|
+
"_fetch_full_agent_details",
|
|
96
|
+
"_get_agent_model_name",
|
|
97
|
+
"_get_language_model_display_name",
|
|
98
|
+
"_model_from_config",
|
|
99
|
+
"_prepare_agent_output",
|
|
100
|
+
"_resolve_resources_by_name",
|
|
101
|
+
"_maybe_attach_transcript_toggle",
|
|
102
|
+
"get_client",
|
|
103
|
+
"with_client_and_spinner",
|
|
104
|
+
"console",
|
|
105
|
+
"handle_json_output",
|
|
106
|
+
"handle_rich_output",
|
|
107
|
+
"output_list",
|
|
108
|
+
"handle_resource_export",
|
|
109
|
+
"build_renderer",
|
|
110
|
+
"display_agent_run_suggestions",
|
|
111
|
+
"markup_text",
|
|
112
|
+
"maybe_launch_post_run_viewer",
|
|
113
|
+
"store_transcript_for_session",
|
|
114
|
+
"fetch_raw_resource_details",
|
|
115
|
+
"is_uuid",
|
|
116
|
+
]
|