glaip-sdk 0.6.15b2__py3-none-any.whl → 0.6.15b3__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/__init__.py +27 -0
- glaip_sdk/agents/base.py +1196 -0
- glaip_sdk/cli/__init__.py +9 -0
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/agent_config.py +78 -0
- glaip_sdk/cli/auth.py +699 -0
- glaip_sdk/cli/commands/__init__.py +5 -0
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents.py +1509 -0
- glaip_sdk/cli/commands/common_config.py +104 -0
- glaip_sdk/cli/commands/configure.py +896 -0
- glaip_sdk/cli/commands/mcps.py +1356 -0
- glaip_sdk/cli/commands/models.py +69 -0
- glaip_sdk/cli/commands/tools.py +576 -0
- glaip_sdk/cli/commands/transcripts.py +755 -0
- glaip_sdk/cli/commands/update.py +61 -0
- glaip_sdk/cli/config.py +95 -0
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +150 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +851 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +355 -0
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +112 -0
- glaip_sdk/cli/main.py +615 -0
- glaip_sdk/cli/masking.py +136 -0
- glaip_sdk/cli/mcp_validators.py +287 -0
- glaip_sdk/cli/pager.py +266 -0
- glaip_sdk/cli/parsers/__init__.py +7 -0
- glaip_sdk/cli/parsers/json_input.py +177 -0
- glaip_sdk/cli/resolution.py +67 -0
- glaip_sdk/cli/rich_helpers.py +27 -0
- glaip_sdk/cli/slash/__init__.py +15 -0
- glaip_sdk/cli/slash/accounts_controller.py +578 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +285 -0
- glaip_sdk/cli/slash/prompt.py +256 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +1708 -0
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +876 -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 +31 -0
- glaip_sdk/cli/transcript/cache.py +536 -0
- glaip_sdk/cli/transcript/capture.py +329 -0
- glaip_sdk/cli/transcript/export.py +38 -0
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/launcher.py +77 -0
- glaip_sdk/cli/transcript/viewer.py +374 -0
- glaip_sdk/cli/update_notifier.py +290 -0
- glaip_sdk/cli/utils.py +263 -0
- glaip_sdk/cli/validators.py +238 -0
- glaip_sdk/client/__init__.py +11 -0
- glaip_sdk/client/_agent_payloads.py +520 -0
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +1335 -0
- glaip_sdk/client/base.py +502 -0
- glaip_sdk/client/main.py +249 -0
- glaip_sdk/client/mcps.py +370 -0
- glaip_sdk/client/run_rendering.py +700 -0
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +661 -0
- glaip_sdk/client/validators.py +198 -0
- glaip_sdk/config/constants.py +52 -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 +7 -0
- glaip_sdk/payload_schemas/agent.py +85 -0
- 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 +232 -0
- glaip_sdk/runner/__init__.py +59 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +112 -0
- glaip_sdk/runner/langgraph.py +782 -0
- glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +95 -0
- glaip_sdk/runner/tool_adapter/__init__.py +18 -0
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +219 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +435 -0
- glaip_sdk/utils/__init__.py +86 -0
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/agent_config.py +194 -0
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +486 -0
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +135 -0
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +61 -0
- glaip_sdk/utils/import_export.py +168 -0
- glaip_sdk/utils/import_resolver.py +492 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -0
- glaip_sdk/utils/rendering/formatting.py +264 -0
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/layout/panels.py +156 -0
- glaip_sdk/utils/rendering/layout/progress.py +202 -0
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +85 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +55 -0
- glaip_sdk/utils/rendering/renderer/base.py +1024 -0
- glaip_sdk/utils/rendering/renderer/config.py +27 -0
- glaip_sdk/utils/rendering/renderer/console.py +55 -0
- glaip_sdk/utils/rendering/renderer/debug.py +178 -0
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +202 -0
- glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/toggle.py +182 -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/step_tree_state.py +100 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/steps/event_processor.py +778 -0
- 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 +195 -0
- glaip_sdk/utils/run_renderer.py +41 -0
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +424 -0
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/tool_detection.py +33 -0
- glaip_sdk/utils/validation.py +264 -0
- {glaip_sdk-0.6.15b2.dist-info → glaip_sdk-0.6.15b3.dist-info}/METADATA +1 -1
- glaip_sdk-0.6.15b3.dist-info/RECORD +160 -0
- glaip_sdk-0.6.15b2.dist-info/RECORD +0 -12
- {glaip_sdk-0.6.15b2.dist-info → glaip_sdk-0.6.15b3.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.6.15b2.dist-info → glaip_sdk-0.6.15b3.dist-info}/entry_points.txt +0 -0
- {glaip_sdk-0.6.15b2.dist-info → glaip_sdk-0.6.15b3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"""Helpers for capturing and caching agent run transcripts.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from io import StringIO
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
|
|
16
|
+
from glaip_sdk.cli.auth import resolve_api_url_from_context
|
|
17
|
+
from glaip_sdk.cli.context import get_ctx_value
|
|
18
|
+
from glaip_sdk.cli.transcript.cache import (
|
|
19
|
+
TranscriptPayload,
|
|
20
|
+
TranscriptStoreResult,
|
|
21
|
+
store_transcript,
|
|
22
|
+
)
|
|
23
|
+
from glaip_sdk.cli.transcript.cache import (
|
|
24
|
+
build_payload as build_transcript_payload,
|
|
25
|
+
)
|
|
26
|
+
from glaip_sdk.utils.rendering.layout.progress import format_tool_title
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(slots=True)
|
|
30
|
+
class StoredTranscriptContext:
|
|
31
|
+
"""Simple container linking payload and manifest data."""
|
|
32
|
+
|
|
33
|
+
payload: TranscriptPayload
|
|
34
|
+
store_result: TranscriptStoreResult
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def coerce_events(value: Any) -> list[dict[str, Any]]:
|
|
38
|
+
"""Normalise renderer events into a list of dictionaries."""
|
|
39
|
+
if not value:
|
|
40
|
+
return []
|
|
41
|
+
if isinstance(value, list):
|
|
42
|
+
return [item for item in value if isinstance(item, dict)]
|
|
43
|
+
try:
|
|
44
|
+
return [item for item in value if isinstance(item, dict)]
|
|
45
|
+
except Exception:
|
|
46
|
+
return []
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def coerce_result_text(result: Any) -> str:
|
|
50
|
+
"""Serialise renderer output to a string for transcript payloads."""
|
|
51
|
+
if result is None:
|
|
52
|
+
return ""
|
|
53
|
+
if isinstance(result, str):
|
|
54
|
+
return result
|
|
55
|
+
try:
|
|
56
|
+
return json.dumps(result, ensure_ascii=False, indent=2)
|
|
57
|
+
except Exception:
|
|
58
|
+
return str(result)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def compute_finished_at(renderer: Any) -> float | None:
|
|
62
|
+
"""Best-effort end-time calculation based on renderer state."""
|
|
63
|
+
state = getattr(renderer, "state", None)
|
|
64
|
+
if state is not None:
|
|
65
|
+
started_at = getattr(state, "streaming_started_at", None)
|
|
66
|
+
duration = getattr(state, "final_duration_seconds", None)
|
|
67
|
+
else:
|
|
68
|
+
started_at = None
|
|
69
|
+
duration = None
|
|
70
|
+
|
|
71
|
+
if started_at is None:
|
|
72
|
+
stream_processor = getattr(renderer, "stream_processor", None)
|
|
73
|
+
started_at = getattr(stream_processor, "streaming_started_at", None) if stream_processor is not None else None
|
|
74
|
+
if started_at is None or duration is None:
|
|
75
|
+
return None
|
|
76
|
+
try:
|
|
77
|
+
return float(started_at) + float(duration)
|
|
78
|
+
except Exception:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def extract_server_run_id(meta: dict[str, Any], events: list[dict[str, Any]]) -> str | None:
|
|
83
|
+
"""Derive a server-side run identifier from renderer metadata."""
|
|
84
|
+
run_id = meta.get("run_id") or meta.get("id")
|
|
85
|
+
if run_id:
|
|
86
|
+
return str(run_id)
|
|
87
|
+
for event in events:
|
|
88
|
+
metadata = event.get("metadata") or {}
|
|
89
|
+
candidate = metadata.get("run_id") or metadata.get("request_id")
|
|
90
|
+
if candidate:
|
|
91
|
+
return str(candidate)
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _coerce_meta(meta: Any) -> dict[str, Any]:
|
|
96
|
+
"""Ensure renderer metadata is recorded as a plain dictionary."""
|
|
97
|
+
if meta is None:
|
|
98
|
+
return {}
|
|
99
|
+
if isinstance(meta, dict):
|
|
100
|
+
return meta
|
|
101
|
+
if hasattr(meta, "items"):
|
|
102
|
+
try:
|
|
103
|
+
return {str(key): value for key, value in meta.items()}
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
return {"value": coerce_result_text(meta)}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def register_last_transcript(ctx: Any, payload: TranscriptPayload, store_result: TranscriptStoreResult) -> None:
|
|
110
|
+
"""Persist last-run transcript references onto the Click context."""
|
|
111
|
+
ctx_obj = getattr(ctx, "obj", None)
|
|
112
|
+
if not isinstance(ctx_obj, dict):
|
|
113
|
+
return
|
|
114
|
+
ctx_obj["_last_transcript_payload"] = payload
|
|
115
|
+
ctx_obj["_last_transcript_manifest"] = store_result.manifest_entry
|
|
116
|
+
ctx_obj["_last_transcript_path"] = str(store_result.path)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _resolve_api_url(ctx: Any) -> str | None:
|
|
120
|
+
"""Resolve API URL from context or account store (CLI/palette ignores env creds)."""
|
|
121
|
+
return resolve_api_url_from_context(
|
|
122
|
+
ctx,
|
|
123
|
+
get_api_url=lambda c: get_ctx_value(c, "api_url"),
|
|
124
|
+
get_account_name=lambda c: get_ctx_value(c, "account_name"),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _extract_step_summaries(renderer: Any) -> list[dict[str, Any]]:
|
|
129
|
+
"""Return lightweight step summaries for the transcript viewer."""
|
|
130
|
+
steps = getattr(renderer, "steps", None)
|
|
131
|
+
if steps is None:
|
|
132
|
+
return []
|
|
133
|
+
|
|
134
|
+
order = getattr(steps, "order", []) or []
|
|
135
|
+
by_id = getattr(steps, "by_id", {}) or {}
|
|
136
|
+
|
|
137
|
+
return [
|
|
138
|
+
_build_step_summary(by_id.get(step_id), index)
|
|
139
|
+
for index, step_id in enumerate(order)
|
|
140
|
+
if by_id.get(step_id) is not None
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _build_step_summary(step: Any, index: int) -> dict[str, Any]:
|
|
145
|
+
"""Construct a single step summary entry."""
|
|
146
|
+
kind = getattr(step, "kind", "") or ""
|
|
147
|
+
name = getattr(step, "name", "") or ""
|
|
148
|
+
status = getattr(step, "status", "") or ""
|
|
149
|
+
duration_ms = _coerce_duration_ms(getattr(step, "duration_ms", None))
|
|
150
|
+
display_name = _format_step_display_name(name)
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
"index": index,
|
|
154
|
+
"step_id": getattr(step, "step_id", f"step-{index}"),
|
|
155
|
+
"kind": kind,
|
|
156
|
+
"name": name,
|
|
157
|
+
"display_name": display_name,
|
|
158
|
+
"status": status,
|
|
159
|
+
"duration_ms": duration_ms,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _coerce_duration_ms(value: Any) -> int | None:
|
|
164
|
+
"""Return duration in milliseconds if numeric, otherwise None."""
|
|
165
|
+
try:
|
|
166
|
+
if isinstance(value, (int, float)):
|
|
167
|
+
return int(value)
|
|
168
|
+
except Exception:
|
|
169
|
+
return None
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _format_step_display_name(name: str) -> str:
|
|
174
|
+
"""Apply tool title formatting with a safe fallback."""
|
|
175
|
+
try:
|
|
176
|
+
return format_tool_title(name)
|
|
177
|
+
except Exception:
|
|
178
|
+
return name
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _extract_step_summary_lines(renderer: Any) -> list[str]:
|
|
182
|
+
"""Render the live steps summary to plain text lines."""
|
|
183
|
+
if not hasattr(renderer, "_render_steps_text"):
|
|
184
|
+
return []
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
renderable = renderer._render_steps_text()
|
|
188
|
+
except Exception:
|
|
189
|
+
return []
|
|
190
|
+
|
|
191
|
+
buffer = StringIO()
|
|
192
|
+
console = Console(file=buffer, record=True, force_terminal=False, width=120)
|
|
193
|
+
try:
|
|
194
|
+
console.print(renderable)
|
|
195
|
+
except Exception:
|
|
196
|
+
return []
|
|
197
|
+
|
|
198
|
+
text = console.export_text() or buffer.getvalue()
|
|
199
|
+
lines = [line.rstrip() for line in text.splitlines()]
|
|
200
|
+
half = len(lines) // 2
|
|
201
|
+
if half and lines[:half] == lines[half : half * 2]:
|
|
202
|
+
return lines[:half]
|
|
203
|
+
start = 0
|
|
204
|
+
prefixes = ("🤖", "🔧", "💭", "├", "└", "│", "•")
|
|
205
|
+
for idx, line in enumerate(lines):
|
|
206
|
+
if line.lstrip().startswith(prefixes):
|
|
207
|
+
start = idx
|
|
208
|
+
break
|
|
209
|
+
trimmed = lines[start:]
|
|
210
|
+
return [line for line in trimmed if line]
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _collect_renderer_outputs(
|
|
214
|
+
renderer: Any, final_result: Any
|
|
215
|
+
) -> tuple[
|
|
216
|
+
list[dict[str, Any]],
|
|
217
|
+
str,
|
|
218
|
+
str,
|
|
219
|
+
]:
|
|
220
|
+
"""Collect events and text outputs from a renderer with safe fallbacks."""
|
|
221
|
+
events_raw = []
|
|
222
|
+
if hasattr(renderer, "get_transcript_events"):
|
|
223
|
+
try:
|
|
224
|
+
events_raw = renderer.get_transcript_events()
|
|
225
|
+
except Exception:
|
|
226
|
+
events_raw = []
|
|
227
|
+
events = coerce_events(events_raw)
|
|
228
|
+
|
|
229
|
+
aggregated_raw = ""
|
|
230
|
+
if hasattr(renderer, "get_aggregated_output"):
|
|
231
|
+
try:
|
|
232
|
+
aggregated_raw = renderer.get_aggregated_output()
|
|
233
|
+
except Exception:
|
|
234
|
+
aggregated_raw = ""
|
|
235
|
+
|
|
236
|
+
aggregated_output = coerce_result_text(aggregated_raw)
|
|
237
|
+
final_output = coerce_result_text(final_result)
|
|
238
|
+
return events, aggregated_output, final_output
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _derive_transcript_meta(
|
|
242
|
+
renderer: Any, model: str | None
|
|
243
|
+
) -> tuple[dict[str, Any], float | None, float | None, str | None]:
|
|
244
|
+
"""Build transcript metadata including step summaries and timings."""
|
|
245
|
+
raw_meta = getattr(getattr(renderer, "state", None), "meta", {}) or {}
|
|
246
|
+
meta = _coerce_meta(raw_meta)
|
|
247
|
+
|
|
248
|
+
step_summaries = _extract_step_summaries(renderer)
|
|
249
|
+
if step_summaries:
|
|
250
|
+
meta["transcript_steps"] = step_summaries
|
|
251
|
+
|
|
252
|
+
step_lines = _extract_step_summary_lines(renderer)
|
|
253
|
+
if step_lines:
|
|
254
|
+
meta["transcript_step_lines"] = step_lines
|
|
255
|
+
|
|
256
|
+
stream_processor = getattr(renderer, "stream_processor", None)
|
|
257
|
+
stream_started_at = (
|
|
258
|
+
getattr(stream_processor, "streaming_started_at", None) if stream_processor is not None else None
|
|
259
|
+
)
|
|
260
|
+
finished_at = compute_finished_at(renderer)
|
|
261
|
+
state = getattr(renderer, "state", None)
|
|
262
|
+
if state is not None:
|
|
263
|
+
duration_hint = getattr(state, "final_duration_seconds", None)
|
|
264
|
+
if duration_hint is not None:
|
|
265
|
+
try:
|
|
266
|
+
meta["final_duration_seconds"] = float(duration_hint)
|
|
267
|
+
except Exception:
|
|
268
|
+
pass
|
|
269
|
+
model_name = meta.get("model") or model
|
|
270
|
+
return meta, stream_started_at, finished_at, model_name
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def store_transcript_for_session(
|
|
274
|
+
ctx: Any,
|
|
275
|
+
renderer: Any,
|
|
276
|
+
*,
|
|
277
|
+
final_result: Any,
|
|
278
|
+
agent_id: str | None,
|
|
279
|
+
agent_name: str | None,
|
|
280
|
+
model: str | None,
|
|
281
|
+
source: str,
|
|
282
|
+
) -> StoredTranscriptContext | None:
|
|
283
|
+
"""Capture renderer output and persist the transcript for later reuse."""
|
|
284
|
+
if not hasattr(renderer, "get_transcript_events"):
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
events, aggregated_output, final_output = _collect_renderer_outputs(renderer, final_result)
|
|
288
|
+
|
|
289
|
+
if not (events or aggregated_output or final_output):
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
meta, stream_started_at, finished_at, model_name = _derive_transcript_meta(renderer, model)
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
api_url = _resolve_api_url(ctx)
|
|
296
|
+
except Exception:
|
|
297
|
+
api_url = None
|
|
298
|
+
if api_url:
|
|
299
|
+
meta["api_url"] = api_url
|
|
300
|
+
|
|
301
|
+
payload: TranscriptPayload = build_transcript_payload(
|
|
302
|
+
events=events,
|
|
303
|
+
renderer_output=aggregated_output,
|
|
304
|
+
final_output=final_output,
|
|
305
|
+
agent_id=agent_id,
|
|
306
|
+
agent_name=agent_name,
|
|
307
|
+
model=model_name,
|
|
308
|
+
server_run_id=extract_server_run_id(meta, events),
|
|
309
|
+
started_at=stream_started_at,
|
|
310
|
+
finished_at=finished_at,
|
|
311
|
+
meta=meta,
|
|
312
|
+
source=source,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
store_result = store_transcript(payload)
|
|
316
|
+
register_last_transcript(ctx, payload, store_result)
|
|
317
|
+
|
|
318
|
+
return StoredTranscriptContext(payload=payload, store_result=store_result)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
__all__ = [
|
|
322
|
+
"StoredTranscriptContext",
|
|
323
|
+
"coerce_events",
|
|
324
|
+
"coerce_result_text",
|
|
325
|
+
"compute_finished_at",
|
|
326
|
+
"extract_server_run_id",
|
|
327
|
+
"register_last_transcript",
|
|
328
|
+
"store_transcript_for_session",
|
|
329
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Shared helpers for transcript export workflows.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from glaip_sdk.cli.transcript.cache import (
|
|
13
|
+
latest_manifest_entry,
|
|
14
|
+
resolve_manifest_entry,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def resolve_manifest_for_export(ctx: Any, run_id: str | None) -> dict[str, Any] | None:
|
|
19
|
+
"""Resolve a manifest entry for export based on run id or recent context."""
|
|
20
|
+
if run_id:
|
|
21
|
+
return resolve_manifest_entry(run_id)
|
|
22
|
+
|
|
23
|
+
ctx_obj = ctx if isinstance(ctx, dict) else getattr(ctx, "obj", None)
|
|
24
|
+
if isinstance(ctx_obj, dict):
|
|
25
|
+
candidate = ctx_obj.get("_last_transcript_manifest")
|
|
26
|
+
if isinstance(candidate, dict):
|
|
27
|
+
return candidate
|
|
28
|
+
|
|
29
|
+
return latest_manifest_entry()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def normalise_export_destination(path: Path) -> Path:
|
|
33
|
+
"""Return an absolute path for the export destination."""
|
|
34
|
+
expanded = path.expanduser()
|
|
35
|
+
return expanded if expanded.is_absolute() else Path.cwd() / expanded
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ["resolve_manifest_for_export", "normalise_export_destination"]
|