glaip-sdk 0.0.20__py3-none-any.whl → 0.6.5b6__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 +10 -3
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1126 -0
- glaip_sdk/branding.py +15 -6
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/agent_config.py +2 -6
- glaip_sdk/cli/auth.py +265 -45
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents.py +270 -173
- glaip_sdk/cli/commands/common_config.py +101 -0
- glaip_sdk/cli/commands/configure.py +735 -143
- glaip_sdk/cli/commands/mcps.py +265 -134
- glaip_sdk/cli/commands/models.py +13 -9
- glaip_sdk/cli/commands/tools.py +67 -88
- glaip_sdk/cli/commands/transcripts.py +755 -0
- glaip_sdk/cli/commands/update.py +3 -8
- glaip_sdk/cli/config.py +49 -7
- 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 +45 -32
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +14 -17
- glaip_sdk/cli/main.py +232 -143
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/mcp_validators.py +5 -15
- glaip_sdk/cli/pager.py +12 -19
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/parsers/json_input.py +11 -22
- glaip_sdk/cli/resolution.py +3 -9
- glaip_sdk/cli/rich_helpers.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 +61 -28
- glaip_sdk/cli/slash/prompt.py +13 -10
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +772 -222
- 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 +258 -60
- glaip_sdk/cli/transcript/capture.py +72 -21
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/launcher.py +1 -3
- glaip_sdk/cli/transcript/viewer.py +77 -329
- glaip_sdk/cli/update_notifier.py +177 -24
- glaip_sdk/cli/utils.py +242 -1309
- glaip_sdk/cli/validators.py +16 -18
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_agent_payloads.py +53 -37
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +320 -92
- glaip_sdk/client/base.py +78 -35
- glaip_sdk/client/main.py +19 -10
- glaip_sdk/client/mcps.py +123 -15
- glaip_sdk/client/run_rendering.py +218 -78
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +161 -34
- glaip_sdk/client/validators.py +20 -48
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/exceptions.py +1 -3
- glaip_sdk/icons.py +9 -3
- 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/payload_schemas/agent.py +1 -3
- 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 +231 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/runner/__init__.py +59 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +115 -0
- glaip_sdk/runner/langgraph.py +597 -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 +158 -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 +177 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +435 -0
- glaip_sdk/utils/__init__.py +58 -12
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/agent_config.py +4 -14
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +46 -28
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +25 -21
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +1 -36
- glaip_sdk/utils/import_export.py +15 -16
- 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 +38 -23
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer → layout}/panels.py +10 -3
- glaip_sdk/utils/rendering/{renderer → layout}/progress.py +73 -12
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +18 -8
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -51
- glaip_sdk/utils/rendering/renderer/base.py +476 -882
- glaip_sdk/utils/rendering/renderer/config.py +4 -10
- glaip_sdk/utils/rendering/renderer/debug.py +30 -34
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +13 -54
- 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.py → steps/manager.py} +122 -26
- 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 +29 -26
- glaip_sdk/utils/runtime_config.py +422 -0
- glaip_sdk/utils/serialization.py +32 -46
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/tool_detection.py +33 -0
- glaip_sdk/utils/validation.py +20 -28
- {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.6.5b6.dist-info}/METADATA +49 -4
- glaip_sdk-0.6.5b6.dist-info/RECORD +159 -0
- {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.6.5b6.dist-info}/WHEEL +1 -1
- glaip_sdk/models.py +0 -259
- glaip_sdk-0.0.20.dist-info/RECORD +0 -80
- {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.6.5b6.dist-info}/entry_points.txt +0 -0
|
@@ -7,9 +7,9 @@ Authors:
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
import io
|
|
11
10
|
import json
|
|
12
11
|
import logging
|
|
12
|
+
from collections.abc import Callable
|
|
13
13
|
from time import monotonic
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
@@ -19,8 +19,30 @@ from rich.console import Console as _Console
|
|
|
19
19
|
from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT
|
|
20
20
|
from glaip_sdk.utils.client_utils import iter_sse_events
|
|
21
21
|
from glaip_sdk.utils.rendering.models import RunStats
|
|
22
|
-
from glaip_sdk.utils.rendering.renderer import
|
|
23
|
-
|
|
22
|
+
from glaip_sdk.utils.rendering.renderer import (
|
|
23
|
+
RendererFactoryOptions,
|
|
24
|
+
RichStreamRenderer,
|
|
25
|
+
make_default_renderer,
|
|
26
|
+
make_minimal_renderer,
|
|
27
|
+
make_silent_renderer,
|
|
28
|
+
make_verbose_renderer,
|
|
29
|
+
)
|
|
30
|
+
from glaip_sdk.utils.rendering.state import TranscriptBuffer
|
|
31
|
+
|
|
32
|
+
NO_AGENT_RESPONSE_FALLBACK = "No agent response received."
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _coerce_to_string(value: Any) -> str:
|
|
36
|
+
"""Return a best-effort string representation for transcripts."""
|
|
37
|
+
try:
|
|
38
|
+
return str(value)
|
|
39
|
+
except Exception:
|
|
40
|
+
return f"{value}"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _has_visible_text(value: Any) -> bool:
|
|
44
|
+
"""Return True when the value is a non-empty string."""
|
|
45
|
+
return isinstance(value, str) and bool(value.strip())
|
|
24
46
|
|
|
25
47
|
|
|
26
48
|
class AgentRunRenderingManager:
|
|
@@ -33,6 +55,7 @@ class AgentRunRenderingManager:
|
|
|
33
55
|
logger: Optional logger instance, creates default if None
|
|
34
56
|
"""
|
|
35
57
|
self._logger = logger or logging.getLogger(__name__)
|
|
58
|
+
self._buffer_factory = TranscriptBuffer
|
|
36
59
|
|
|
37
60
|
# --------------------------------------------------------------------- #
|
|
38
61
|
# Renderer setup helpers
|
|
@@ -44,17 +67,38 @@ class AgentRunRenderingManager:
|
|
|
44
67
|
verbose: bool = False,
|
|
45
68
|
) -> RichStreamRenderer:
|
|
46
69
|
"""Create an appropriate renderer based on the supplied spec."""
|
|
70
|
+
transcript_buffer = self._buffer_factory()
|
|
71
|
+
base_options = RendererFactoryOptions(console=_Console(), transcript_buffer=transcript_buffer)
|
|
47
72
|
if isinstance(renderer_spec, RichStreamRenderer):
|
|
48
73
|
return renderer_spec
|
|
49
74
|
|
|
50
75
|
if isinstance(renderer_spec, str):
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
76
|
+
lowered = renderer_spec.lower()
|
|
77
|
+
if lowered == "silent":
|
|
78
|
+
return self._attach_buffer(base_options.build(make_silent_renderer), transcript_buffer)
|
|
79
|
+
if lowered == "minimal":
|
|
80
|
+
return self._attach_buffer(base_options.build(make_minimal_renderer), transcript_buffer)
|
|
81
|
+
if lowered == "verbose":
|
|
82
|
+
return self._attach_buffer(base_options.build(make_verbose_renderer), transcript_buffer)
|
|
83
|
+
|
|
84
|
+
if verbose:
|
|
85
|
+
return self._attach_buffer(base_options.build(make_verbose_renderer), transcript_buffer)
|
|
86
|
+
|
|
87
|
+
default_options = RendererFactoryOptions(
|
|
88
|
+
console=_Console(),
|
|
89
|
+
transcript_buffer=transcript_buffer,
|
|
90
|
+
verbose=verbose,
|
|
91
|
+
)
|
|
92
|
+
return self._attach_buffer(default_options.build(make_default_renderer), transcript_buffer)
|
|
56
93
|
|
|
57
|
-
|
|
94
|
+
@staticmethod
|
|
95
|
+
def _attach_buffer(renderer: RichStreamRenderer, buffer: TranscriptBuffer) -> RichStreamRenderer:
|
|
96
|
+
"""Attach a captured transcript buffer to a renderer for later inspection."""
|
|
97
|
+
try:
|
|
98
|
+
renderer._captured_transcript_buffer = buffer # type: ignore[attr-defined]
|
|
99
|
+
except Exception:
|
|
100
|
+
pass
|
|
101
|
+
return renderer
|
|
58
102
|
|
|
59
103
|
def build_initial_metadata(
|
|
60
104
|
self,
|
|
@@ -75,52 +119,6 @@ class AgentRunRenderingManager:
|
|
|
75
119
|
"""Notify renderer that streaming is starting."""
|
|
76
120
|
renderer.on_start(meta)
|
|
77
121
|
|
|
78
|
-
def _create_silent_renderer(self) -> RichStreamRenderer:
|
|
79
|
-
silent_config = RendererConfig(
|
|
80
|
-
live=False,
|
|
81
|
-
persist_live=False,
|
|
82
|
-
show_delegate_tool_panels=False,
|
|
83
|
-
render_thinking=False,
|
|
84
|
-
)
|
|
85
|
-
return RichStreamRenderer(
|
|
86
|
-
console=_Console(file=io.StringIO(), force_terminal=False),
|
|
87
|
-
cfg=silent_config,
|
|
88
|
-
verbose=False,
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
def _create_minimal_renderer(self) -> RichStreamRenderer:
|
|
92
|
-
minimal_config = RendererConfig(
|
|
93
|
-
live=False,
|
|
94
|
-
persist_live=False,
|
|
95
|
-
show_delegate_tool_panels=False,
|
|
96
|
-
render_thinking=False,
|
|
97
|
-
)
|
|
98
|
-
return RichStreamRenderer(
|
|
99
|
-
console=_Console(),
|
|
100
|
-
cfg=minimal_config,
|
|
101
|
-
verbose=False,
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
def _create_verbose_renderer(self) -> RichStreamRenderer:
|
|
105
|
-
verbose_config = RendererConfig(
|
|
106
|
-
theme="dark",
|
|
107
|
-
style="debug",
|
|
108
|
-
live=False,
|
|
109
|
-
show_delegate_tool_panels=False,
|
|
110
|
-
append_finished_snapshots=False,
|
|
111
|
-
)
|
|
112
|
-
return RichStreamRenderer(
|
|
113
|
-
console=_Console(),
|
|
114
|
-
cfg=verbose_config,
|
|
115
|
-
verbose=True,
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
def _create_default_renderer(self, verbose: bool) -> RichStreamRenderer:
|
|
119
|
-
if verbose:
|
|
120
|
-
return self._create_verbose_renderer()
|
|
121
|
-
default_config = RendererConfig()
|
|
122
|
-
return RichStreamRenderer(console=_Console(), cfg=default_config)
|
|
123
|
-
|
|
124
122
|
# --------------------------------------------------------------------- #
|
|
125
123
|
# Streaming event handling
|
|
126
124
|
# --------------------------------------------------------------------- #
|
|
@@ -139,17 +137,28 @@ class AgentRunRenderingManager:
|
|
|
139
137
|
|
|
140
138
|
self._capture_request_id(stream_response, meta, renderer)
|
|
141
139
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
controller = getattr(renderer, "transcript_controller", None)
|
|
141
|
+
if controller and getattr(controller, "enabled", False):
|
|
142
|
+
controller.on_stream_start(renderer)
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
144
|
+
try:
|
|
145
|
+
for event in iter_sse_events(stream_response, timeout_seconds, agent_name):
|
|
146
|
+
if started_monotonic is None:
|
|
147
|
+
started_monotonic = self._maybe_start_timer(event)
|
|
148
|
+
|
|
149
|
+
final_text, stats_usage = self._process_single_event(
|
|
150
|
+
event,
|
|
151
|
+
renderer,
|
|
152
|
+
final_text,
|
|
153
|
+
stats_usage,
|
|
154
|
+
meta,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if controller and getattr(controller, "enabled", False):
|
|
158
|
+
controller.poll(renderer)
|
|
159
|
+
finally:
|
|
160
|
+
if controller and getattr(controller, "enabled", False):
|
|
161
|
+
controller.on_stream_complete()
|
|
153
162
|
|
|
154
163
|
finished_monotonic = monotonic()
|
|
155
164
|
return final_text, stats_usage, started_monotonic, finished_monotonic
|
|
@@ -160,14 +169,27 @@ class AgentRunRenderingManager:
|
|
|
160
169
|
meta: dict[str, Any],
|
|
161
170
|
renderer: RichStreamRenderer,
|
|
162
171
|
) -> None:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
172
|
+
"""Capture request ID from response headers and update metadata.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
stream_response: HTTP response stream.
|
|
176
|
+
meta: Metadata dictionary to update.
|
|
177
|
+
renderer: Renderer instance.
|
|
178
|
+
"""
|
|
179
|
+
req_id = stream_response.headers.get("x-request-id") or stream_response.headers.get("x-run-id")
|
|
166
180
|
if req_id:
|
|
167
181
|
meta["run_id"] = req_id
|
|
168
182
|
renderer.on_start(meta)
|
|
169
183
|
|
|
170
184
|
def _maybe_start_timer(self, event: dict[str, Any]) -> float | None:
|
|
185
|
+
"""Start timing if this is a content-bearing event.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
event: Event dictionary.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Monotonic time if timer should start, None otherwise.
|
|
192
|
+
"""
|
|
171
193
|
try:
|
|
172
194
|
ev = json.loads(event["data"])
|
|
173
195
|
except json.JSONDecodeError:
|
|
@@ -185,6 +207,18 @@ class AgentRunRenderingManager:
|
|
|
185
207
|
stats_usage: dict[str, Any],
|
|
186
208
|
meta: dict[str, Any],
|
|
187
209
|
) -> tuple[str, dict[str, Any]]:
|
|
210
|
+
"""Process a single streaming event.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
event: Event dictionary.
|
|
214
|
+
renderer: Renderer instance.
|
|
215
|
+
final_text: Accumulated text so far.
|
|
216
|
+
stats_usage: Usage statistics dictionary.
|
|
217
|
+
meta: Metadata dictionary.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Tuple of (updated_final_text, updated_stats_usage).
|
|
221
|
+
"""
|
|
188
222
|
try:
|
|
189
223
|
ev = json.loads(event["data"])
|
|
190
224
|
except json.JSONDecodeError:
|
|
@@ -194,21 +228,61 @@ class AgentRunRenderingManager:
|
|
|
194
228
|
kind = (ev.get("metadata") or {}).get("kind")
|
|
195
229
|
renderer.on_event(ev)
|
|
196
230
|
|
|
231
|
+
handled = self._handle_metadata_kind(
|
|
232
|
+
kind,
|
|
233
|
+
ev,
|
|
234
|
+
final_text,
|
|
235
|
+
stats_usage,
|
|
236
|
+
meta,
|
|
237
|
+
renderer,
|
|
238
|
+
)
|
|
239
|
+
if handled is not None:
|
|
240
|
+
return handled
|
|
241
|
+
|
|
242
|
+
if ev.get("content"):
|
|
243
|
+
final_text = self._handle_content_event(ev, final_text)
|
|
244
|
+
|
|
245
|
+
return final_text, stats_usage
|
|
246
|
+
|
|
247
|
+
def _handle_metadata_kind(
|
|
248
|
+
self,
|
|
249
|
+
kind: str | None,
|
|
250
|
+
ev: dict[str, Any],
|
|
251
|
+
final_text: str,
|
|
252
|
+
stats_usage: dict[str, Any],
|
|
253
|
+
meta: dict[str, Any],
|
|
254
|
+
renderer: RichStreamRenderer,
|
|
255
|
+
) -> tuple[str, dict[str, Any]] | None:
|
|
256
|
+
"""Process well-known metadata kinds and return updated state."""
|
|
197
257
|
if kind == "artifact":
|
|
198
258
|
return final_text, stats_usage
|
|
199
259
|
|
|
200
|
-
if kind == "final_response"
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
260
|
+
if kind == "final_response":
|
|
261
|
+
content = ev.get("content")
|
|
262
|
+
if content:
|
|
263
|
+
return content, stats_usage
|
|
264
|
+
return final_text, stats_usage
|
|
265
|
+
|
|
266
|
+
if kind == "usage":
|
|
205
267
|
stats_usage.update(ev.get("usage") or {})
|
|
206
|
-
|
|
268
|
+
return final_text, stats_usage
|
|
269
|
+
|
|
270
|
+
if kind == "run_info":
|
|
207
271
|
self._handle_run_info_event(ev, meta, renderer)
|
|
272
|
+
return final_text, stats_usage
|
|
208
273
|
|
|
209
|
-
return
|
|
274
|
+
return None
|
|
210
275
|
|
|
211
276
|
def _handle_content_event(self, ev: dict[str, Any], final_text: str) -> str:
|
|
277
|
+
"""Handle a content event and update final text.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
ev: Event dictionary.
|
|
281
|
+
final_text: Current accumulated text.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
Updated final text.
|
|
285
|
+
"""
|
|
212
286
|
content = ev.get("content", "")
|
|
213
287
|
if not content.startswith("Artifact received:"):
|
|
214
288
|
return content
|
|
@@ -220,6 +294,13 @@ class AgentRunRenderingManager:
|
|
|
220
294
|
meta: dict[str, Any],
|
|
221
295
|
renderer: RichStreamRenderer,
|
|
222
296
|
) -> None:
|
|
297
|
+
"""Handle a run_info event and update metadata.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
ev: Event dictionary.
|
|
301
|
+
meta: Metadata dictionary to update.
|
|
302
|
+
renderer: Renderer instance.
|
|
303
|
+
"""
|
|
223
304
|
if ev.get("model"):
|
|
224
305
|
meta["model"] = ev["model"]
|
|
225
306
|
renderer.on_start(meta)
|
|
@@ -227,6 +308,59 @@ class AgentRunRenderingManager:
|
|
|
227
308
|
meta["run_id"] = ev["run_id"]
|
|
228
309
|
renderer.on_start(meta)
|
|
229
310
|
|
|
311
|
+
def _ensure_renderer_final_content(self, renderer: RichStreamRenderer, text: str) -> None:
|
|
312
|
+
"""Populate renderer state with final output when the stream omits it."""
|
|
313
|
+
if not text:
|
|
314
|
+
return
|
|
315
|
+
|
|
316
|
+
text_value = _coerce_to_string(text)
|
|
317
|
+
state = getattr(renderer, "state", None)
|
|
318
|
+
if state is None:
|
|
319
|
+
self._ensure_renderer_text(renderer, text_value)
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
self._ensure_state_final_text(state, text_value)
|
|
323
|
+
self._ensure_state_buffer(state, text_value)
|
|
324
|
+
|
|
325
|
+
def _ensure_renderer_text(self, renderer: RichStreamRenderer, text_value: str) -> None:
|
|
326
|
+
"""Best-effort assignment for renderer.final_text."""
|
|
327
|
+
if not hasattr(renderer, "final_text"):
|
|
328
|
+
return
|
|
329
|
+
current_text = getattr(renderer, "final_text", "")
|
|
330
|
+
if _has_visible_text(current_text):
|
|
331
|
+
return
|
|
332
|
+
self._safe_set_attr(renderer, "final_text", text_value)
|
|
333
|
+
|
|
334
|
+
def _ensure_state_final_text(self, state: Any, text_value: str) -> None:
|
|
335
|
+
"""Best-effort assignment for renderer.state.final_text."""
|
|
336
|
+
current_text = getattr(state, "final_text", "")
|
|
337
|
+
if _has_visible_text(current_text):
|
|
338
|
+
return
|
|
339
|
+
self._safe_set_attr(state, "final_text", text_value)
|
|
340
|
+
|
|
341
|
+
def _ensure_state_buffer(self, state: Any, text_value: str) -> None:
|
|
342
|
+
"""Append fallback text to the state buffer when available."""
|
|
343
|
+
buffer = getattr(state, "buffer", None)
|
|
344
|
+
if not hasattr(buffer, "append"):
|
|
345
|
+
return
|
|
346
|
+
self._safe_append(buffer.append, text_value)
|
|
347
|
+
|
|
348
|
+
@staticmethod
|
|
349
|
+
def _safe_set_attr(target: Any, attr: str, value: str) -> None:
|
|
350
|
+
"""Assign attribute while masking renderer-specific failures."""
|
|
351
|
+
try:
|
|
352
|
+
setattr(target, attr, value)
|
|
353
|
+
except Exception:
|
|
354
|
+
pass
|
|
355
|
+
|
|
356
|
+
@staticmethod
|
|
357
|
+
def _safe_append(appender: Callable[[str], Any], value: str) -> None:
|
|
358
|
+
"""Invoke append-like functions without leaking renderer errors."""
|
|
359
|
+
try:
|
|
360
|
+
appender(value)
|
|
361
|
+
except Exception:
|
|
362
|
+
pass
|
|
363
|
+
|
|
230
364
|
# --------------------------------------------------------------------- #
|
|
231
365
|
# Finalisation helpers
|
|
232
366
|
# --------------------------------------------------------------------- #
|
|
@@ -250,16 +384,22 @@ class AgentRunRenderingManager:
|
|
|
250
384
|
if hasattr(renderer, "state") and hasattr(renderer.state, "buffer"):
|
|
251
385
|
buffer_values = renderer.state.buffer
|
|
252
386
|
elif hasattr(renderer, "buffer"):
|
|
253
|
-
buffer_values =
|
|
387
|
+
buffer_values = renderer.buffer
|
|
254
388
|
|
|
255
|
-
if buffer_values
|
|
389
|
+
if isinstance(buffer_values, TranscriptBuffer):
|
|
390
|
+
rendered_text = buffer_values.render()
|
|
391
|
+
elif buffer_values is not None:
|
|
256
392
|
try:
|
|
257
393
|
rendered_text = "".join(buffer_values)
|
|
258
394
|
except TypeError:
|
|
259
395
|
rendered_text = ""
|
|
260
396
|
|
|
397
|
+
fallback_text = final_text or rendered_text
|
|
398
|
+
if fallback_text:
|
|
399
|
+
self._ensure_renderer_final_content(renderer, fallback_text)
|
|
400
|
+
|
|
261
401
|
renderer.on_complete(st)
|
|
262
|
-
return final_text or rendered_text or
|
|
402
|
+
return final_text or rendered_text or NO_AGENT_RESPONSE_FALLBACK
|
|
263
403
|
|
|
264
404
|
|
|
265
405
|
def compute_timeout_seconds(kwargs: dict[str, Any]) -> float:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Shared helpers for client configuration wiring.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from glaip_sdk.client.base import BaseClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def build_shared_config(client: BaseClient) -> dict[str, Any]:
|
|
15
|
+
"""Return the keyword arguments used to initialize sub-clients."""
|
|
16
|
+
return {
|
|
17
|
+
"parent_client": client,
|
|
18
|
+
"api_url": client.api_url,
|
|
19
|
+
"api_key": client.api_key,
|
|
20
|
+
"timeout": client._timeout,
|
|
21
|
+
}
|