glaip-sdk 0.6.12__py3-none-any.whl → 0.6.14__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 (156) hide show
  1. glaip_sdk/__init__.py +42 -5
  2. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.14.dist-info}/METADATA +31 -37
  3. glaip_sdk-0.6.14.dist-info/RECORD +12 -0
  4. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.14.dist-info}/WHEEL +2 -1
  5. glaip_sdk-0.6.14.dist-info/entry_points.txt +2 -0
  6. glaip_sdk-0.6.14.dist-info/top_level.txt +1 -0
  7. glaip_sdk/agents/__init__.py +0 -27
  8. glaip_sdk/agents/base.py +0 -1191
  9. glaip_sdk/cli/__init__.py +0 -9
  10. glaip_sdk/cli/account_store.py +0 -540
  11. glaip_sdk/cli/agent_config.py +0 -78
  12. glaip_sdk/cli/auth.py +0 -699
  13. glaip_sdk/cli/commands/__init__.py +0 -5
  14. glaip_sdk/cli/commands/accounts.py +0 -746
  15. glaip_sdk/cli/commands/agents.py +0 -1509
  16. glaip_sdk/cli/commands/common_config.py +0 -101
  17. glaip_sdk/cli/commands/configure.py +0 -896
  18. glaip_sdk/cli/commands/mcps.py +0 -1356
  19. glaip_sdk/cli/commands/models.py +0 -69
  20. glaip_sdk/cli/commands/tools.py +0 -576
  21. glaip_sdk/cli/commands/transcripts.py +0 -755
  22. glaip_sdk/cli/commands/update.py +0 -61
  23. glaip_sdk/cli/config.py +0 -95
  24. glaip_sdk/cli/constants.py +0 -38
  25. glaip_sdk/cli/context.py +0 -150
  26. glaip_sdk/cli/core/__init__.py +0 -79
  27. glaip_sdk/cli/core/context.py +0 -124
  28. glaip_sdk/cli/core/output.py +0 -846
  29. glaip_sdk/cli/core/prompting.py +0 -649
  30. glaip_sdk/cli/core/rendering.py +0 -187
  31. glaip_sdk/cli/display.py +0 -355
  32. glaip_sdk/cli/hints.py +0 -57
  33. glaip_sdk/cli/io.py +0 -112
  34. glaip_sdk/cli/main.py +0 -604
  35. glaip_sdk/cli/masking.py +0 -136
  36. glaip_sdk/cli/mcp_validators.py +0 -287
  37. glaip_sdk/cli/pager.py +0 -266
  38. glaip_sdk/cli/parsers/__init__.py +0 -7
  39. glaip_sdk/cli/parsers/json_input.py +0 -177
  40. glaip_sdk/cli/resolution.py +0 -67
  41. glaip_sdk/cli/rich_helpers.py +0 -27
  42. glaip_sdk/cli/slash/__init__.py +0 -15
  43. glaip_sdk/cli/slash/accounts_controller.py +0 -578
  44. glaip_sdk/cli/slash/accounts_shared.py +0 -75
  45. glaip_sdk/cli/slash/agent_session.py +0 -285
  46. glaip_sdk/cli/slash/prompt.py +0 -256
  47. glaip_sdk/cli/slash/remote_runs_controller.py +0 -566
  48. glaip_sdk/cli/slash/session.py +0 -1708
  49. glaip_sdk/cli/slash/tui/__init__.py +0 -9
  50. glaip_sdk/cli/slash/tui/accounts_app.py +0 -876
  51. glaip_sdk/cli/slash/tui/background_tasks.py +0 -72
  52. glaip_sdk/cli/slash/tui/loading.py +0 -58
  53. glaip_sdk/cli/slash/tui/remote_runs_app.py +0 -628
  54. glaip_sdk/cli/transcript/__init__.py +0 -31
  55. glaip_sdk/cli/transcript/cache.py +0 -536
  56. glaip_sdk/cli/transcript/capture.py +0 -329
  57. glaip_sdk/cli/transcript/export.py +0 -38
  58. glaip_sdk/cli/transcript/history.py +0 -815
  59. glaip_sdk/cli/transcript/launcher.py +0 -77
  60. glaip_sdk/cli/transcript/viewer.py +0 -374
  61. glaip_sdk/cli/update_notifier.py +0 -290
  62. glaip_sdk/cli/utils.py +0 -263
  63. glaip_sdk/cli/validators.py +0 -238
  64. glaip_sdk/client/__init__.py +0 -11
  65. glaip_sdk/client/_agent_payloads.py +0 -520
  66. glaip_sdk/client/agent_runs.py +0 -147
  67. glaip_sdk/client/agents.py +0 -1335
  68. glaip_sdk/client/base.py +0 -502
  69. glaip_sdk/client/main.py +0 -249
  70. glaip_sdk/client/mcps.py +0 -370
  71. glaip_sdk/client/run_rendering.py +0 -700
  72. glaip_sdk/client/shared.py +0 -21
  73. glaip_sdk/client/tools.py +0 -661
  74. glaip_sdk/client/validators.py +0 -198
  75. glaip_sdk/config/constants.py +0 -52
  76. glaip_sdk/mcps/__init__.py +0 -21
  77. glaip_sdk/mcps/base.py +0 -345
  78. glaip_sdk/models/__init__.py +0 -90
  79. glaip_sdk/models/agent.py +0 -47
  80. glaip_sdk/models/agent_runs.py +0 -116
  81. glaip_sdk/models/common.py +0 -42
  82. glaip_sdk/models/mcp.py +0 -33
  83. glaip_sdk/models/tool.py +0 -33
  84. glaip_sdk/payload_schemas/__init__.py +0 -7
  85. glaip_sdk/payload_schemas/agent.py +0 -85
  86. glaip_sdk/registry/__init__.py +0 -55
  87. glaip_sdk/registry/agent.py +0 -164
  88. glaip_sdk/registry/base.py +0 -139
  89. glaip_sdk/registry/mcp.py +0 -253
  90. glaip_sdk/registry/tool.py +0 -232
  91. glaip_sdk/runner/__init__.py +0 -59
  92. glaip_sdk/runner/base.py +0 -84
  93. glaip_sdk/runner/deps.py +0 -115
  94. glaip_sdk/runner/langgraph.py +0 -782
  95. glaip_sdk/runner/mcp_adapter/__init__.py +0 -13
  96. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +0 -43
  97. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +0 -257
  98. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +0 -95
  99. glaip_sdk/runner/tool_adapter/__init__.py +0 -18
  100. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +0 -44
  101. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +0 -219
  102. glaip_sdk/tools/__init__.py +0 -22
  103. glaip_sdk/tools/base.py +0 -435
  104. glaip_sdk/utils/__init__.py +0 -86
  105. glaip_sdk/utils/a2a/__init__.py +0 -34
  106. glaip_sdk/utils/a2a/event_processor.py +0 -188
  107. glaip_sdk/utils/agent_config.py +0 -194
  108. glaip_sdk/utils/bundler.py +0 -267
  109. glaip_sdk/utils/client.py +0 -111
  110. glaip_sdk/utils/client_utils.py +0 -486
  111. glaip_sdk/utils/datetime_helpers.py +0 -58
  112. glaip_sdk/utils/discovery.py +0 -78
  113. glaip_sdk/utils/display.py +0 -135
  114. glaip_sdk/utils/export.py +0 -143
  115. glaip_sdk/utils/general.py +0 -61
  116. glaip_sdk/utils/import_export.py +0 -168
  117. glaip_sdk/utils/import_resolver.py +0 -492
  118. glaip_sdk/utils/instructions.py +0 -101
  119. glaip_sdk/utils/rendering/__init__.py +0 -115
  120. glaip_sdk/utils/rendering/formatting.py +0 -264
  121. glaip_sdk/utils/rendering/layout/__init__.py +0 -64
  122. glaip_sdk/utils/rendering/layout/panels.py +0 -156
  123. glaip_sdk/utils/rendering/layout/progress.py +0 -202
  124. glaip_sdk/utils/rendering/layout/summary.py +0 -74
  125. glaip_sdk/utils/rendering/layout/transcript.py +0 -606
  126. glaip_sdk/utils/rendering/models.py +0 -85
  127. glaip_sdk/utils/rendering/renderer/__init__.py +0 -55
  128. glaip_sdk/utils/rendering/renderer/base.py +0 -1024
  129. glaip_sdk/utils/rendering/renderer/config.py +0 -27
  130. glaip_sdk/utils/rendering/renderer/console.py +0 -55
  131. glaip_sdk/utils/rendering/renderer/debug.py +0 -178
  132. glaip_sdk/utils/rendering/renderer/factory.py +0 -138
  133. glaip_sdk/utils/rendering/renderer/stream.py +0 -202
  134. glaip_sdk/utils/rendering/renderer/summary_window.py +0 -79
  135. glaip_sdk/utils/rendering/renderer/thinking.py +0 -273
  136. glaip_sdk/utils/rendering/renderer/toggle.py +0 -182
  137. glaip_sdk/utils/rendering/renderer/tool_panels.py +0 -442
  138. glaip_sdk/utils/rendering/renderer/transcript_mode.py +0 -162
  139. glaip_sdk/utils/rendering/state.py +0 -204
  140. glaip_sdk/utils/rendering/step_tree_state.py +0 -100
  141. glaip_sdk/utils/rendering/steps/__init__.py +0 -34
  142. glaip_sdk/utils/rendering/steps/event_processor.py +0 -778
  143. glaip_sdk/utils/rendering/steps/format.py +0 -176
  144. glaip_sdk/utils/rendering/steps/manager.py +0 -387
  145. glaip_sdk/utils/rendering/timing.py +0 -36
  146. glaip_sdk/utils/rendering/viewer/__init__.py +0 -21
  147. glaip_sdk/utils/rendering/viewer/presenter.py +0 -184
  148. glaip_sdk/utils/resource_refs.py +0 -195
  149. glaip_sdk/utils/run_renderer.py +0 -41
  150. glaip_sdk/utils/runtime_config.py +0 -425
  151. glaip_sdk/utils/serialization.py +0 -424
  152. glaip_sdk/utils/sync.py +0 -142
  153. glaip_sdk/utils/tool_detection.py +0 -33
  154. glaip_sdk/utils/validation.py +0 -264
  155. glaip_sdk-0.6.12.dist-info/RECORD +0 -159
  156. glaip_sdk-0.6.12.dist-info/entry_points.txt +0 -3
