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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Layout utilities exposed for renderer/viewer consumers.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from glaip_sdk.utils.rendering.layout.panels import (
|
|
8
|
+
create_context_panel,
|
|
9
|
+
create_final_panel,
|
|
10
|
+
create_main_panel,
|
|
11
|
+
create_tool_panel,
|
|
12
|
+
)
|
|
13
|
+
from glaip_sdk.utils.rendering.layout.progress import (
|
|
14
|
+
TrailingSpinnerLine,
|
|
15
|
+
build_progress_footer,
|
|
16
|
+
format_elapsed_time,
|
|
17
|
+
format_tool_title,
|
|
18
|
+
format_working_indicator,
|
|
19
|
+
get_spinner,
|
|
20
|
+
get_spinner_char,
|
|
21
|
+
is_delegation_tool,
|
|
22
|
+
)
|
|
23
|
+
from glaip_sdk.utils.rendering.layout.transcript import (
|
|
24
|
+
DEFAULT_TRANSCRIPT_THEME,
|
|
25
|
+
TranscriptGlyphs,
|
|
26
|
+
TranscriptRow,
|
|
27
|
+
TranscriptSnapshot,
|
|
28
|
+
build_final_panel,
|
|
29
|
+
build_transcript_snapshot,
|
|
30
|
+
build_transcript_view,
|
|
31
|
+
extract_query_from_meta,
|
|
32
|
+
format_final_panel_title,
|
|
33
|
+
render_final_panel,
|
|
34
|
+
)
|
|
35
|
+
from glaip_sdk.utils.rendering.layout.summary import render_summary_panels
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
# Panels
|
|
39
|
+
"create_context_panel",
|
|
40
|
+
"create_final_panel",
|
|
41
|
+
"create_main_panel",
|
|
42
|
+
"create_tool_panel",
|
|
43
|
+
"render_summary_panels",
|
|
44
|
+
# Progress
|
|
45
|
+
"TrailingSpinnerLine",
|
|
46
|
+
"build_progress_footer",
|
|
47
|
+
"format_elapsed_time",
|
|
48
|
+
"format_tool_title",
|
|
49
|
+
"format_working_indicator",
|
|
50
|
+
"get_spinner",
|
|
51
|
+
"get_spinner_char",
|
|
52
|
+
"is_delegation_tool",
|
|
53
|
+
# Transcript
|
|
54
|
+
"DEFAULT_TRANSCRIPT_THEME",
|
|
55
|
+
"TranscriptGlyphs",
|
|
56
|
+
"TranscriptRow",
|
|
57
|
+
"TranscriptSnapshot",
|
|
58
|
+
"build_final_panel",
|
|
59
|
+
"build_transcript_snapshot",
|
|
60
|
+
"build_transcript_view",
|
|
61
|
+
"extract_query_from_meta",
|
|
62
|
+
"format_final_panel_title",
|
|
63
|
+
"render_final_panel",
|
|
64
|
+
]
|
|
@@ -6,6 +6,7 @@ Authors:
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
from rich.align import Align
|
|
10
11
|
from rich.markdown import Markdown
|
|
11
12
|
from rich.spinner import Spinner
|
|
@@ -145,3 +146,11 @@ def create_final_panel(content: str, title: str = "Final Result", theme: str = "
|
|
|
145
146
|
border_style=SUCCESS,
|
|
146
147
|
padding=(0, 1),
|
|
147
148
|
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
__all__ = [
|
|
152
|
+
"create_main_panel",
|
|
153
|
+
"create_tool_panel",
|
|
154
|
+
"create_context_panel",
|
|
155
|
+
"create_final_panel",
|
|
156
|
+
]
|
|
@@ -7,8 +7,22 @@ Authors:
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
from time import monotonic
|
|
10
|
+
from typing import Any
|
|
10
11
|
|
|
11
|
-
from
|
|
12
|
+
from rich.console import Console as RichConsole
|
|
13
|
+
from rich.console import Group
|
|
14
|
+
from rich.measure import Measurement
|
|
15
|
+
from rich.spinner import Spinner
|
|
16
|
+
from rich.text import Text
|
|
17
|
+
|
|
18
|
+
from glaip_sdk.utils.rendering.steps.manager import StepManager
|
|
19
|
+
|
|
20
|
+
_SPINNER_FRAMES = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _spinner_time() -> float:
|
|
24
|
+
"""Return the monotonic time used for spinner animation."""
|
|
25
|
+
return monotonic()
|
|
12
26
|
|
|
13
27
|
|
|
14
28
|
def get_spinner() -> str:
|
|
@@ -16,6 +30,33 @@ def get_spinner() -> str:
|
|
|
16
30
|
return get_spinner_char()
|
|
17
31
|
|
|
18
32
|
|
|
33
|
+
def get_spinner_char() -> str:
|
|
34
|
+
"""Return the spinner frame based on elapsed time."""
|
|
35
|
+
frame_index = int(_spinner_time() * 10) % len(_SPINNER_FRAMES)
|
|
36
|
+
return _SPINNER_FRAMES[frame_index]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TrailingSpinnerLine:
|
|
40
|
+
"""Render a text line with a trailing animated Rich spinner."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, base_text: Text, spinner: Spinner) -> None:
|
|
43
|
+
"""Initialize spinner line with base text and spinner component."""
|
|
44
|
+
self._base_text = base_text
|
|
45
|
+
self._spinner = spinner
|
|
46
|
+
|
|
47
|
+
def __rich_console__(self, console: RichConsole, options: Any) -> Any: # type: ignore[override]
|
|
48
|
+
"""Render the text with trailing animated spinner."""
|
|
49
|
+
spinner_render = self._spinner.render(console.get_time())
|
|
50
|
+
combined = Text.assemble(self._base_text.copy(), " ", spinner_render)
|
|
51
|
+
yield combined
|
|
52
|
+
|
|
53
|
+
def __rich_measure__(self, console: RichConsole, options: Any) -> Measurement: # type: ignore[override]
|
|
54
|
+
"""Measure the combined text and spinner dimensions."""
|
|
55
|
+
snapshot = self._spinner.render(0)
|
|
56
|
+
combined = Text.assemble(self._base_text.copy(), " ", snapshot)
|
|
57
|
+
return Measurement.get(console, options, combined)
|
|
58
|
+
|
|
59
|
+
|
|
19
60
|
def _resolve_elapsed_time(
|
|
20
61
|
started_at: float | None,
|
|
21
62
|
server_elapsed_time: float | None,
|
|
@@ -131,3 +172,31 @@ def format_tool_title(tool_name: str) -> str:
|
|
|
131
172
|
|
|
132
173
|
# Convert snake_case to Title Case
|
|
133
174
|
return clean_name.replace("_", " ").title()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _has_running_steps(steps: StepManager) -> bool:
|
|
178
|
+
for step in steps.by_id.values():
|
|
179
|
+
if getattr(step, "status", None) not in {"finished", "failed", "stopped"}:
|
|
180
|
+
return True
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def build_progress_footer(
|
|
185
|
+
*,
|
|
186
|
+
state: Any,
|
|
187
|
+
steps: StepManager,
|
|
188
|
+
started_at: float | None,
|
|
189
|
+
server_elapsed_time: float | None,
|
|
190
|
+
) -> Group | None:
|
|
191
|
+
"""Return a trailing progress indicator when work is ongoing."""
|
|
192
|
+
if not _has_running_steps(steps):
|
|
193
|
+
return None
|
|
194
|
+
|
|
195
|
+
indicator = format_working_indicator(
|
|
196
|
+
started_at,
|
|
197
|
+
server_elapsed_time,
|
|
198
|
+
getattr(state, "streaming_started_at", None),
|
|
199
|
+
)
|
|
200
|
+
text = Text(indicator, style="dim")
|
|
201
|
+
spinner = Spinner("dots", style="dim")
|
|
202
|
+
return Group(TrailingSpinnerLine(text, spinner))
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Summary panel helpers shared between renderer and viewer.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections.abc import Mapping
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from glaip_sdk.utils.rendering.layout.transcript import (
|
|
13
|
+
DEFAULT_TRANSCRIPT_THEME,
|
|
14
|
+
build_transcript_snapshot,
|
|
15
|
+
build_transcript_view,
|
|
16
|
+
normalise_meta_payload,
|
|
17
|
+
)
|
|
18
|
+
from glaip_sdk.utils.rendering.state import RendererState
|
|
19
|
+
from glaip_sdk.utils.rendering.steps import StepManager
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def render_summary_panels(
|
|
23
|
+
state: RendererState,
|
|
24
|
+
steps: StepManager,
|
|
25
|
+
*,
|
|
26
|
+
theme: str | None = None,
|
|
27
|
+
summary_window: int | None = None,
|
|
28
|
+
include_query_panel: bool = True,
|
|
29
|
+
include_final_panel: bool = True,
|
|
30
|
+
step_status_overrides: dict[str, str] | None = None,
|
|
31
|
+
) -> list[Any]:
|
|
32
|
+
"""Return shared summary panels for renderer and offline viewer."""
|
|
33
|
+
resolved_theme = theme or DEFAULT_TRANSCRIPT_THEME
|
|
34
|
+
snapshot_source = state.to_snapshot() if hasattr(state, "to_snapshot") else state
|
|
35
|
+
if isinstance(snapshot_source, Mapping):
|
|
36
|
+
raw_meta = snapshot_source.get("meta")
|
|
37
|
+
else:
|
|
38
|
+
raw_meta = getattr(state, "meta", None)
|
|
39
|
+
snapshot_meta = normalise_meta_payload(raw_meta)
|
|
40
|
+
snapshot = build_transcript_snapshot(
|
|
41
|
+
snapshot_source,
|
|
42
|
+
steps,
|
|
43
|
+
meta=snapshot_meta,
|
|
44
|
+
summary_window=summary_window,
|
|
45
|
+
theme=resolved_theme,
|
|
46
|
+
step_status_overrides=step_status_overrides,
|
|
47
|
+
)
|
|
48
|
+
_header, body = build_transcript_view(snapshot, theme=resolved_theme)
|
|
49
|
+
|
|
50
|
+
return [
|
|
51
|
+
renderable
|
|
52
|
+
for renderable in body
|
|
53
|
+
if _should_include_summary_panel(
|
|
54
|
+
renderable,
|
|
55
|
+
include_query_panel=include_query_panel,
|
|
56
|
+
include_final_panel=include_final_panel,
|
|
57
|
+
)
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _should_include_summary_panel(
|
|
62
|
+
renderable: Any,
|
|
63
|
+
*,
|
|
64
|
+
include_query_panel: bool,
|
|
65
|
+
include_final_panel: bool,
|
|
66
|
+
) -> bool:
|
|
67
|
+
"""Return True when the panel should be included in the summary list."""
|
|
68
|
+
title = getattr(renderable, "title", "")
|
|
69
|
+
normalised = title.lower() if isinstance(title, str) else ""
|
|
70
|
+
if not include_query_panel and normalised == "user request":
|
|
71
|
+
return False
|
|
72
|
+
if not include_final_panel and normalised.startswith("final result"):
|
|
73
|
+
return False
|
|
74
|
+
return True
|