glaip-sdk 0.1.2__py3-none-any.whl → 0.6.5b3__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 +5 -2
- glaip_sdk/_version.py +9 -0
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1090 -0
- glaip_sdk/branding.py +13 -0
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/auth.py +254 -15
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents.py +214 -74
- glaip_sdk/cli/commands/common_config.py +101 -0
- glaip_sdk/cli/commands/configure.py +729 -113
- glaip_sdk/cli/commands/mcps.py +241 -72
- glaip_sdk/cli/commands/models.py +11 -5
- glaip_sdk/cli/commands/tools.py +49 -57
- glaip_sdk/cli/commands/transcripts.py +755 -0
- glaip_sdk/cli/config.py +48 -4
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +8 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +846 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +41 -20
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +6 -3
- glaip_sdk/cli/main.py +228 -119
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/pager.py +9 -10
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/accounts_controller.py +500 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +58 -20
- glaip_sdk/cli/slash/prompt.py +10 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +736 -134
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +86 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +872 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +255 -44
- glaip_sdk/cli/transcript/capture.py +66 -1
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/viewer.py +70 -463
- glaip_sdk/cli/update_notifier.py +14 -5
- glaip_sdk/cli/utils.py +243 -1258
- glaip_sdk/cli/validators.py +5 -6
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_agent_payloads.py +45 -9
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +287 -29
- glaip_sdk/client/base.py +1 -0
- glaip_sdk/client/main.py +19 -10
- glaip_sdk/client/mcps.py +122 -12
- glaip_sdk/client/run_rendering.py +133 -90
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +153 -10
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +90 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +116 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/registry/__init__.py +55 -0
- glaip_sdk/registry/agent.py +164 -0
- glaip_sdk/registry/base.py +139 -0
- glaip_sdk/registry/mcp.py +253 -0
- glaip_sdk/registry/tool.py +238 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +435 -0
- glaip_sdk/utils/__init__.py +58 -12
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +39 -7
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +23 -15
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +0 -33
- glaip_sdk/utils/import_export.py +12 -7
- glaip_sdk/utils/import_resolver.py +492 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -1
- glaip_sdk/utils/rendering/formatting.py +5 -30
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer → layout}/panels.py +9 -0
- glaip_sdk/utils/rendering/{renderer → layout}/progress.py +70 -1
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +1 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -47
- glaip_sdk/utils/rendering/renderer/base.py +241 -1434
- glaip_sdk/utils/rendering/renderer/config.py +1 -5
- glaip_sdk/utils/rendering/renderer/debug.py +26 -20
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +4 -33
- glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
- glaip_sdk/utils/rendering/state.py +204 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +53 -440
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/steps/manager.py +387 -0
- glaip_sdk/utils/rendering/timing.py +36 -0
- glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
- glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
- glaip_sdk/utils/resource_refs.py +25 -13
- glaip_sdk/utils/runtime_config.py +306 -0
- glaip_sdk/utils/serialization.py +18 -0
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/validation.py +16 -24
- {glaip_sdk-0.1.2.dist-info → glaip_sdk-0.6.5b3.dist-info}/METADATA +39 -4
- glaip_sdk-0.6.5b3.dist-info/RECORD +145 -0
- {glaip_sdk-0.1.2.dist-info → glaip_sdk-0.6.5b3.dist-info}/WHEEL +1 -1
- glaip_sdk/models.py +0 -240
- glaip_sdk-0.1.2.dist-info/RECORD +0 -82
- {glaip_sdk-0.1.2.dist-info → glaip_sdk-0.6.5b3.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Shared helpers for palette `/accounts`.
|
|
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
|
+
from glaip_sdk.cli.masking import mask_api_key_display
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def build_account_status_string(row: dict[str, Any], *, use_markup: bool = False) -> str:
|
|
16
|
+
"""Build status string for an account row (active/env-lock).
|
|
17
|
+
|
|
18
|
+
When `use_markup` is True, returns Rich markup strings for Textual/Rich rendering;
|
|
19
|
+
when False, returns plain text for console output.
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
build_account_status_string({"active": True, "env_lock": True}, use_markup=True)
|
|
23
|
+
returns "[bold green]● active[/] · [yellow]🔒 env-lock[/]"
|
|
24
|
+
use_markup=False returns "● active · 🔒 env-lock"
|
|
25
|
+
"""
|
|
26
|
+
status_parts: list[str] = []
|
|
27
|
+
if row.get("active"):
|
|
28
|
+
status_parts.append("[bold green]● active[/]" if use_markup else "● active")
|
|
29
|
+
if row.get("env_lock"):
|
|
30
|
+
status_parts.append("[yellow]🔒 env-lock[/]" if use_markup else "🔒 env-lock")
|
|
31
|
+
return " · ".join(status_parts)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def env_credentials_present(*, partial: bool = False) -> bool:
|
|
35
|
+
"""Return True when env credentials are present.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
partial: When True, treat either AIP_API_URL or AIP_API_KEY as present
|
|
39
|
+
(used by UIs that should lock on any env override). When False,
|
|
40
|
+
require both to be non-empty (used for context display).
|
|
41
|
+
"""
|
|
42
|
+
api_url = (os.getenv("AIP_API_URL") or "").strip()
|
|
43
|
+
api_key = (os.getenv("AIP_API_KEY") or "").strip()
|
|
44
|
+
if partial:
|
|
45
|
+
return bool(api_url or api_key)
|
|
46
|
+
return bool(api_url and api_key)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def build_account_rows(
|
|
50
|
+
accounts: dict[str, dict[str, str]],
|
|
51
|
+
active_account: str | None,
|
|
52
|
+
env_lock: bool,
|
|
53
|
+
) -> list[dict[str, str | bool]]:
|
|
54
|
+
"""Build account rows for display from accounts dict.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
accounts: Dictionary mapping account names to account data.
|
|
58
|
+
active_account: Name of the currently active account.
|
|
59
|
+
env_lock: Whether environment credentials are locking account switching.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
List of account row dictionaries with name, api_url, masked_key, active, and env_lock.
|
|
63
|
+
"""
|
|
64
|
+
rows: list[dict[str, str | bool]] = []
|
|
65
|
+
for name, account in sorted(accounts.items()):
|
|
66
|
+
rows.append(
|
|
67
|
+
{
|
|
68
|
+
"name": name,
|
|
69
|
+
"api_url": account.get("api_url", ""),
|
|
70
|
+
"masked_key": mask_api_key_display(account.get("api_key", "")),
|
|
71
|
+
"active": name == active_account,
|
|
72
|
+
"env_lock": env_lock,
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
return rows
|
|
@@ -14,8 +14,10 @@ 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
|
|
18
|
+
from glaip_sdk.cli.hints import format_command_hint
|
|
17
19
|
from glaip_sdk.cli.slash.prompt import _HAS_PROMPT_TOOLKIT, FormattedText
|
|
18
|
-
from glaip_sdk.cli.utils import
|
|
20
|
+
from glaip_sdk.cli.utils import bind_slash_session_context
|
|
19
21
|
|
|
20
22
|
if TYPE_CHECKING: # pragma: no cover - type checking only
|
|
21
23
|
from glaip_sdk.cli.slash.session import SlashSession
|
|
@@ -38,11 +40,13 @@ class AgentRunSession:
|
|
|
38
40
|
self._agent_name = getattr(agent, "name", "") or self._agent_id
|
|
39
41
|
self._prompt_placeholder: str = "Chat with this agent here; use / for shortcuts. Alt+Enter inserts a newline."
|
|
40
42
|
self._contextual_completion_help: dict[str, str] = {
|
|
41
|
-
"details": "Show this agent's
|
|
43
|
+
"details": "Show this agent's configuration (+ expands prompt).",
|
|
42
44
|
"help": "Display this context-aware menu.",
|
|
45
|
+
"runs": "✨ NEW · Browse remote run history for this agent.",
|
|
43
46
|
"exit": "Return to the command palette.",
|
|
44
47
|
"q": "Return to the command palette.",
|
|
45
48
|
}
|
|
49
|
+
self._instruction_preview_limit = DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
|
|
46
50
|
|
|
47
51
|
def run(self) -> None:
|
|
48
52
|
"""Run the interactive agent session loop."""
|
|
@@ -86,6 +90,7 @@ class AgentRunSession:
|
|
|
86
90
|
try:
|
|
87
91
|
|
|
88
92
|
def _prompt_message() -> Any:
|
|
93
|
+
"""Get formatted prompt message for agent session."""
|
|
89
94
|
prompt_prefix = f"{self._agent_name} ({self._agent_id}) "
|
|
90
95
|
|
|
91
96
|
# Use FormattedText if prompt_toolkit is available, otherwise use simple string
|
|
@@ -122,7 +127,7 @@ class AgentRunSession:
|
|
|
122
127
|
if raw in {"/exit", "/back", "/q"}:
|
|
123
128
|
return self._handle_exit_command()
|
|
124
129
|
|
|
125
|
-
if raw
|
|
130
|
+
if raw == "/details":
|
|
126
131
|
return self._handle_details_command(agent_id)
|
|
127
132
|
|
|
128
133
|
if raw in {"/help", "/?"}:
|
|
@@ -151,16 +156,59 @@ class AgentRunSession:
|
|
|
151
156
|
self.session.handle_command(raw, invoked_from_agent=True)
|
|
152
157
|
return not self.session._should_exit
|
|
153
158
|
|
|
154
|
-
def _show_details(self, agent_id: str) -> None:
|
|
159
|
+
def _show_details(self, agent_id: str, *, enable_prompt: bool = True) -> None:
|
|
160
|
+
"""Render the agent's configuration export inside the command palette."""
|
|
155
161
|
try:
|
|
156
|
-
self.session.ctx.invoke(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
162
|
+
self.session.ctx.invoke(
|
|
163
|
+
agents_get_command,
|
|
164
|
+
agent_ref=agent_id,
|
|
165
|
+
instruction_preview=self._instruction_preview_limit,
|
|
160
166
|
)
|
|
167
|
+
if enable_prompt:
|
|
168
|
+
self._prompt_instruction_view_toggle(agent_id)
|
|
169
|
+
self.console.print(
|
|
170
|
+
f"[{HINT_PREFIX_STYLE}]Tip:[/] Continue the conversation in this prompt, or use "
|
|
171
|
+
f"{format_command_hint('/help') or '/help'} for shortcuts."
|
|
172
|
+
)
|
|
161
173
|
except click.ClickException as exc:
|
|
162
174
|
self.console.print(f"[{ERROR_STYLE}]{exc}[/]")
|
|
163
175
|
|
|
176
|
+
def _prompt_instruction_view_toggle(self, agent_id: str) -> None:
|
|
177
|
+
"""Offer a prompt to expand or collapse the instruction preview after details."""
|
|
178
|
+
if not getattr(self.console, "is_terminal", False):
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
while True:
|
|
182
|
+
mode = "expanded" if self._instruction_preview_limit == 0 else "trimmed"
|
|
183
|
+
self.console.print(f"[dim]Instruction view is {mode}. Press Ctrl+T to toggle, Enter to continue.[/dim]")
|
|
184
|
+
try:
|
|
185
|
+
ch = click.getchar()
|
|
186
|
+
except (EOFError, KeyboardInterrupt): # pragma: no cover - defensive guard
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
if not self._handle_instruction_toggle_input(agent_id, ch):
|
|
190
|
+
break
|
|
191
|
+
|
|
192
|
+
if self._instruction_preview_limit == 0:
|
|
193
|
+
self._instruction_preview_limit = DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
|
|
194
|
+
self.console.print("")
|
|
195
|
+
|
|
196
|
+
def _handle_instruction_toggle_input(self, agent_id: str, ch: str) -> bool:
|
|
197
|
+
"""Process a single toggle keypress; return False when the loop should exit."""
|
|
198
|
+
if ch in {"\r", "\n"}:
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
lowered = ch.lower()
|
|
202
|
+
if lowered == "t" or ch == "\x14": # support literal 't' or Ctrl+T
|
|
203
|
+
self._instruction_preview_limit = (
|
|
204
|
+
DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT if self._instruction_preview_limit == 0 else 0
|
|
205
|
+
)
|
|
206
|
+
self._show_details(agent_id, enable_prompt=False)
|
|
207
|
+
return True
|
|
208
|
+
|
|
209
|
+
# Ignore other keys and continue prompting.
|
|
210
|
+
return True
|
|
211
|
+
|
|
164
212
|
def _after_agent_run(self) -> None:
|
|
165
213
|
"""Handle transcript viewer behaviour after a successful run."""
|
|
166
214
|
payload, manifest = self.session._get_last_transcript()
|
|
@@ -206,21 +254,11 @@ class AgentRunSession:
|
|
|
206
254
|
@contextmanager
|
|
207
255
|
def _bind_session_context(self) -> Any:
|
|
208
256
|
"""Temporarily attach this slash session to the Click context."""
|
|
209
|
-
|
|
210
|
-
has_context = isinstance(ctx_obj, dict)
|
|
211
|
-
previous_session = ctx_obj.get("_slash_session") if has_context else None
|
|
212
|
-
if has_context:
|
|
213
|
-
ctx_obj["_slash_session"] = self.session
|
|
214
|
-
try:
|
|
257
|
+
with bind_slash_session_context(self.session.ctx, self.session):
|
|
215
258
|
yield
|
|
216
|
-
finally:
|
|
217
|
-
if has_context:
|
|
218
|
-
if previous_session is None:
|
|
219
|
-
ctx_obj.pop("_slash_session", None)
|
|
220
|
-
else:
|
|
221
|
-
ctx_obj["_slash_session"] = previous_session
|
|
222
259
|
|
|
223
260
|
def _run_agent(self, agent_id: str, message: str) -> None:
|
|
261
|
+
"""Execute the agents run command for the active agent."""
|
|
224
262
|
if not message:
|
|
225
263
|
return
|
|
226
264
|
|
glaip_sdk/cli/slash/prompt.py
CHANGED
|
@@ -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)
|
|
@@ -163,6 +168,7 @@ def _create_key_bindings(_session: SlashSession) -> Any:
|
|
|
163
168
|
def _iter_command_completions(
|
|
164
169
|
session: SlashSession, text: str
|
|
165
170
|
) -> Iterable[Completion]: # pragma: no cover - thin wrapper
|
|
171
|
+
"""Yield completions for global slash commands."""
|
|
166
172
|
prefix = text[1:]
|
|
167
173
|
seen: set[str] = set()
|
|
168
174
|
|
|
@@ -171,8 +177,11 @@ def _iter_command_completions(
|
|
|
171
177
|
return []
|
|
172
178
|
|
|
173
179
|
commands = sorted(session._unique_commands.values(), key=lambda c: c.name)
|
|
180
|
+
agent_context = bool(getattr(session, "_current_agent", None))
|
|
174
181
|
|
|
175
182
|
for cmd in commands:
|
|
183
|
+
if getattr(cmd, "agent_only", False) and not agent_context:
|
|
184
|
+
continue
|
|
176
185
|
yield from _generate_command_completions(cmd, prefix, text, seen)
|
|
177
186
|
|
|
178
187
|
|
|
@@ -203,6 +212,7 @@ def _generate_command_completions(cmd: Any, prefix: str, text: str, seen: set[st
|
|
|
203
212
|
def _iter_contextual_completions(
|
|
204
213
|
session: SlashSession, text: str
|
|
205
214
|
) -> Iterable[Completion]: # pragma: no cover - thin wrapper
|
|
215
|
+
"""Yield completions for context-specific slash commands."""
|
|
206
216
|
prefix = text[1:]
|
|
207
217
|
seen: set[str] = set()
|
|
208
218
|
|