@@ -1,77 +0,0 @@
1
- """Utilities for launching the post-run transcript viewer.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- import sys
10
- from pathlib import Path
11
- from typing import Any
12
-
13
- from rich.console import Console
14
-
15
- from glaip_sdk.cli.context import get_ctx_value
16
- from glaip_sdk.cli.transcript.cache import (
17
- export_transcript as export_cached_transcript,
18
- )
19
- from glaip_sdk.cli.transcript.capture import StoredTranscriptContext
20
- from glaip_sdk.cli.transcript.viewer import ViewerContext, run_viewer_session
21
-
22
-
23
- def should_launch_post_run_viewer(ctx: Any, console: Console, *, slash_mode: bool) -> bool:
24
- """Return True if the viewer should open automatically."""
25
- if slash_mode:
26
- return False
27
- ctx_obj = getattr(ctx, "obj", None)
28
- if isinstance(ctx_obj, dict) and ctx_obj.get("_slash_session"):
29
- return False
30
- if get_ctx_value(ctx, "view", "rich") != "rich":
31
- return False
32
- if not bool(get_ctx_value(ctx, "tty", True)):
33
- return False
34
- if not console.is_terminal:
35
- return False
36
- try:
37
- if not sys.stdin.isatty():
38
- return False
39
- except Exception:
40
- return False
41
- return True
42
-
43
-
44
- def maybe_launch_post_run_viewer(
45
- ctx: Any,
46
- transcript_context: StoredTranscriptContext | None,
47
- *,
48
- console: Console,
49
- slash_mode: bool,
50
- ) -> None:
51
- """Launch the post-run viewer when context and settings allow it."""
52
- if transcript_context is None:
53
- return
54
- if not should_launch_post_run_viewer(ctx, console, slash_mode=slash_mode):
55
- return
56
-
57
- manifest_entry = transcript_context.store_result.manifest_entry
58
- run_id = manifest_entry.get("run_id")
59
- if not run_id:
60
- return
61
-
62
- viewer_ctx = ViewerContext(
63
- manifest_entry=manifest_entry,
64
- events=transcript_context.payload.events,
65
- default_output=transcript_context.payload.default_output,
66
- final_output=transcript_context.payload.final_output,
67
- stream_started_at=None,
68
- meta=transcript_context.payload.meta,
69
- )
70
-
71
- def _export(destination: Path) -> Path:
72
- return export_cached_transcript(destination=destination, run_id=run_id)
73
-
74
- run_viewer_session(console, viewer_ctx, _export)
75
-
76
-
77
- __all__ = ["should_launch_post_run_viewer", "maybe_launch_post_run_viewer"]
@@ -1,374 +0,0 @@
1
- """Interactive viewer for post-run transcript exploration.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from collections.abc import Callable
10
- from pathlib import Path
11
- from typing import Any
12
-
13
- import click
14
- from rich.console import Console
15
-
16
- try: # pragma: no cover - optional dependency
17
- import questionary
18
- from questionary import Choice
19
- except Exception: # pragma: no cover - optional dependency
20
- questionary = None # type: ignore[assignment]
21
- Choice = None # type: ignore[assignment]
22
-
23
- from glaip_sdk.cli.transcript.cache import suggest_filename
24
- from glaip_sdk.cli.utils import prompt_export_choice_questionary, questionary_safe_ask
25
- from glaip_sdk.utils.rendering.layout.progress import is_delegation_tool
26
- from glaip_sdk.utils.rendering.layout.transcript import DEFAULT_TRANSCRIPT_THEME
27
- from glaip_sdk.utils.rendering.viewer import (
28
- ViewerContext as PresenterViewerContext,
29
- prepare_viewer_snapshot as presenter_prepare_viewer_snapshot,
30
- render_post_run_view as presenter_render_post_run_view,
31
- render_transcript_events as presenter_render_transcript_events,
32
- render_transcript_view as presenter_render_transcript_view,
33
- )
34
-
35
- EXPORT_CANCELLED_MESSAGE = "[dim]Export cancelled.[/dim]"
36
-
37
-
38
- ViewerContext = PresenterViewerContext
39
-
40
-
41
- class PostRunViewer: # pragma: no cover - interactive flows are not unit tested
42
- """Simple interactive session for inspecting agent run transcripts."""
43
-
44
- def __init__(
45
- self,
46
- console: Console,
47
- ctx: ViewerContext,
48
- export_callback: Callable[[Path], Path],
49
- *,
50
- initial_view: str = "default",
51
- ) -> None:
52
- """Initialize viewer state for a captured transcript."""
53
- self.console = console
54
- self.ctx = ctx
55
- self._export_callback = export_callback
56
- self._view_mode = initial_view if initial_view in {"default", "transcript"} else "default"
57
-
58
- def run(self) -> None:
59
- """Enter the interactive loop."""
60
- if not self.ctx.events and not (self.ctx.default_output or self.ctx.final_output):
61
- return
62
- if self._view_mode == "transcript":
63
- self._render()
64
- self._print_command_hint()
65
- self._fallback_loop()
66
-
67
- # ------------------------------------------------------------------
68
- # Rendering helpers
69
- # ------------------------------------------------------------------
70
- def _render(self) -> None:
71
- """Render the transcript viewer interface."""
72
- try:
73
- if self.console.is_terminal:
74
- self.console.clear()
75
- except Exception: # pragma: no cover - platform quirks
76
- pass
77
-
78
- header = f"Agent transcript viewer · run {self.ctx.manifest_entry.get('run_id')}"
79
- agent_label = self.ctx.manifest_entry.get("agent_name") or "unknown agent"
80
- model = self.ctx.manifest_entry.get("model") or self.ctx.meta.get("model")
81
- agent_id = self.ctx.manifest_entry.get("agent_id")
82
- subtitle_parts = [agent_label]
83
- if model:
84
- subtitle_parts.append(str(model))
85
- if agent_id:
86
- subtitle_parts.append(agent_id)
87
-
88
- if self._view_mode == "transcript":
89
- self.console.rule(header)
90
- if subtitle_parts:
91
- self.console.print(f"[dim]{' · '.join(subtitle_parts)}[/]")
92
- self.console.print()
93
-
94
- if self._view_mode == "default":
95
- presenter_render_post_run_view(self.console, self.ctx)
96
- else:
97
- theme = DEFAULT_TRANSCRIPT_THEME
98
- snapshot, state = presenter_prepare_viewer_snapshot(self.ctx, glyphs=None, theme=theme)
99
- presenter_render_transcript_view(self.console, snapshot, theme=theme)
100
- presenter_render_transcript_events(self.console, state.events)
101
-
102
- # ------------------------------------------------------------------
103
- # Interaction loops
104
- # ------------------------------------------------------------------
105
- def _fallback_loop(self) -> None:
106
- """Fallback interaction loop for non-interactive terminals."""
107
- while True:
108
- try:
109
- ch = click.getchar()
110
- except (EOFError, KeyboardInterrupt):
111
- break
112
-
113
- if ch in {"\r", "\n"}:
114
- break
115
-
116
- if ch == "\x14" or ch.lower() == "t": # Ctrl+T or t
117
- self.toggle_view()
118
- continue
119
-
120
- if ch.lower() == "e":
121
- self.export_transcript()
122
- self._print_command_hint()
123
- else:
124
- continue
125
-
126
- def _handle_command(self, raw: str) -> bool:
127
- """Handle a command input.
128
-
129
- Args:
130
- raw: Raw command string.
131
-
132
- Returns:
133
- True to continue, False to exit.
134
- """
135
- lowered = raw.lower()
136
- if lowered in {"exit", "quit", "q"}:
137
- return True
138
- if lowered in {"export", "e"}:
139
- self.export_transcript()
140
- self._print_command_hint()
141
- return False
142
- self.console.print("[dim]Commands: export, exit.[/dim]")
143
- return False
144
-
145
- # ------------------------------------------------------------------
146
- # Actions
147
- # ------------------------------------------------------------------
148
- def toggle_view(self) -> None:
149
- """Switch between default result view and verbose transcript."""
150
- self._view_mode = "transcript" if self._view_mode == "default" else "default"
151
- self._render()
152
- self._print_command_hint()
153
-
154
- def export_transcript(self) -> None:
155
- """Prompt user for a destination and export the cached transcript."""
156
- entry = self.ctx.manifest_entry
157
- default_name = suggest_filename(entry)
158
- default_path = Path.cwd() / default_name
159
-
160
- def _display_path(path: Path) -> str:
161
- raw = str(path)
162
- return raw if len(raw) <= 80 else f"…{raw[-77:]}"
163
-
164
- selection = self._prompt_export_choice(default_path, _display_path(default_path))
165
- if selection is None:
166
- self._legacy_export_prompt(default_path, _display_path)
167
- return
168
-
169
- action, _ = selection
170
- if action == "cancel":
171
- self.console.print(EXPORT_CANCELLED_MESSAGE)
172
- return
173
-
174
- if action == "default":
175
- destination = default_path
176
- else:
177
- destination = self._prompt_custom_destination()
178
- if destination is None:
179
- self.console.print(EXPORT_CANCELLED_MESSAGE)
180
- return
181
-
182
- try:
183
- target = self._export_callback(destination)
184
- self.console.print(f"[green]Transcript exported to {target}[/green]")
185
- except FileNotFoundError as exc:
186
- self.console.print(f"[red]{exc}[/red]")
187
- except Exception as exc: # pragma: no cover - unexpected IO failures
188
- self.console.print(f"[red]Failed to export transcript: {exc}[/red]")
189
-
190
- def _prompt_export_choice(self, default_path: Path, default_display: str) -> tuple[str, Any] | None:
191
- """Render interactive export menu with numeric shortcuts."""
192
- if not self.console.is_terminal:
193
- return None
194
-
195
- return prompt_export_choice_questionary(default_path, default_display)
196
-
197
- def _prompt_custom_destination(self) -> Path | None:
198
- """Prompt for custom export path with filesystem completion."""
199
- if not self.console.is_terminal:
200
- return None
201
-
202
- try:
203
- question = questionary.path(
204
- "Destination path (Tab to autocomplete):",
205
- default="",
206
- only_directories=False,
207
- )
208
- response = questionary_safe_ask(question)
209
- except Exception:
210
- return None
211
-
212
- if not response:
213
- return None
214
-
215
- candidate = Path(response.strip()).expanduser()
216
- if not candidate.is_absolute():
217
- candidate = Path.cwd() / candidate
218
- return candidate
219
-
220
- def _legacy_export_prompt(self, default_path: Path, formatter: Callable[[Path], str]) -> None:
221
- """Fallback export workflow when interactive UI is unavailable."""
222
- self.console.print("[dim]Export options (fallback mode)[/dim]")
223
- self.console.print(f" 1. Save to default ({formatter(default_path)})")
224
- self.console.print(" 2. Choose a different path")
225
- self.console.print(" 3. Cancel")
226
-
227
- try:
228
- choice = click.prompt(
229
- "Select option",
230
- type=click.Choice(["1", "2", "3"], case_sensitive=False),
231
- default="1",
232
- show_choices=False,
233
- )
234
- except (EOFError, KeyboardInterrupt):
235
- self.console.print(EXPORT_CANCELLED_MESSAGE)
236
- return
237
-
238
- if choice == "3":
239
- self.console.print(EXPORT_CANCELLED_MESSAGE)
240
- return
241
-
242
- if choice == "1":
243
- destination = default_path
244
- else:
245
- try:
246
- destination_str = click.prompt("Enter destination path", default="")
247
- except (EOFError, KeyboardInterrupt):
248
- self.console.print(EXPORT_CANCELLED_MESSAGE)
249
- return
250
- if not destination_str.strip():
251
- self.console.print(EXPORT_CANCELLED_MESSAGE)
252
- return
253
- destination = Path(destination_str.strip()).expanduser()
254
- if not destination.is_absolute():
255
- destination = Path.cwd() / destination
256
-
257
- try:
258
- target = self._export_callback(destination)
259
- self.console.print(f"[green]Transcript exported to {target}[/green]")
260
- except FileNotFoundError as exc:
261
- self.console.print(f"[red]{exc}[/red]")
262
- except Exception as exc: # pragma: no cover - unexpected IO failures
263
- self.console.print(f"[red]Failed to export transcript: {exc}[/red]")
264
-
265
- def _print_command_hint(self) -> None:
266
- """Print command hint for user interaction."""
267
- self.console.print("[dim]Ctrl+T to toggle transcript · type `e` to export · press Enter to exit[/dim]")
268
- self.console.print()
269
-
270
- @staticmethod
271
- def _extract_direct_tool(
272
- tool_info: dict[str, Any],
273
- ) -> tuple[str, dict[str, Any]] | None:
274
- """Extract direct tool from tool_info.
275
-
276
- Args:
277
- tool_info: Tool info dictionary.
278
-
279
- Returns:
280
- Tuple of (tool_name, tool_info) or None.
281
- """
282
- if isinstance(tool_info, dict):
283
- name = tool_info.get("name")
284
- if name:
285
- return name, tool_info
286
- return None
287
-
288
- @staticmethod
289
- def _extract_completed_name(event: dict[str, Any]) -> str | None:
290
- """Extract completed tool name from event content.
291
-
292
- Args:
293
- event: Event dictionary.
294
-
295
- Returns:
296
- Tool name or None.
297
- """
298
- content = event.get("content") or ""
299
- if isinstance(content, str) and content.startswith("Completed "):
300
- name = content.replace("Completed ", "").strip()
301
- if name:
302
- return name
303
- return None
304
-
305
- def _ensure_step_entry(
306
- self,
307
- steps: dict[str, dict[str, Any]],
308
- order: list[str],
309
- name: str,
310
- ) -> dict[str, Any]:
311
- """Ensure step entry exists, creating if needed.
312
-
313
- Args:
314
- steps: Steps dictionary.
315
- order: Order list.
316
- name: Step name.
317
-
318
- Returns:
319
- Step dictionary.
320
- """
321
- if name not in steps:
322
- steps[name] = {
323
- "name": name,
324
- "title": name,
325
- "is_delegate": is_delegation_tool(name),
326
- "duration": None,
327
- "started_at": None,
328
- "finished": False,
329
- }
330
- order.append(name)
331
- return steps[name]
332
-
333
- def _apply_step_update(
334
- self,
335
- step: dict[str, Any],
336
- metadata: dict[str, Any],
337
- info: dict[str, Any],
338
- event: dict[str, Any],
339
- ) -> None:
340
- """Apply update to step from event metadata.
341
-
342
- Args:
343
- step: Step dictionary to update.
344
- metadata: Event metadata.
345
- info: Step info dictionary.
346
- event: Event dictionary.
347
- """
348
- status = metadata.get("status")
349
- event_time = metadata.get("time")
350
-
351
- if status == "running" and step.get("started_at") is None and isinstance(event_time, (int, float)):
352
- try:
353
- step["started_at"] = float(event_time)
354
- except Exception:
355
- step["started_at"] = None
356
-
357
- if self._is_step_finished(metadata, event):
358
- step["finished"] = True
359
-
360
- duration = self._compute_step_duration(step, info, metadata)
361
- if duration is not None:
362
- step["duration"] = duration
363
-
364
-
365
- def run_viewer_session(
366
- console: Console,
367
- ctx: ViewerContext,
368
- export_callback: Callable[[Path], Path],
369
- *,
370
- initial_view: str = "default",
371
- ) -> None:
372
- """Entry point for creating and running the post-run viewer."""
373
- viewer = PostRunViewer(console, ctx, export_callback, initial_view=initial_view)
374
- viewer.run()