glaip-sdk 0.2.2__py3-none-any.whl → 0.4.0__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/cli/auth.py +2 -1
- glaip_sdk/cli/commands/agents.py +51 -36
- glaip_sdk/cli/commands/configure.py +2 -1
- glaip_sdk/cli/commands/mcps.py +219 -62
- glaip_sdk/cli/commands/models.py +3 -5
- glaip_sdk/cli/commands/tools.py +27 -16
- glaip_sdk/cli/commands/transcripts.py +1 -1
- glaip_sdk/cli/constants.py +3 -0
- glaip_sdk/cli/display.py +1 -1
- glaip_sdk/cli/hints.py +58 -0
- glaip_sdk/cli/io.py +6 -3
- glaip_sdk/cli/main.py +3 -4
- glaip_sdk/cli/slash/agent_session.py +4 -13
- glaip_sdk/cli/slash/prompt.py +3 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +139 -48
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +632 -0
- glaip_sdk/cli/transcript/capture.py +1 -1
- glaip_sdk/cli/transcript/viewer.py +19 -678
- glaip_sdk/cli/update_notifier.py +2 -1
- glaip_sdk/cli/utils.py +228 -101
- glaip_sdk/cli/validators.py +5 -6
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +40 -22
- glaip_sdk/client/main.py +2 -6
- glaip_sdk/client/mcps.py +13 -5
- glaip_sdk/client/run_rendering.py +90 -111
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +2 -3
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/models/__init__.py +56 -0
- glaip_sdk/models/agent_runs.py +117 -0
- glaip_sdk/models.py +8 -7
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/utils/client_utils.py +13 -0
- glaip_sdk/utils/display.py +23 -15
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/import_export.py +6 -9
- 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 +10 -28
- glaip_sdk/utils/rendering/renderer/base.py +217 -1476
- glaip_sdk/utils/rendering/renderer/debug.py +24 -1
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +4 -12
- 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 -439
- 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 +26 -15
- glaip_sdk/utils/validation.py +13 -21
- {glaip_sdk-0.2.2.dist-info → glaip_sdk-0.4.0.dist-info}/METADATA +24 -2
- glaip_sdk-0.4.0.dist-info/RECORD +110 -0
- glaip_sdk-0.2.2.dist-info/RECORD +0 -87
- {glaip_sdk-0.2.2.dist-info → glaip_sdk-0.4.0.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.2.2.dist-info → glaip_sdk-0.4.0.dist-info}/entry_points.txt +0 -0
glaip_sdk/cli/commands/tools.py
CHANGED
|
@@ -4,7 +4,6 @@ Authors:
|
|
|
4
4
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
# pylint: disable=duplicate-code
|
|
8
7
|
import json
|
|
9
8
|
import re
|
|
10
9
|
from pathlib import Path
|
|
@@ -40,7 +39,10 @@ from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
|
40
39
|
from glaip_sdk.cli.rich_helpers import markup_text, print_markup
|
|
41
40
|
from glaip_sdk.cli.utils import (
|
|
42
41
|
coerce_to_row,
|
|
42
|
+
format_datetime_fields,
|
|
43
43
|
get_client,
|
|
44
|
+
handle_best_effort_check,
|
|
45
|
+
handle_resource_export,
|
|
44
46
|
output_list,
|
|
45
47
|
output_result,
|
|
46
48
|
spinner_context,
|
|
@@ -57,16 +59,32 @@ def tools_group() -> None:
|
|
|
57
59
|
pass
|
|
58
60
|
|
|
59
61
|
|
|
60
|
-
# pylint: disable=duplicate-code
|
|
61
62
|
def _resolve_tool(ctx: Any, client: Any, ref: str, select: int | None = None) -> Any | None:
|
|
62
|
-
"""Resolve tool
|
|
63
|
+
"""Resolve a tool by ID or name, handling ambiguous matches interactively.
|
|
64
|
+
|
|
65
|
+
This function provides tool-specific resolution logic. It uses
|
|
66
|
+
resolve_resource_reference to find tools by UUID or name, with interactive
|
|
67
|
+
selection when multiple matches are found.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
ctx: Click context for CLI operations.
|
|
71
|
+
client: API client instance.
|
|
72
|
+
ref: Tool reference (UUID string or name).
|
|
73
|
+
select: Pre-selected index for non-interactive mode (1-based).
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Tool object if found, None otherwise.
|
|
77
|
+
"""
|
|
78
|
+
# Configure tool-specific resolution with standard fuzzy matching
|
|
79
|
+
get_by_id = client.get_tool
|
|
80
|
+
find_by_name = client.find_tools
|
|
63
81
|
return resolve_resource_reference(
|
|
64
82
|
ctx,
|
|
65
83
|
client,
|
|
66
84
|
ref,
|
|
67
85
|
"tool",
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
get_by_id,
|
|
87
|
+
find_by_name,
|
|
70
88
|
"Tool",
|
|
71
89
|
select=select,
|
|
72
90
|
)
|
|
@@ -100,19 +118,16 @@ def _validate_name_match(provided: str | None, internal: str) -> str:
|
|
|
100
118
|
|
|
101
119
|
def _check_duplicate_name(client: Any, tool_name: str) -> None:
|
|
102
120
|
"""Raise if a tool with the same name already exists."""
|
|
103
|
-
|
|
121
|
+
|
|
122
|
+
def _check_duplicate() -> None:
|
|
104
123
|
existing = client.find_tools(name=tool_name)
|
|
105
124
|
if existing:
|
|
106
125
|
raise click.ClickException(
|
|
107
126
|
f"A tool named '{tool_name}' already exists. "
|
|
108
127
|
"Please change your plugin's 'name' to a unique value, then re-run."
|
|
109
128
|
)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
raise
|
|
113
|
-
except Exception:
|
|
114
|
-
# Non-fatal: best-effort duplicate check for other errors
|
|
115
|
-
pass
|
|
129
|
+
|
|
130
|
+
handle_best_effort_check(_check_duplicate)
|
|
116
131
|
|
|
117
132
|
|
|
118
133
|
def _parse_tags(tags: str | None) -> list[str]:
|
|
@@ -349,8 +364,6 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
|
|
|
349
364
|
|
|
350
365
|
# Handle export option
|
|
351
366
|
if export:
|
|
352
|
-
from glaip_sdk.cli.utils import handle_resource_export
|
|
353
|
-
|
|
354
367
|
handle_resource_export(
|
|
355
368
|
ctx,
|
|
356
369
|
tool,
|
|
@@ -371,8 +384,6 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
|
|
|
371
384
|
if raw_tool_data:
|
|
372
385
|
# Use raw API data - this preserves ALL fields
|
|
373
386
|
# Format dates for better display (minimal postprocessing)
|
|
374
|
-
from glaip_sdk.cli.utils import format_datetime_fields
|
|
375
|
-
|
|
376
387
|
formatted_data = format_datetime_fields(raw_tool_data)
|
|
377
388
|
|
|
378
389
|
# Display using output_result with raw data
|
|
@@ -37,7 +37,7 @@ from glaip_sdk.cli.transcript.viewer import ViewerContext, run_viewer_session
|
|
|
37
37
|
from glaip_sdk.cli.utils import format_size, get_ctx_value, parse_json_line
|
|
38
38
|
from glaip_sdk.rich_components import AIPTable
|
|
39
39
|
from glaip_sdk.utils.rendering.renderer.debug import render_debug_event
|
|
40
|
-
from glaip_sdk.utils.rendering.
|
|
40
|
+
from glaip_sdk.utils.rendering.layout.panels import create_final_panel
|
|
41
41
|
|
|
42
42
|
console = Console()
|
|
43
43
|
|
glaip_sdk/cli/constants.py
CHANGED
glaip_sdk/cli/display.py
CHANGED
|
@@ -17,7 +17,7 @@ from rich.text import Text
|
|
|
17
17
|
|
|
18
18
|
from glaip_sdk.branding import ERROR_STYLE, SUCCESS, SUCCESS_STYLE, WARNING_STYLE
|
|
19
19
|
from glaip_sdk.cli.rich_helpers import markup_text
|
|
20
|
-
from glaip_sdk.cli.
|
|
20
|
+
from glaip_sdk.cli.hints import command_hint, format_command_hint, in_slash_mode
|
|
21
21
|
from glaip_sdk.icons import ICON_AGENT, ICON_TOOL
|
|
22
22
|
from glaip_sdk.rich_components import AIPPanel
|
|
23
23
|
|
glaip_sdk/cli/hints.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Helpers for formatting CLI/slash command hints.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from glaip_sdk.branding import HINT_COMMAND_STYLE, HINT_DESCRIPTION_COLOR
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def in_slash_mode(ctx: click.Context | None = None) -> bool:
|
|
16
|
+
"""Return True when running inside the slash command palette."""
|
|
17
|
+
if ctx is None:
|
|
18
|
+
try:
|
|
19
|
+
ctx = click.get_current_context(silent=True)
|
|
20
|
+
except RuntimeError:
|
|
21
|
+
ctx = None
|
|
22
|
+
|
|
23
|
+
if ctx is None:
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
obj = getattr(ctx, "obj", None)
|
|
27
|
+
if isinstance(obj, dict):
|
|
28
|
+
return bool(obj.get("_slash_session"))
|
|
29
|
+
|
|
30
|
+
return bool(getattr(obj, "_slash_session", False))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def command_hint(
|
|
34
|
+
cli_command: str | None,
|
|
35
|
+
slash_command: str | None = None,
|
|
36
|
+
*,
|
|
37
|
+
ctx: click.Context | None = None,
|
|
38
|
+
) -> str | None:
|
|
39
|
+
"""Return the appropriate command string for the current mode."""
|
|
40
|
+
if in_slash_mode(ctx):
|
|
41
|
+
if not slash_command:
|
|
42
|
+
return None
|
|
43
|
+
return slash_command if slash_command.startswith("/") else f"/{slash_command}"
|
|
44
|
+
|
|
45
|
+
if not cli_command:
|
|
46
|
+
return None
|
|
47
|
+
return f"aip {cli_command}"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def format_command_hint(command: str | None, description: str | None = None) -> str | None:
|
|
51
|
+
"""Return a Rich markup string that highlights a command hint."""
|
|
52
|
+
if not command:
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
highlighted = f"[{HINT_COMMAND_STYLE}]{command}[/]"
|
|
56
|
+
if description:
|
|
57
|
+
highlighted += f" [{HINT_DESCRIPTION_COLOR}]{description}[/{HINT_DESCRIPTION_COLOR}]"
|
|
58
|
+
return highlighted
|
glaip_sdk/cli/io.py
CHANGED
|
@@ -7,6 +7,7 @@ Authors:
|
|
|
7
7
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
from importlib import import_module
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import TYPE_CHECKING, Any
|
|
12
13
|
|
|
@@ -25,9 +26,11 @@ if TYPE_CHECKING: # pragma: no cover - typing-only imports
|
|
|
25
26
|
|
|
26
27
|
def _create_console() -> "Console":
|
|
27
28
|
"""Return a Console instance (lazy import for easier testing)."""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
try:
|
|
30
|
+
console_module = import_module("rich.console")
|
|
31
|
+
except ImportError as exc: # pragma: no cover - optional dependency missing
|
|
32
|
+
raise RuntimeError("Rich Console is not available") from exc
|
|
33
|
+
return console_module.Console()
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
def load_resource_from_file_with_validation(file_path: Path, resource_type: str) -> dict[str, Any]:
|
glaip_sdk/cli/main.py
CHANGED
|
@@ -34,11 +34,12 @@ from glaip_sdk.cli.commands.mcps import mcps_group
|
|
|
34
34
|
from glaip_sdk.cli.commands.models import models_group
|
|
35
35
|
from glaip_sdk.cli.commands.tools import tools_group
|
|
36
36
|
from glaip_sdk.cli.commands.transcripts import transcripts_group
|
|
37
|
-
from glaip_sdk.cli.commands.update import update_command
|
|
37
|
+
from glaip_sdk.cli.commands.update import _build_upgrade_command, update_command
|
|
38
38
|
from glaip_sdk.cli.config import load_config
|
|
39
39
|
from glaip_sdk.cli.transcript import get_transcript_cache_stats
|
|
40
40
|
from glaip_sdk.cli.update_notifier import maybe_notify_update
|
|
41
|
-
from glaip_sdk.cli.
|
|
41
|
+
from glaip_sdk.cli.hints import in_slash_mode
|
|
42
|
+
from glaip_sdk.cli.utils import format_size, sdk_version, spinner_context, update_spinner
|
|
42
43
|
from glaip_sdk.config.constants import (
|
|
43
44
|
DEFAULT_AGENT_RUN_TIMEOUT,
|
|
44
45
|
)
|
|
@@ -418,8 +419,6 @@ def update(check_only: bool, force: bool) -> None:
|
|
|
418
419
|
|
|
419
420
|
# Update using pip
|
|
420
421
|
try:
|
|
421
|
-
from glaip_sdk.cli.commands.update import _build_upgrade_command
|
|
422
|
-
|
|
423
422
|
cmd = list(_build_upgrade_command(include_prerelease=False))
|
|
424
423
|
# Replace package name with "glaip-sdk" (main.py uses different name)
|
|
425
424
|
cmd[-1] = "glaip-sdk"
|
|
@@ -16,7 +16,8 @@ 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
17
|
from glaip_sdk.cli.constants import DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
|
|
18
18
|
from glaip_sdk.cli.slash.prompt import _HAS_PROMPT_TOOLKIT, FormattedText
|
|
19
|
-
from glaip_sdk.cli.
|
|
19
|
+
from glaip_sdk.cli.hints import format_command_hint
|
|
20
|
+
from glaip_sdk.cli.utils import bind_slash_session_context
|
|
20
21
|
|
|
21
22
|
if TYPE_CHECKING: # pragma: no cover - type checking only
|
|
22
23
|
from glaip_sdk.cli.slash.session import SlashSession
|
|
@@ -41,6 +42,7 @@ class AgentRunSession:
|
|
|
41
42
|
self._contextual_completion_help: dict[str, str] = {
|
|
42
43
|
"details": "Show this agent's configuration (+ expands prompt).",
|
|
43
44
|
"help": "Display this context-aware menu.",
|
|
45
|
+
"runs": "✨ NEW · Browse remote run history for this agent.",
|
|
44
46
|
"exit": "Return to the command palette.",
|
|
45
47
|
"q": "Return to the command palette.",
|
|
46
48
|
}
|
|
@@ -252,19 +254,8 @@ class AgentRunSession:
|
|
|
252
254
|
@contextmanager
|
|
253
255
|
def _bind_session_context(self) -> Any:
|
|
254
256
|
"""Temporarily attach this slash session to the Click context."""
|
|
255
|
-
|
|
256
|
-
has_context = isinstance(ctx_obj, dict)
|
|
257
|
-
previous_session = ctx_obj.get("_slash_session") if has_context else None
|
|
258
|
-
if has_context:
|
|
259
|
-
ctx_obj["_slash_session"] = self.session
|
|
260
|
-
try:
|
|
257
|
+
with bind_slash_session_context(self.session.ctx, self.session):
|
|
261
258
|
yield
|
|
262
|
-
finally:
|
|
263
|
-
if has_context:
|
|
264
|
-
if previous_session is None:
|
|
265
|
-
ctx_obj.pop("_slash_session", None)
|
|
266
|
-
else:
|
|
267
|
-
ctx_obj["_slash_session"] = previous_session
|
|
268
259
|
|
|
269
260
|
def _run_agent(self, agent_id: str, message: str) -> None:
|
|
270
261
|
"""Execute the agents run command for the active agent."""
|
glaip_sdk/cli/slash/prompt.py
CHANGED
|
@@ -177,8 +177,11 @@ def _iter_command_completions(
|
|
|
177
177
|
return []
|
|
178
178
|
|
|
179
179
|
commands = sorted(session._unique_commands.values(), key=lambda c: c.name)
|
|
180
|
+
agent_context = bool(getattr(session, "_current_agent", None))
|
|
180
181
|
|
|
181
182
|
for cmd in commands:
|
|
183
|
+
if getattr(cmd, "agent_only", False) and not agent_context:
|
|
184
|
+
continue
|
|
182
185
|
yield from _generate_command_completions(cmd, prefix, text, seen)
|
|
183
186
|
|
|
184
187
|
|