glaip-sdk 0.0.6a0__py3-none-any.whl → 0.0.8__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/_version.py +42 -19
- glaip_sdk/branding.py +3 -3
- glaip_sdk/cli/commands/agents.py +136 -38
- glaip_sdk/cli/commands/configure.py +2 -2
- glaip_sdk/cli/commands/mcps.py +2 -4
- glaip_sdk/cli/commands/tools.py +2 -4
- glaip_sdk/cli/display.py +15 -15
- glaip_sdk/cli/main.py +51 -5
- glaip_sdk/cli/resolution.py +17 -9
- glaip_sdk/cli/slash/__init__.py +25 -0
- glaip_sdk/cli/slash/agent_session.py +146 -0
- glaip_sdk/cli/slash/prompt.py +198 -0
- glaip_sdk/cli/slash/session.py +665 -0
- glaip_sdk/cli/utils.py +162 -38
- glaip_sdk/client/agents.py +101 -73
- glaip_sdk/client/base.py +45 -14
- glaip_sdk/client/tools.py +44 -26
- glaip_sdk/models.py +1 -0
- glaip_sdk/utils/client_utils.py +95 -71
- glaip_sdk/utils/import_export.py +3 -1
- glaip_sdk/utils/rendering/renderer/base.py +170 -125
- glaip_sdk/utils/serialization.py +52 -16
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.8.dist-info}/METADATA +1 -1
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.8.dist-info}/RECORD +26 -22
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.8.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.0.6a0.dist-info → glaip_sdk-0.0.8.dist-info}/entry_points.txt +0 -0
|
@@ -121,40 +121,68 @@ class RichStreamRenderer:
|
|
|
121
121
|
self.stream_processor.streaming_started_at = self._started_at
|
|
122
122
|
|
|
123
123
|
# Print compact header and user request (parity with old renderer)
|
|
124
|
+
self._render_header(meta)
|
|
125
|
+
self._render_user_query(meta)
|
|
126
|
+
|
|
127
|
+
def _render_header(self, meta: dict[str, Any]) -> None:
|
|
128
|
+
"""Render the agent header with metadata."""
|
|
129
|
+
parts = self._build_header_parts(meta)
|
|
130
|
+
self.header_text = " ".join(parts)
|
|
131
|
+
|
|
132
|
+
if not self.header_text:
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
# Use a rule-like header for readability with fallback
|
|
136
|
+
if not self._render_header_rule():
|
|
137
|
+
self._render_header_fallback()
|
|
138
|
+
|
|
139
|
+
def _build_header_parts(self, meta: dict[str, Any]) -> list[str]:
|
|
140
|
+
"""Build header text parts from metadata."""
|
|
141
|
+
parts: list[str] = ["🤖"]
|
|
142
|
+
agent_name = meta.get("agent_name", "agent")
|
|
143
|
+
if agent_name:
|
|
144
|
+
parts.append(agent_name)
|
|
145
|
+
|
|
146
|
+
model = meta.get("model", "")
|
|
147
|
+
if model:
|
|
148
|
+
parts.extend(["•", model])
|
|
149
|
+
|
|
150
|
+
run_id = meta.get("run_id", "")
|
|
151
|
+
if run_id:
|
|
152
|
+
parts.extend(["•", run_id])
|
|
153
|
+
|
|
154
|
+
return parts
|
|
155
|
+
|
|
156
|
+
def _render_header_rule(self) -> bool:
|
|
157
|
+
"""Render header as a rule. Returns True if successful."""
|
|
124
158
|
try:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if model:
|
|
131
|
-
parts.extend(["•", model])
|
|
132
|
-
run_id = meta.get("run_id", "")
|
|
133
|
-
if run_id:
|
|
134
|
-
parts.extend(["•", run_id])
|
|
135
|
-
self.header_text = " ".join(parts)
|
|
136
|
-
if self.header_text:
|
|
137
|
-
try:
|
|
138
|
-
# Use a rule-like header for readability
|
|
139
|
-
self.console.rule(self.header_text)
|
|
140
|
-
except Exception:
|
|
141
|
-
self.console.print(self.header_text)
|
|
159
|
+
self.console.rule(self.header_text)
|
|
160
|
+
return True
|
|
161
|
+
except Exception: # pragma: no cover - defensive fallback
|
|
162
|
+
logger.exception("Failed to render header rule")
|
|
163
|
+
return False
|
|
142
164
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
self.console.print(
|
|
148
|
-
AIPPanel(
|
|
149
|
-
Markdown(f"**Query:** {query}"),
|
|
150
|
-
title="User Request",
|
|
151
|
-
border_style="yellow",
|
|
152
|
-
padding=(0, 1),
|
|
153
|
-
)
|
|
154
|
-
)
|
|
165
|
+
def _render_header_fallback(self) -> None:
|
|
166
|
+
"""Fallback header rendering."""
|
|
167
|
+
try:
|
|
168
|
+
self.console.print(self.header_text)
|
|
155
169
|
except Exception:
|
|
156
|
-
|
|
157
|
-
|
|
170
|
+
logger.exception("Failed to print header fallback")
|
|
171
|
+
|
|
172
|
+
def _render_user_query(self, meta: dict[str, Any]) -> None:
|
|
173
|
+
"""Render the user query panel."""
|
|
174
|
+
query = meta.get("input_message") or meta.get("query") or meta.get("message")
|
|
175
|
+
if not query:
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
self.console.print(
|
|
179
|
+
AIPPanel(
|
|
180
|
+
Markdown(f"**Query:** {query}"),
|
|
181
|
+
title="User Request",
|
|
182
|
+
border_style="#d97706",
|
|
183
|
+
padding=(0, 1),
|
|
184
|
+
)
|
|
185
|
+
)
|
|
158
186
|
|
|
159
187
|
def on_event(self, ev: dict[str, Any]) -> None:
|
|
160
188
|
"""Handle streaming events from the backend."""
|
|
@@ -230,50 +258,77 @@ class RichStreamRenderer:
|
|
|
230
258
|
# Update live display
|
|
231
259
|
self._ensure_live()
|
|
232
260
|
|
|
261
|
+
def _finish_running_steps(self) -> None:
|
|
262
|
+
"""Mark any running steps as finished to avoid lingering spinners."""
|
|
263
|
+
for st in list(self.steps.by_id.values()):
|
|
264
|
+
if not is_step_finished(st):
|
|
265
|
+
st.finish(None)
|
|
266
|
+
|
|
267
|
+
def _finish_tool_panels(self) -> None:
|
|
268
|
+
"""Mark unfinished tool panels as finished."""
|
|
269
|
+
try:
|
|
270
|
+
items = list(self.tool_panels.items())
|
|
271
|
+
except Exception: # pragma: no cover - defensive guard
|
|
272
|
+
logger.exception("Failed to iterate tool panels during cleanup")
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
for _sid, meta in items:
|
|
276
|
+
if meta.get("status") != "finished":
|
|
277
|
+
meta["status"] = "finished"
|
|
278
|
+
|
|
279
|
+
def _stop_live_display(self) -> None:
|
|
280
|
+
"""Stop live display and clean up."""
|
|
281
|
+
self._shutdown_live()
|
|
282
|
+
|
|
283
|
+
def _print_final_panel_if_needed(self) -> None:
|
|
284
|
+
"""Print final result panel if verbose mode and content available."""
|
|
285
|
+
if self.verbose and not self.state.printed_final_panel:
|
|
286
|
+
body = ("".join(self.state.buffer) or "").strip()
|
|
287
|
+
if body:
|
|
288
|
+
final_panel = create_final_panel(body, theme=self.cfg.theme)
|
|
289
|
+
self.console.print(final_panel)
|
|
290
|
+
self.state.printed_final_panel = True
|
|
291
|
+
|
|
233
292
|
def on_complete(self, _stats: RunStats) -> None:
|
|
234
293
|
"""Handle completion event."""
|
|
235
294
|
self.state.finalizing_ui = True
|
|
236
295
|
|
|
237
296
|
# Mark any running steps as finished to avoid lingering spinners
|
|
238
|
-
|
|
239
|
-
for st in list(self.steps.by_id.values()):
|
|
240
|
-
if not is_step_finished(st):
|
|
241
|
-
st.finish(None)
|
|
242
|
-
except Exception:
|
|
243
|
-
pass
|
|
297
|
+
self._finish_running_steps()
|
|
244
298
|
|
|
245
299
|
# Mark unfinished tool panels as finished
|
|
246
|
-
|
|
247
|
-
for _sid, meta in list(self.tool_panels.items()):
|
|
248
|
-
if meta.get("status") != "finished":
|
|
249
|
-
meta["status"] = "finished"
|
|
250
|
-
except Exception:
|
|
251
|
-
pass
|
|
300
|
+
self._finish_tool_panels()
|
|
252
301
|
|
|
253
302
|
# Final refresh
|
|
254
303
|
self._ensure_live()
|
|
255
304
|
|
|
256
305
|
# Stop live display
|
|
257
|
-
|
|
258
|
-
self.live.stop()
|
|
259
|
-
self.live = None
|
|
306
|
+
self._stop_live_display()
|
|
260
307
|
|
|
261
|
-
#
|
|
262
|
-
|
|
263
|
-
try:
|
|
264
|
-
if self.verbose and not self.state.printed_final_panel:
|
|
265
|
-
body = ("".join(self.state.buffer) or "").strip()
|
|
266
|
-
if body:
|
|
267
|
-
final_panel = create_final_panel(body, theme=self.cfg.theme)
|
|
268
|
-
self.console.print(final_panel)
|
|
269
|
-
self.state.printed_final_panel = True
|
|
270
|
-
except Exception:
|
|
271
|
-
# Non-fatal; renderer best-effort
|
|
272
|
-
pass
|
|
308
|
+
# Print final panel if needed
|
|
309
|
+
self._print_final_panel_if_needed()
|
|
273
310
|
|
|
274
311
|
def _ensure_live(self) -> None:
|
|
275
312
|
"""Ensure live display is updated."""
|
|
276
313
|
# Lazily create Live if needed
|
|
314
|
+
# Rich's Live expects the console to maintain a _live_stack list. When tests
|
|
315
|
+
# or callers provide a lightweight console double (e.g. unittest.mock.Mock),
|
|
316
|
+
# the attribute might be missing or replaced with another type which breaks
|
|
317
|
+
# the background refresh thread. Normal Rich consoles always expose
|
|
318
|
+
# _live_stack as a list, so we defensively initialise it if needed.
|
|
319
|
+
live_stack = getattr(self.console, "_live_stack", None)
|
|
320
|
+
if not isinstance(live_stack, list):
|
|
321
|
+
try:
|
|
322
|
+
self.console._live_stack = [] # type: ignore[attr-defined]
|
|
323
|
+
except Exception:
|
|
324
|
+
# If the console forbids attribute assignment we simply skip the
|
|
325
|
+
# live update for this cycle and fall back to buffered printing.
|
|
326
|
+
logger.debug(
|
|
327
|
+
"Console missing _live_stack; skipping live UI initialisation",
|
|
328
|
+
exc_info=True,
|
|
329
|
+
)
|
|
330
|
+
return
|
|
331
|
+
|
|
277
332
|
if self.live is None and self.cfg.live:
|
|
278
333
|
try:
|
|
279
334
|
self.live = Live(
|
|
@@ -441,22 +496,24 @@ class RichStreamRenderer:
|
|
|
441
496
|
|
|
442
497
|
def _calculate_tool_duration(self, meta: dict[str, Any]) -> float | None:
|
|
443
498
|
"""Calculate tool duration from metadata."""
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
dur = None
|
|
499
|
+
server_now = self.stream_processor.server_elapsed_time
|
|
500
|
+
server_start = meta.get("server_started_at")
|
|
501
|
+
dur = None
|
|
448
502
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
):
|
|
503
|
+
try:
|
|
504
|
+
if isinstance(server_now, (int, float)) and server_start is not None:
|
|
452
505
|
dur = max(0.0, float(server_now) - float(server_start))
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
506
|
+
else:
|
|
507
|
+
started_at = meta.get("started_at")
|
|
508
|
+
if started_at is not None:
|
|
509
|
+
started_at_float = float(started_at)
|
|
510
|
+
dur = max(0.0, float(monotonic()) - started_at_float)
|
|
511
|
+
except (TypeError, ValueError):
|
|
512
|
+
logger.exception("Failed to calculate tool duration")
|
|
458
513
|
return None
|
|
459
514
|
|
|
515
|
+
return dur
|
|
516
|
+
|
|
460
517
|
def _update_tool_metadata(self, meta: dict[str, Any], dur: float | None) -> None:
|
|
461
518
|
"""Update tool metadata with duration information."""
|
|
462
519
|
if dur is not None:
|
|
@@ -510,10 +567,7 @@ class RichStreamRenderer:
|
|
|
510
567
|
) -> float | None:
|
|
511
568
|
"""Get step duration from tool panels."""
|
|
512
569
|
tool_sid = f"tool_{finished_tool_name}_{task_id}_{context_id}"
|
|
513
|
-
|
|
514
|
-
return self.tool_panels.get(tool_sid, {}).get("duration_seconds")
|
|
515
|
-
except Exception:
|
|
516
|
-
return None
|
|
570
|
+
return self.tool_panels.get(tool_sid, {}).get("duration_seconds")
|
|
517
571
|
|
|
518
572
|
def _finish_delegation_step(
|
|
519
573
|
self,
|
|
@@ -647,27 +701,23 @@ class RichStreamRenderer:
|
|
|
647
701
|
self, finished_tool_name: str, task_id: str, context_id: str
|
|
648
702
|
) -> None:
|
|
649
703
|
"""Create and print a snapshot for a finished tool."""
|
|
650
|
-
|
|
651
|
-
tool_sid = f"tool_{finished_tool_name}_{task_id}_{context_id}"
|
|
652
|
-
|
|
653
|
-
if not self._should_create_snapshot(tool_sid):
|
|
654
|
-
return
|
|
704
|
+
tool_sid = f"tool_{finished_tool_name}_{task_id}_{context_id}"
|
|
655
705
|
|
|
656
|
-
|
|
657
|
-
|
|
706
|
+
if not self._should_create_snapshot(tool_sid):
|
|
707
|
+
return
|
|
658
708
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
body_text = self._clamp_snapshot_body(body_text)
|
|
709
|
+
meta = self.tool_panels[tool_sid]
|
|
710
|
+
adjusted_title = self._get_snapshot_title(meta, finished_tool_name)
|
|
662
711
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
712
|
+
# Compose body from chunks and clamp
|
|
713
|
+
body_text = "".join(meta.get("chunks") or [])
|
|
714
|
+
body_text = self._clamp_snapshot_body(body_text)
|
|
666
715
|
|
|
667
|
-
|
|
716
|
+
snapshot_panel = self._create_snapshot_panel(
|
|
717
|
+
adjusted_title, body_text, finished_tool_name
|
|
718
|
+
)
|
|
668
719
|
|
|
669
|
-
|
|
670
|
-
pass
|
|
720
|
+
self._print_and_mark_snapshot(tool_sid, snapshot_panel)
|
|
671
721
|
|
|
672
722
|
def _handle_agent_step(
|
|
673
723
|
self,
|
|
@@ -725,21 +775,30 @@ class RichStreamRenderer:
|
|
|
725
775
|
|
|
726
776
|
def close(self) -> None:
|
|
727
777
|
"""Gracefully stop any live rendering and release resources."""
|
|
778
|
+
self._shutdown_live()
|
|
779
|
+
|
|
780
|
+
def __del__(self) -> None:
|
|
781
|
+
# Destructors must never raise
|
|
728
782
|
try:
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
self.live.stop()
|
|
732
|
-
finally:
|
|
733
|
-
self.live = None
|
|
734
|
-
except Exception:
|
|
783
|
+
self._shutdown_live(reset_attr=False)
|
|
784
|
+
except Exception: # pragma: no cover - destructor safety net
|
|
735
785
|
pass
|
|
736
786
|
|
|
737
|
-
def
|
|
787
|
+
def _shutdown_live(self, reset_attr: bool = True) -> None:
|
|
788
|
+
"""Stop the live renderer without letting exceptions escape."""
|
|
789
|
+
live = getattr(self, "live", None)
|
|
790
|
+
if not live:
|
|
791
|
+
if reset_attr and not hasattr(self, "live"):
|
|
792
|
+
self.live = None
|
|
793
|
+
return
|
|
794
|
+
|
|
738
795
|
try:
|
|
739
|
-
|
|
740
|
-
self.live.stop()
|
|
796
|
+
live.stop()
|
|
741
797
|
except Exception:
|
|
742
|
-
|
|
798
|
+
logger.exception("Failed to stop live display")
|
|
799
|
+
finally:
|
|
800
|
+
if reset_attr:
|
|
801
|
+
self.live = None
|
|
743
802
|
|
|
744
803
|
def _get_analysis_progress_info(self) -> dict[str, Any]:
|
|
745
804
|
total_steps = len(self.steps.order)
|
|
@@ -754,15 +813,9 @@ class RichStreamRenderer:
|
|
|
754
813
|
# Prefer server elapsed time when available
|
|
755
814
|
elapsed = 0.0
|
|
756
815
|
if isinstance(self.stream_processor.server_elapsed_time, int | float):
|
|
757
|
-
|
|
758
|
-
elapsed = float(self.stream_processor.server_elapsed_time)
|
|
759
|
-
except Exception:
|
|
760
|
-
elapsed = 0.0
|
|
816
|
+
elapsed = float(self.stream_processor.server_elapsed_time)
|
|
761
817
|
elif self._started_at is not None:
|
|
762
|
-
|
|
763
|
-
elapsed = monotonic() - self._started_at
|
|
764
|
-
except Exception:
|
|
765
|
-
elapsed = 0.0
|
|
818
|
+
elapsed = monotonic() - self._started_at
|
|
766
819
|
progress_percent = (
|
|
767
820
|
int((completed_steps / total_steps) * 100) if total_steps else 0
|
|
768
821
|
)
|
|
@@ -913,10 +966,7 @@ class RichStreamRenderer:
|
|
|
913
966
|
):
|
|
914
967
|
elapsed = max(0.0, float(server_elapsed) - float(server_start))
|
|
915
968
|
else:
|
|
916
|
-
|
|
917
|
-
elapsed = max(0.0, monotonic() - (meta.get("started_at") or 0.0))
|
|
918
|
-
except Exception:
|
|
919
|
-
elapsed = 0.0
|
|
969
|
+
elapsed = max(0.0, monotonic() - (meta.get("started_at") or 0.0))
|
|
920
970
|
|
|
921
971
|
return self._format_elapsed_time(elapsed)
|
|
922
972
|
|
|
@@ -1025,17 +1075,14 @@ class RichStreamRenderer:
|
|
|
1025
1075
|
if not (tool_name and is_delegation_tool(tool_name)):
|
|
1026
1076
|
return output
|
|
1027
1077
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
return output[len(prefix) :].lstrip()
|
|
1037
|
-
except Exception:
|
|
1038
|
-
pass
|
|
1078
|
+
sub = tool_name
|
|
1079
|
+
if tool_name.startswith("delegate_to_"):
|
|
1080
|
+
sub = tool_name.replace("delegate_to_", "")
|
|
1081
|
+
elif tool_name.startswith("delegate_"):
|
|
1082
|
+
sub = tool_name.replace("delegate_", "")
|
|
1083
|
+
prefix = f"[{sub}]"
|
|
1084
|
+
if output.startswith(prefix):
|
|
1085
|
+
return output[len(prefix) :].lstrip()
|
|
1039
1086
|
|
|
1040
1087
|
return output
|
|
1041
1088
|
|
|
@@ -1080,5 +1127,3 @@ class RichStreamRenderer:
|
|
|
1080
1127
|
return self._format_string_output(output_value, tool_name)
|
|
1081
1128
|
else:
|
|
1082
1129
|
return self._format_other_output(output_value)
|
|
1083
|
-
|
|
1084
|
-
# No legacy surface helpers are exposed; use modern interfaces only
|
glaip_sdk/utils/serialization.py
CHANGED
|
@@ -8,7 +8,7 @@ Authors:
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
-
from collections.abc import Iterable
|
|
11
|
+
from collections.abc import Callable, Iterable
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Any
|
|
14
14
|
|
|
@@ -184,7 +184,9 @@ def collect_attributes_for_export(resource: Any) -> dict[str, Any]:
|
|
|
184
184
|
"""
|
|
185
185
|
|
|
186
186
|
mapping = _coerce_resource_to_mapping(resource)
|
|
187
|
-
if
|
|
187
|
+
if (
|
|
188
|
+
mapping is None
|
|
189
|
+
): # pragma: no cover - defensive fallback when attribute introspection fails
|
|
188
190
|
items = (
|
|
189
191
|
(name, _safe_getattr(resource, name))
|
|
190
192
|
for name in _iter_public_attribute_names(resource)
|
|
@@ -215,11 +217,13 @@ def _coerce_resource_to_mapping(resource: Any) -> dict[str, Any] | None:
|
|
|
215
217
|
if isinstance(resource, dict):
|
|
216
218
|
return resource
|
|
217
219
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
+
try:
|
|
221
|
+
if hasattr(resource, "__dict__"):
|
|
220
222
|
return dict(resource.__dict__)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
+
except (
|
|
224
|
+
Exception
|
|
225
|
+
): # pragma: no cover - pathological objects can still defeat coercion
|
|
226
|
+
return None
|
|
223
227
|
|
|
224
228
|
return None
|
|
225
229
|
|
|
@@ -231,27 +235,59 @@ def _iter_public_attribute_names(resource: Any) -> Iterable[str]:
|
|
|
231
235
|
names: list[str] = []
|
|
232
236
|
|
|
233
237
|
def _collect(candidates: Iterable[str] | None) -> None:
|
|
234
|
-
|
|
235
|
-
return
|
|
236
|
-
for candidate in candidates:
|
|
238
|
+
for candidate in candidates or ():
|
|
237
239
|
if candidate not in seen:
|
|
238
240
|
seen.add(candidate)
|
|
239
241
|
names.append(candidate)
|
|
240
242
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
)
|
|
246
|
-
|
|
243
|
+
# Collect from __dict__
|
|
244
|
+
_collect_from_dict(resource, _collect)
|
|
245
|
+
|
|
246
|
+
# Collect from __annotations__
|
|
247
|
+
_collect_from_annotations(resource, _collect)
|
|
248
|
+
|
|
249
|
+
# Collect from __slots__
|
|
247
250
|
_collect(getattr(resource, "__slots__", ()))
|
|
248
251
|
|
|
252
|
+
# Fallback to dir() if no names found
|
|
249
253
|
if not names:
|
|
250
|
-
|
|
254
|
+
_collect_from_dir(resource, _collect)
|
|
251
255
|
|
|
252
256
|
return iter(names)
|
|
253
257
|
|
|
254
258
|
|
|
259
|
+
def _collect_from_dict(
|
|
260
|
+
resource: Any, collect_func: Callable[[Iterable[str]], None]
|
|
261
|
+
) -> None:
|
|
262
|
+
"""Safely collect attribute names from __dict__."""
|
|
263
|
+
try:
|
|
264
|
+
if hasattr(resource, "__dict__"):
|
|
265
|
+
dict_keys = getattr(resource, "__dict__", {})
|
|
266
|
+
if dict_keys:
|
|
267
|
+
collect_func(dict_keys.keys())
|
|
268
|
+
except Exception: # pragma: no cover - defensive programming
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _collect_from_annotations(
|
|
273
|
+
resource: Any, collect_func: Callable[[Iterable[str]], None]
|
|
274
|
+
) -> None:
|
|
275
|
+
"""Safely collect attribute names from __annotations__."""
|
|
276
|
+
annotations = getattr(resource, "__annotations__", {})
|
|
277
|
+
if annotations:
|
|
278
|
+
collect_func(annotations.keys())
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _collect_from_dir(
|
|
282
|
+
resource: Any, collect_func: Callable[[Iterable[str]], None]
|
|
283
|
+
) -> None:
|
|
284
|
+
"""Safely collect attribute names from dir()."""
|
|
285
|
+
try:
|
|
286
|
+
collect_func(name for name in dir(resource) if not name.startswith("__"))
|
|
287
|
+
except Exception: # pragma: no cover - defensive programming
|
|
288
|
+
pass
|
|
289
|
+
|
|
290
|
+
|
|
255
291
|
def _safe_getattr(resource: Any, name: str) -> Any:
|
|
256
292
|
try:
|
|
257
293
|
return getattr(resource, name)
|
|
@@ -1,42 +1,46 @@
|
|
|
1
1
|
glaip_sdk/__init__.py,sha256=FD-oTyFUKsTB9xTuGiqvkhuFXfeZ-TspjkeXERglha8,370
|
|
2
|
-
glaip_sdk/_version.py,sha256=
|
|
3
|
-
glaip_sdk/branding.py,sha256=
|
|
2
|
+
glaip_sdk/_version.py,sha256=tGkFWAVu2ry4Hy7j-u7ophGbPRX8y-ngBbXDhN1VBIQ,2007
|
|
3
|
+
glaip_sdk/branding.py,sha256=_TiQtiwH3ZSWaQhooWPHioriL0goTiYANeN6DT8lQX8,5398
|
|
4
4
|
glaip_sdk/cli/__init__.py,sha256=xCCfuF1Yc7mpCDcfhHZTX0vizvtrDSLeT8MJ3V7m5A0,156
|
|
5
5
|
glaip_sdk/cli/agent_config.py,sha256=VHjebw68wAdhGUzYdPH8qz10oADZPRgUQcPW6F7iHIU,2421
|
|
6
6
|
glaip_sdk/cli/commands/__init__.py,sha256=x0CZlZbZHoHvuzfoTWIyEch6WmNnbPzxajrox6riYp0,173
|
|
7
|
-
glaip_sdk/cli/commands/agents.py,sha256=
|
|
8
|
-
glaip_sdk/cli/commands/configure.py,sha256=
|
|
9
|
-
glaip_sdk/cli/commands/mcps.py,sha256=
|
|
7
|
+
glaip_sdk/cli/commands/agents.py,sha256=1xGSoH6C9hSaGglXf4pnloqX5gJQIPsgHhkliiWQQcY,39988
|
|
8
|
+
glaip_sdk/cli/commands/configure.py,sha256=eRDzsaKV4fl2lJt8ieS4g2-xRnaa02eAAPW8xBf-tqA,7507
|
|
9
|
+
glaip_sdk/cli/commands/mcps.py,sha256=ZfmFkisXHHqgFH6WU7W5qPvfdt5Dxd5ZFZb_Ml3POoQ,12794
|
|
10
10
|
glaip_sdk/cli/commands/models.py,sha256=lHEVuXT8Sq239C_2LneV8PimVZSm9DXJKajdSVO-N50,1496
|
|
11
|
-
glaip_sdk/cli/commands/tools.py,sha256=
|
|
12
|
-
glaip_sdk/cli/display.py,sha256=
|
|
11
|
+
glaip_sdk/cli/commands/tools.py,sha256=Xm_qCe0h2EqhbqNuKTBvow1HMc7MbLYx6j92A6rLwu0,16743
|
|
12
|
+
glaip_sdk/cli/display.py,sha256=jE20swoRKzpYUmc0jgbeonaXKeE9x95hfjWAEdnBYRc,8727
|
|
13
13
|
glaip_sdk/cli/io.py,sha256=GPkw3pQMLBGoD5GH-KlbKpNRlVWFZOXHE17F7V3kQsI,3343
|
|
14
|
-
glaip_sdk/cli/main.py,sha256=
|
|
15
|
-
glaip_sdk/cli/resolution.py,sha256=
|
|
16
|
-
glaip_sdk/cli/
|
|
14
|
+
glaip_sdk/cli/main.py,sha256=1RSR3YmJECnpErD_y9NXqCHjyho3JkYkVc26J6NAbzE,12694
|
|
15
|
+
glaip_sdk/cli/resolution.py,sha256=BOw2NchReLKewAwBAZLWw_3_bI7u3tfzQEO7kQbIiGE,2067
|
|
16
|
+
glaip_sdk/cli/slash/__init__.py,sha256=Vdv6Y8bu-pA8dxDlyP4XrhudBPivztUozhLAz9vaLig,682
|
|
17
|
+
glaip_sdk/cli/slash/agent_session.py,sha256=JFIFBxB4xzigqHtpLGbl2fgg7RHNwy3e-kUMPMK9MdM,5006
|
|
18
|
+
glaip_sdk/cli/slash/prompt.py,sha256=QFWYgNt5AhBRYGGyUkH30ToZE7B6LS-eZGzoyibYrK8,6064
|
|
19
|
+
glaip_sdk/cli/slash/session.py,sha256=GtnnBqV79KtFJHeLfCKKnCXJ6SU1AmeXquPjy72T20E,24215
|
|
20
|
+
glaip_sdk/cli/utils.py,sha256=Jhjv9ggwZGQ8oJZGIPIpOc29LqSZAks9FLVWtTpklYU,40629
|
|
17
21
|
glaip_sdk/cli/validators.py,sha256=USbBgY86AwuDHO-Q_g8g7hu-ot4NgITBsWjTWIl62ms,5569
|
|
18
22
|
glaip_sdk/client/__init__.py,sha256=nYLXfBVTTWwKjP0e63iumPYO4k5FifwWaELQPaPIKIg,188
|
|
19
|
-
glaip_sdk/client/agents.py,sha256=
|
|
20
|
-
glaip_sdk/client/base.py,sha256=
|
|
23
|
+
glaip_sdk/client/agents.py,sha256=FSKubF40wptMNIheC3_iawiX2CRbhTcNLFiz4qkPC6k,34659
|
|
24
|
+
glaip_sdk/client/base.py,sha256=O3dv3I7PqY91gH1FehBMRZcSXjwimfeBcJuiXidDmqw,13700
|
|
21
25
|
glaip_sdk/client/main.py,sha256=LlvYHP7-Hy7Eq1ep1kfk337K-Oue5SdKWJpqYfX9eXY,7993
|
|
22
26
|
glaip_sdk/client/mcps.py,sha256=yxwrAtztElYDEGhp2EHRpeYUxNsOlTLTqtw9jSKJmcI,8936
|
|
23
|
-
glaip_sdk/client/tools.py,sha256=
|
|
27
|
+
glaip_sdk/client/tools.py,sha256=n8DIiOOf1YU_j9JK3Bx2-rDnkpckPi0MI9Ok2s1kwa4,16634
|
|
24
28
|
glaip_sdk/client/validators.py,sha256=NtPsWjQLjj25LiUnmR-WuS8lL5p4MVRaYT9UVRmj9bo,8809
|
|
25
29
|
glaip_sdk/config/constants.py,sha256=NgmPqJmpK1wgEds7T-_B6CDUBsvcsmIy27ms-Z8GFgY,902
|
|
26
30
|
glaip_sdk/exceptions.py,sha256=QTVtwxRHMN4e8gGn0icXphZvdugiRvcSrlMYylwGsDc,1993
|
|
27
|
-
glaip_sdk/models.py,sha256=
|
|
31
|
+
glaip_sdk/models.py,sha256=Ry_Ihd6FuC0JGb0Obd5T3A22AOp2r9xStQisfE8uo8c,8822
|
|
28
32
|
glaip_sdk/rich_components.py,sha256=pmJd-81OQE8bC9UOXtga5rsax4zphKlzCZ1JoWbbQzQ,803
|
|
29
33
|
glaip_sdk/utils/__init__.py,sha256=fmVGcUFa7G0CCfSMSqfNU2BqFl36G1gOFyDfTvtJfVw,926
|
|
30
34
|
glaip_sdk/utils/agent_config.py,sha256=b7_J5DELyk0b_XEoi7tsxbS3wqzAKbMa-3_C-65pPIY,6791
|
|
31
|
-
glaip_sdk/utils/client_utils.py,sha256=
|
|
35
|
+
glaip_sdk/utils/client_utils.py,sha256=M6rZloMKyONaZfI0RtU5tnkibwrIJL5Udw4wPMKkJcw,13588
|
|
32
36
|
glaip_sdk/utils/display.py,sha256=94s9lYF_8ra8jpeqOkbVrUm8oidtCE6OtucyxLQPKmU,3105
|
|
33
37
|
glaip_sdk/utils/general.py,sha256=V5hJrIpYDvDsldU_nChHpuvV2AwhFLUI7Qvcaihq_8A,2270
|
|
34
|
-
glaip_sdk/utils/import_export.py,sha256=
|
|
38
|
+
glaip_sdk/utils/import_export.py,sha256=Wxt2QuWI7JexSkkcBOdTgeYs1nly35yppaTNeF28XJo,5400
|
|
35
39
|
glaip_sdk/utils/rendering/__init__.py,sha256=vXjwk5rPhhfPyD8S0DnV4GFFEtPJp4HCCg1Um9SXfs0,70
|
|
36
40
|
glaip_sdk/utils/rendering/formatting.py,sha256=_k8tkcobctmHvdygMljZF7-ALGXpD9-hHF1CNtM2KMU,7201
|
|
37
41
|
glaip_sdk/utils/rendering/models.py,sha256=SS34_00FaoGuSYn-viBkAtIbq7cJNwwPjpxnvyeUmxI,1567
|
|
38
42
|
glaip_sdk/utils/rendering/renderer/__init__.py,sha256=EXwVBmGkSYcype4ocAXo69Z1kXu0gpNXmhH5LW0_B7A,2939
|
|
39
|
-
glaip_sdk/utils/rendering/renderer/base.py,sha256=
|
|
43
|
+
glaip_sdk/utils/rendering/renderer/base.py,sha256=OqRBfdE1cwYhaB-1wXwc4pyGaagnX2duistDOIaVsD0,40969
|
|
40
44
|
glaip_sdk/utils/rendering/renderer/config.py,sha256=E4ER8TJJbqr1hcWjkwG7XROqLuccQy4EL99CbuLvSXE,783
|
|
41
45
|
glaip_sdk/utils/rendering/renderer/console.py,sha256=4cLOw4Q1fkHkApuj6dWW8eYpeYdcT0t2SO5MbVt5UTc,1844
|
|
42
46
|
glaip_sdk/utils/rendering/renderer/debug.py,sha256=FEYxAu4ZB0CjrJKevqQ2TKDgElA2cf6GqZXCNm12sNQ,3721
|
|
@@ -47,9 +51,9 @@ glaip_sdk/utils/rendering/steps.py,sha256=4zdeyKxMbUzCal4-yv8yf18144cs5wwXaxhe6m
|
|
|
47
51
|
glaip_sdk/utils/resource_refs.py,sha256=0YzblJNfRhz9xhpaKE9aE68XEV-6_ssr0fIkiMVOka0,5489
|
|
48
52
|
glaip_sdk/utils/rich_utils.py,sha256=-Ij-1bIJvnVAi6DrfftchIlMcvOTjVmSE0Qqax0EY_s,763
|
|
49
53
|
glaip_sdk/utils/run_renderer.py,sha256=d_VMI6LbvHPUUeRmGqh5wK_lHqDEIAcym2iqpbtDad0,1365
|
|
50
|
-
glaip_sdk/utils/serialization.py,sha256=
|
|
54
|
+
glaip_sdk/utils/serialization.py,sha256=cUE6PxqTsfJuEEmsk_Li3QmaDavTIPotEA-BQ-v5exY,9043
|
|
51
55
|
glaip_sdk/utils/validation.py,sha256=QNORcdyvuliEs4EH2_mkDgmoyT9utgl7YNhaf45SEf8,6992
|
|
52
|
-
glaip_sdk-0.0.
|
|
53
|
-
glaip_sdk-0.0.
|
|
54
|
-
glaip_sdk-0.0.
|
|
55
|
-
glaip_sdk-0.0.
|
|
56
|
+
glaip_sdk-0.0.8.dist-info/METADATA,sha256=yWuZjBH9LvHlgsGZ8NP8GsUpsAM2X2ScE9uNCDnRPls,4942
|
|
57
|
+
glaip_sdk-0.0.8.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
58
|
+
glaip_sdk-0.0.8.dist-info/entry_points.txt,sha256=EGs8NO8J1fdFMWA3CsF7sKBEvtHb_fujdCoNPhfMouE,47
|
|
59
|
+
glaip_sdk-0.0.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|