glaip-sdk 0.1.0__py3-none-any.whl → 0.1.1__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 +1 -3
- glaip_sdk/branding.py +2 -6
- glaip_sdk/cli/agent_config.py +2 -6
- glaip_sdk/cli/auth.py +11 -30
- glaip_sdk/cli/commands/agents.py +45 -107
- glaip_sdk/cli/commands/configure.py +12 -36
- glaip_sdk/cli/commands/mcps.py +26 -63
- glaip_sdk/cli/commands/models.py +2 -4
- glaip_sdk/cli/commands/tools.py +22 -35
- glaip_sdk/cli/commands/update.py +3 -8
- glaip_sdk/cli/config.py +1 -3
- glaip_sdk/cli/display.py +4 -12
- glaip_sdk/cli/io.py +8 -14
- glaip_sdk/cli/main.py +10 -30
- glaip_sdk/cli/mcp_validators.py +5 -15
- glaip_sdk/cli/pager.py +3 -9
- 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/agent_session.py +5 -10
- glaip_sdk/cli/slash/prompt.py +3 -10
- glaip_sdk/cli/slash/session.py +46 -95
- glaip_sdk/cli/transcript/cache.py +6 -19
- glaip_sdk/cli/transcript/capture.py +6 -20
- glaip_sdk/cli/transcript/launcher.py +1 -3
- glaip_sdk/cli/transcript/viewer.py +11 -40
- glaip_sdk/cli/update_notifier.py +165 -21
- glaip_sdk/cli/utils.py +33 -84
- glaip_sdk/cli/validators.py +11 -12
- glaip_sdk/client/_agent_payloads.py +10 -30
- glaip_sdk/client/agents.py +33 -63
- glaip_sdk/client/base.py +6 -22
- glaip_sdk/client/mcps.py +1 -3
- glaip_sdk/client/run_rendering.py +6 -14
- glaip_sdk/client/tools.py +8 -24
- glaip_sdk/client/validators.py +20 -48
- glaip_sdk/exceptions.py +1 -3
- glaip_sdk/models.py +14 -33
- glaip_sdk/payload_schemas/agent.py +1 -3
- glaip_sdk/utils/agent_config.py +4 -14
- glaip_sdk/utils/client_utils.py +7 -21
- glaip_sdk/utils/display.py +2 -6
- glaip_sdk/utils/general.py +1 -3
- glaip_sdk/utils/import_export.py +3 -9
- glaip_sdk/utils/rendering/formatting.py +2 -5
- glaip_sdk/utils/rendering/models.py +2 -6
- glaip_sdk/utils/rendering/renderer/__init__.py +1 -3
- glaip_sdk/utils/rendering/renderer/base.py +63 -189
- glaip_sdk/utils/rendering/renderer/debug.py +4 -14
- glaip_sdk/utils/rendering/renderer/panels.py +1 -3
- glaip_sdk/utils/rendering/renderer/progress.py +3 -11
- glaip_sdk/utils/rendering/renderer/stream.py +7 -19
- glaip_sdk/utils/rendering/renderer/toggle.py +1 -3
- glaip_sdk/utils/rendering/step_tree_state.py +1 -3
- glaip_sdk/utils/rendering/steps.py +29 -83
- glaip_sdk/utils/resource_refs.py +4 -13
- glaip_sdk/utils/serialization.py +14 -46
- glaip_sdk/utils/validation.py +4 -4
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.1.1.dist-info}/METADATA +1 -1
- glaip_sdk-0.1.1.dist-info/RECORD +82 -0
- glaip_sdk-0.1.0.dist-info/RECORD +0 -82
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.1.1.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.1.1.dist-info}/entry_points.txt +0 -0
glaip_sdk/client/agents.py
CHANGED
|
@@ -34,7 +34,7 @@ from glaip_sdk.config.constants import (
|
|
|
34
34
|
DEFAULT_AGENT_VERSION,
|
|
35
35
|
DEFAULT_MODEL,
|
|
36
36
|
)
|
|
37
|
-
from glaip_sdk.exceptions import NotFoundError
|
|
37
|
+
from glaip_sdk.exceptions import NotFoundError, ValidationError
|
|
38
38
|
from glaip_sdk.models import Agent
|
|
39
39
|
from glaip_sdk.payload_schemas.agent import list_server_only_fields
|
|
40
40
|
from glaip_sdk.utils.agent_config import normalize_agent_config_for_import
|
|
@@ -97,9 +97,7 @@ def _merge_override_maps(
|
|
|
97
97
|
for key, value in source.items():
|
|
98
98
|
if value is None:
|
|
99
99
|
continue
|
|
100
|
-
merged[key] = (
|
|
101
|
-
_normalise_sequence(value) if key in _MERGED_SEQUENCE_FIELDS else value
|
|
102
|
-
)
|
|
100
|
+
merged[key] = _normalise_sequence(value) if key in _MERGED_SEQUENCE_FIELDS else value
|
|
103
101
|
return merged
|
|
104
102
|
|
|
105
103
|
|
|
@@ -134,9 +132,7 @@ def _prepare_agent_metadata(value: Any) -> dict[str, Any]:
|
|
|
134
132
|
return prepared
|
|
135
133
|
|
|
136
134
|
|
|
137
|
-
def _load_agent_file_payload(
|
|
138
|
-
file_path: Path, *, model_override: str | None
|
|
139
|
-
) -> dict[str, Any]:
|
|
135
|
+
def _load_agent_file_payload(file_path: Path, *, model_override: str | None) -> dict[str, Any]:
|
|
140
136
|
"""Load agent configuration from disk and normalise legacy fields."""
|
|
141
137
|
if not file_path.exists():
|
|
142
138
|
raise FileNotFoundError(f"Agent configuration file not found: {file_path}")
|
|
@@ -168,9 +164,7 @@ def _prepare_import_payload(
|
|
|
168
164
|
raw_definition = load_resource_from_file(file_path)
|
|
169
165
|
original_refs = _extract_original_refs(raw_definition)
|
|
170
166
|
|
|
171
|
-
base_payload = _load_agent_file_payload(
|
|
172
|
-
file_path, model_override=overrides_dict.get("model")
|
|
173
|
-
)
|
|
167
|
+
base_payload = _load_agent_file_payload(file_path, model_override=overrides_dict.get("model"))
|
|
174
168
|
|
|
175
169
|
cli_args = _build_cli_args(overrides_dict)
|
|
176
170
|
|
|
@@ -223,11 +217,7 @@ def _build_cli_args(overrides_dict: dict) -> dict[str, Any]:
|
|
|
223
217
|
|
|
224
218
|
def _build_additional_args(overrides_dict: dict, cli_args: dict) -> dict[str, Any]:
|
|
225
219
|
"""Build additional args not already in CLI args."""
|
|
226
|
-
return {
|
|
227
|
-
key: value
|
|
228
|
-
for key, value in overrides_dict.items()
|
|
229
|
-
if value is not None and key not in cli_args
|
|
230
|
-
}
|
|
220
|
+
return {key: value for key, value in overrides_dict.items() if value is not None and key not in cli_args}
|
|
231
221
|
|
|
232
222
|
|
|
233
223
|
def _remove_model_fields_if_needed(merged: dict, overrides_dict: dict) -> None:
|
|
@@ -278,9 +268,7 @@ class AgentClient(BaseClient):
|
|
|
278
268
|
"""
|
|
279
269
|
if query is not None and kwargs:
|
|
280
270
|
# Both query object and individual parameters provided
|
|
281
|
-
raise ValueError(
|
|
282
|
-
"Provide either `query` or individual filter arguments, not both."
|
|
283
|
-
)
|
|
271
|
+
raise ValueError("Provide either `query` or individual filter arguments, not both.")
|
|
284
272
|
|
|
285
273
|
if query is None:
|
|
286
274
|
# Create query from individual parameters for backward compatibility
|
|
@@ -339,7 +327,19 @@ class AgentClient(BaseClient):
|
|
|
339
327
|
|
|
340
328
|
def get_agent_by_id(self, agent_id: str) -> Agent:
|
|
341
329
|
"""Get agent by ID."""
|
|
342
|
-
|
|
330
|
+
try:
|
|
331
|
+
data = self._request("GET", f"/agents/{agent_id}")
|
|
332
|
+
except ValidationError as exc:
|
|
333
|
+
if exc.status_code == 422:
|
|
334
|
+
message = f"Agent '{agent_id}' not found"
|
|
335
|
+
raise NotFoundError(
|
|
336
|
+
message,
|
|
337
|
+
status_code=404,
|
|
338
|
+
error_type=exc.error_type,
|
|
339
|
+
payload=exc.payload,
|
|
340
|
+
request_id=exc.request_id,
|
|
341
|
+
) from exc
|
|
342
|
+
raise
|
|
343
343
|
|
|
344
344
|
if isinstance(data, str):
|
|
345
345
|
# Some backends may respond with plain text for missing agents.
|
|
@@ -372,9 +372,7 @@ class AgentClient(BaseClient):
|
|
|
372
372
|
self._renderer_manager = manager
|
|
373
373
|
return manager
|
|
374
374
|
|
|
375
|
-
def _create_renderer(
|
|
376
|
-
self, renderer: RichStreamRenderer | str | None, **kwargs: Any
|
|
377
|
-
) -> RichStreamRenderer:
|
|
375
|
+
def _create_renderer(self, renderer: RichStreamRenderer | str | None, **kwargs: Any) -> RichStreamRenderer:
|
|
378
376
|
manager = self._get_renderer_manager()
|
|
379
377
|
verbose = kwargs.get("verbose", False)
|
|
380
378
|
if isinstance(renderer, RichStreamRenderer) or hasattr(renderer, "on_start"):
|
|
@@ -506,9 +504,7 @@ class AgentClient(BaseClient):
|
|
|
506
504
|
return entry_id
|
|
507
505
|
|
|
508
506
|
if entry_name:
|
|
509
|
-
resolved, success = self._resolve_resource_by_name(
|
|
510
|
-
find_by_name, entry_name, singular, plural
|
|
511
|
-
)
|
|
507
|
+
resolved, success = self._resolve_resource_by_name(find_by_name, entry_name, singular, plural)
|
|
512
508
|
return resolved if success else entry_name
|
|
513
509
|
|
|
514
510
|
raise ValueError(f"{singular} references must include a valid ID or name.")
|
|
@@ -523,9 +519,7 @@ class AgentClient(BaseClient):
|
|
|
523
519
|
return str(entry)
|
|
524
520
|
|
|
525
521
|
@staticmethod
|
|
526
|
-
def _validate_resource_id(
|
|
527
|
-
fetch_by_id: Callable[[str], Any], candidate_id: str | None
|
|
528
|
-
) -> str | None:
|
|
522
|
+
def _validate_resource_id(fetch_by_id: Callable[[str], Any], candidate_id: str | None) -> str | None:
|
|
529
523
|
if not candidate_id:
|
|
530
524
|
return None
|
|
531
525
|
try:
|
|
@@ -547,21 +541,13 @@ class AgentClient(BaseClient):
|
|
|
547
541
|
return entry_name, False
|
|
548
542
|
|
|
549
543
|
if not matches:
|
|
550
|
-
raise ValueError(
|
|
551
|
-
f"{singular} '{entry_name}' not found in current workspace."
|
|
552
|
-
)
|
|
544
|
+
raise ValueError(f"{singular} '{entry_name}' not found in current workspace.")
|
|
553
545
|
if len(matches) > 1:
|
|
554
|
-
exact = [
|
|
555
|
-
m
|
|
556
|
-
for m in matches
|
|
557
|
-
if getattr(m, "name", "").lower() == entry_name.lower()
|
|
558
|
-
]
|
|
546
|
+
exact = [m for m in matches if getattr(m, "name", "").lower() == entry_name.lower()]
|
|
559
547
|
if len(exact) == 1:
|
|
560
548
|
matches = exact
|
|
561
549
|
else:
|
|
562
|
-
raise ValueError(
|
|
563
|
-
f"Multiple {plural} named '{entry_name}'. Please disambiguate."
|
|
564
|
-
)
|
|
550
|
+
raise ValueError(f"Multiple {plural} named '{entry_name}'. Please disambiguate.")
|
|
565
551
|
return str(matches[0].id), True
|
|
566
552
|
|
|
567
553
|
def _resolve_tool_ids(
|
|
@@ -610,9 +596,7 @@ class AgentClient(BaseClient):
|
|
|
610
596
|
|
|
611
597
|
def _create_agent_from_payload(self, payload: Mapping[str, Any]) -> "Agent":
|
|
612
598
|
"""Create an agent using a fully prepared payload mapping."""
|
|
613
|
-
known, extras = _split_known_and_extra(
|
|
614
|
-
payload, AgentCreateRequest.__dataclass_fields__
|
|
615
|
-
)
|
|
599
|
+
known, extras = _split_known_and_extra(payload, AgentCreateRequest.__dataclass_fields__)
|
|
616
600
|
|
|
617
601
|
name = known.pop("name", None)
|
|
618
602
|
instruction = known.pop("instruction", None)
|
|
@@ -721,9 +705,7 @@ class AgentClient(BaseClient):
|
|
|
721
705
|
overrides = _merge_override_maps(base_overrides, kwargs)
|
|
722
706
|
|
|
723
707
|
if file is not None:
|
|
724
|
-
payload = _prepare_import_payload(
|
|
725
|
-
Path(file).expanduser(), overrides, drop_model_fields=True
|
|
726
|
-
)
|
|
708
|
+
payload = _prepare_import_payload(Path(file).expanduser(), overrides, drop_model_fields=True)
|
|
727
709
|
if overrides.get("model") is None:
|
|
728
710
|
payload.pop("model", None)
|
|
729
711
|
else:
|
|
@@ -746,9 +728,7 @@ class AgentClient(BaseClient):
|
|
|
746
728
|
payload: Mapping[str, Any],
|
|
747
729
|
) -> "Agent":
|
|
748
730
|
"""Update an agent using a prepared payload mapping."""
|
|
749
|
-
known, extras = _split_known_and_extra(
|
|
750
|
-
payload, AgentUpdateRequest.__dataclass_fields__
|
|
751
|
-
)
|
|
731
|
+
known, extras = _split_known_and_extra(payload, AgentUpdateRequest.__dataclass_fields__)
|
|
752
732
|
_normalise_sequence_fields(known)
|
|
753
733
|
|
|
754
734
|
tool_refs = extras.pop("_tool_refs", None)
|
|
@@ -818,9 +798,7 @@ class AgentClient(BaseClient):
|
|
|
818
798
|
overrides = _merge_override_maps(base_overrides, kwargs)
|
|
819
799
|
|
|
820
800
|
if file is not None:
|
|
821
|
-
payload = _prepare_import_payload(
|
|
822
|
-
Path(file).expanduser(), overrides, drop_model_fields=True
|
|
823
|
-
)
|
|
801
|
+
payload = _prepare_import_payload(Path(file).expanduser(), overrides, drop_model_fields=True)
|
|
824
802
|
else:
|
|
825
803
|
payload = overrides
|
|
826
804
|
|
|
@@ -882,9 +860,7 @@ class AgentClient(BaseClient):
|
|
|
882
860
|
payload["tty"] = True
|
|
883
861
|
return payload, None, None, headers, None
|
|
884
862
|
|
|
885
|
-
def _get_timeout_values(
|
|
886
|
-
self, timeout: float | None, **kwargs: Any
|
|
887
|
-
) -> tuple[float, float]:
|
|
863
|
+
def _get_timeout_values(self, timeout: float | None, **kwargs: Any) -> tuple[float, float]:
|
|
888
864
|
"""Get request timeout and execution timeout values.
|
|
889
865
|
|
|
890
866
|
Args:
|
|
@@ -1009,9 +985,7 @@ class AgentClient(BaseClient):
|
|
|
1009
985
|
headers = {"Accept": SSE_CONTENT_TYPE}
|
|
1010
986
|
return payload, None, None, headers
|
|
1011
987
|
|
|
1012
|
-
def _create_async_client_config(
|
|
1013
|
-
self, timeout: float | None, headers: dict | None
|
|
1014
|
-
) -> dict:
|
|
988
|
+
def _create_async_client_config(self, timeout: float | None, headers: dict | None) -> dict:
|
|
1015
989
|
"""Create async client configuration with proper headers and timeout."""
|
|
1016
990
|
config = self._build_async_client(timeout or self.timeout)
|
|
1017
991
|
if headers:
|
|
@@ -1040,9 +1014,7 @@ class AgentClient(BaseClient):
|
|
|
1040
1014
|
) as stream_response:
|
|
1041
1015
|
stream_response.raise_for_status()
|
|
1042
1016
|
|
|
1043
|
-
async for event in aiter_sse_events(
|
|
1044
|
-
stream_response, timeout_seconds, agent_name
|
|
1045
|
-
):
|
|
1017
|
+
async for event in aiter_sse_events(stream_response, timeout_seconds, agent_name):
|
|
1046
1018
|
try:
|
|
1047
1019
|
chunk = json.loads(event["data"])
|
|
1048
1020
|
yield chunk
|
|
@@ -1077,9 +1049,7 @@ class AgentClient(BaseClient):
|
|
|
1077
1049
|
Exception: For other unexpected errors
|
|
1078
1050
|
"""
|
|
1079
1051
|
# Prepare request data
|
|
1080
|
-
payload, data_payload, files_payload, headers = self._prepare_request_data(
|
|
1081
|
-
message, files, **kwargs
|
|
1082
|
-
)
|
|
1052
|
+
payload, data_payload, files_payload, headers = self._prepare_request_data(message, files, **kwargs)
|
|
1083
1053
|
|
|
1084
1054
|
# Create async client configuration
|
|
1085
1055
|
async_client_config = self._create_async_client_config(timeout, headers)
|
glaip_sdk/client/base.py
CHANGED
|
@@ -151,12 +151,7 @@ class BaseClient:
|
|
|
151
151
|
def timeout(self, value: float) -> None:
|
|
152
152
|
"""Set timeout and rebuild client."""
|
|
153
153
|
self._timeout = value
|
|
154
|
-
if (
|
|
155
|
-
hasattr(self, "http_client")
|
|
156
|
-
and self.http_client
|
|
157
|
-
and not self._session_scoped
|
|
158
|
-
and not self._parent_client
|
|
159
|
-
):
|
|
154
|
+
if hasattr(self, "http_client") and self.http_client and not self._session_scoped and not self._parent_client:
|
|
160
155
|
self.http_client.close()
|
|
161
156
|
self.http_client = self._build_client(value)
|
|
162
157
|
|
|
@@ -246,18 +241,14 @@ class BaseClient:
|
|
|
246
241
|
client_log.debug(f"Response status: {response.status_code}")
|
|
247
242
|
return response
|
|
248
243
|
except httpx.ConnectError as e:
|
|
249
|
-
client_log.warning(
|
|
250
|
-
f"Connection error on {method} {endpoint}, retrying once: {e}"
|
|
251
|
-
)
|
|
244
|
+
client_log.warning(f"Connection error on {method} {endpoint}, retrying once: {e}")
|
|
252
245
|
try:
|
|
253
246
|
response = self.http_client.request(method, endpoint, **kwargs)
|
|
254
|
-
client_log.debug(
|
|
255
|
-
f"Retry successful, response status: {response.status_code}"
|
|
256
|
-
)
|
|
247
|
+
client_log.debug(f"Retry successful, response status: {response.status_code}")
|
|
257
248
|
return response
|
|
258
249
|
except httpx.ConnectError:
|
|
259
250
|
client_log.error(f"Retry failed for {method} {endpoint}: {e}")
|
|
260
|
-
raise
|
|
251
|
+
raise
|
|
261
252
|
|
|
262
253
|
def _request(self, method: str, endpoint: str, **kwargs) -> Any:
|
|
263
254
|
"""Make HTTP request with error handling and unwrap success envelopes."""
|
|
@@ -381,9 +372,7 @@ class BaseClient:
|
|
|
381
372
|
error_message = self._get_error_message(response)
|
|
382
373
|
# Try to parse response content for payload
|
|
383
374
|
parsed_content = self._parse_response_content(response)
|
|
384
|
-
self._raise_api_error(
|
|
385
|
-
response.status_code, error_message, payload=parsed_content
|
|
386
|
-
)
|
|
375
|
+
self._raise_api_error(response.status_code, error_message, payload=parsed_content)
|
|
387
376
|
return None # Won't be reached but helps with type checking
|
|
388
377
|
|
|
389
378
|
parsed = self._parse_response_content(response)
|
|
@@ -435,12 +424,7 @@ class BaseClient:
|
|
|
435
424
|
|
|
436
425
|
def close(self) -> None:
|
|
437
426
|
"""Close the HTTP client."""
|
|
438
|
-
if (
|
|
439
|
-
hasattr(self, "http_client")
|
|
440
|
-
and self.http_client
|
|
441
|
-
and not self._session_scoped
|
|
442
|
-
and not self._parent_client
|
|
443
|
-
):
|
|
427
|
+
if hasattr(self, "http_client") and self.http_client and not self._session_scoped and not self._parent_client:
|
|
444
428
|
self.http_client.close()
|
|
445
429
|
|
|
446
430
|
def __enter__(self) -> "BaseClient":
|
glaip_sdk/client/mcps.py
CHANGED
|
@@ -179,9 +179,7 @@ class MCPClient(BaseClient):
|
|
|
179
179
|
update_data = {
|
|
180
180
|
"name": name if name is not None else current_mcp.name,
|
|
181
181
|
"type": DEFAULT_MCP_TYPE, # Required by backend, MCPs are always server type
|
|
182
|
-
"transport": kwargs.get(
|
|
183
|
-
"transport", getattr(current_mcp, "transport", DEFAULT_MCP_TRANSPORT)
|
|
184
|
-
),
|
|
182
|
+
"transport": kwargs.get("transport", getattr(current_mcp, "transport", DEFAULT_MCP_TRANSPORT)),
|
|
185
183
|
}
|
|
186
184
|
|
|
187
185
|
# Handle description with proper None handling
|
|
@@ -43,9 +43,7 @@ def _update_state_transcript(state: Any, text_value: str) -> bool:
|
|
|
43
43
|
|
|
44
44
|
updated = False
|
|
45
45
|
|
|
46
|
-
if hasattr(state, "final_text") and not _has_visible_text(
|
|
47
|
-
getattr(state, "final_text", "")
|
|
48
|
-
):
|
|
46
|
+
if hasattr(state, "final_text") and not _has_visible_text(getattr(state, "final_text", "")):
|
|
49
47
|
try:
|
|
50
48
|
state.final_text = text_value
|
|
51
49
|
updated = True
|
|
@@ -66,11 +64,9 @@ def _update_renderer_transcript(renderer: Any, text_value: str) -> None:
|
|
|
66
64
|
if _update_state_transcript(state, text_value):
|
|
67
65
|
return
|
|
68
66
|
|
|
69
|
-
if hasattr(renderer, "final_text") and not _has_visible_text(
|
|
70
|
-
getattr(renderer, "final_text", "")
|
|
71
|
-
):
|
|
67
|
+
if hasattr(renderer, "final_text") and not _has_visible_text(getattr(renderer, "final_text", "")):
|
|
72
68
|
try:
|
|
73
|
-
|
|
69
|
+
renderer.final_text = text_value
|
|
74
70
|
except Exception:
|
|
75
71
|
pass
|
|
76
72
|
|
|
@@ -220,9 +216,7 @@ class AgentRunRenderingManager:
|
|
|
220
216
|
meta: dict[str, Any],
|
|
221
217
|
renderer: RichStreamRenderer,
|
|
222
218
|
) -> None:
|
|
223
|
-
req_id = stream_response.headers.get(
|
|
224
|
-
"x-request-id"
|
|
225
|
-
) or stream_response.headers.get("x-run-id")
|
|
219
|
+
req_id = stream_response.headers.get("x-request-id") or stream_response.headers.get("x-run-id")
|
|
226
220
|
if req_id:
|
|
227
221
|
meta["run_id"] = req_id
|
|
228
222
|
renderer.on_start(meta)
|
|
@@ -318,9 +312,7 @@ class AgentRunRenderingManager:
|
|
|
318
312
|
meta["run_id"] = ev["run_id"]
|
|
319
313
|
renderer.on_start(meta)
|
|
320
314
|
|
|
321
|
-
def _ensure_renderer_final_content(
|
|
322
|
-
self, renderer: RichStreamRenderer, text: str
|
|
323
|
-
) -> None:
|
|
315
|
+
def _ensure_renderer_final_content(self, renderer: RichStreamRenderer, text: str) -> None:
|
|
324
316
|
"""Populate renderer state with final output when the stream omits it."""
|
|
325
317
|
if not text:
|
|
326
318
|
return
|
|
@@ -351,7 +343,7 @@ class AgentRunRenderingManager:
|
|
|
351
343
|
if hasattr(renderer, "state") and hasattr(renderer.state, "buffer"):
|
|
352
344
|
buffer_values = renderer.state.buffer
|
|
353
345
|
elif hasattr(renderer, "buffer"):
|
|
354
|
-
buffer_values =
|
|
346
|
+
buffer_values = renderer.buffer
|
|
355
347
|
|
|
356
348
|
if buffer_values is not None:
|
|
357
349
|
try:
|
glaip_sdk/client/tools.py
CHANGED
|
@@ -96,9 +96,7 @@ class ToolClient(BaseClient):
|
|
|
96
96
|
"""
|
|
97
97
|
return os.path.splitext(os.path.basename(file_path))[0]
|
|
98
98
|
|
|
99
|
-
def _prepare_upload_data(
|
|
100
|
-
self, name: str, framework: str, description: str | None = None, **kwargs
|
|
101
|
-
) -> dict:
|
|
99
|
+
def _prepare_upload_data(self, name: str, framework: str, description: str | None = None, **kwargs) -> dict:
|
|
102
100
|
"""Prepare upload data dictionary.
|
|
103
101
|
|
|
104
102
|
Args:
|
|
@@ -217,29 +215,21 @@ class ToolClient(BaseClient):
|
|
|
217
215
|
elif hasattr(current_tool, "description") and current_tool.description:
|
|
218
216
|
update_data["description"] = current_tool.description
|
|
219
217
|
|
|
220
|
-
def _handle_tags_update(
|
|
221
|
-
self, update_data: dict[str, Any], kwargs: dict[str, Any], current_tool: Tool
|
|
222
|
-
) -> None:
|
|
218
|
+
def _handle_tags_update(self, update_data: dict[str, Any], kwargs: dict[str, Any], current_tool: Tool) -> None:
|
|
223
219
|
"""Handle tags field in update payload."""
|
|
224
220
|
if kwargs.get("tags"):
|
|
225
221
|
if isinstance(kwargs["tags"], list):
|
|
226
|
-
update_data["tags"] = ",".join(
|
|
227
|
-
str(tag).strip() for tag in kwargs["tags"]
|
|
228
|
-
)
|
|
222
|
+
update_data["tags"] = ",".join(str(tag).strip() for tag in kwargs["tags"])
|
|
229
223
|
else:
|
|
230
224
|
update_data["tags"] = str(kwargs["tags"])
|
|
231
225
|
elif hasattr(current_tool, "tags") and current_tool.tags:
|
|
232
226
|
# Preserve existing tags if present
|
|
233
227
|
if isinstance(current_tool.tags, list):
|
|
234
|
-
update_data["tags"] = ",".join(
|
|
235
|
-
str(tag).strip() for tag in current_tool.tags
|
|
236
|
-
)
|
|
228
|
+
update_data["tags"] = ",".join(str(tag).strip() for tag in current_tool.tags)
|
|
237
229
|
else:
|
|
238
230
|
update_data["tags"] = str(current_tool.tags)
|
|
239
231
|
|
|
240
|
-
def _handle_additional_kwargs(
|
|
241
|
-
self, update_data: dict[str, Any], kwargs: dict[str, Any]
|
|
242
|
-
) -> None:
|
|
232
|
+
def _handle_additional_kwargs(self, update_data: dict[str, Any], kwargs: dict[str, Any]) -> None:
|
|
243
233
|
"""Handle additional kwargs in update payload."""
|
|
244
234
|
excluded_keys = {
|
|
245
235
|
"tags",
|
|
@@ -290,12 +280,8 @@ class ToolClient(BaseClient):
|
|
|
290
280
|
update_data = {
|
|
291
281
|
"name": name if name is not None else current_tool.name,
|
|
292
282
|
"type": current_type,
|
|
293
|
-
"framework": kwargs.get(
|
|
294
|
-
|
|
295
|
-
),
|
|
296
|
-
"version": kwargs.get(
|
|
297
|
-
"version", getattr(current_tool, "version", DEFAULT_TOOL_VERSION)
|
|
298
|
-
),
|
|
283
|
+
"framework": kwargs.get("framework", getattr(current_tool, "framework", DEFAULT_TOOL_FRAMEWORK)),
|
|
284
|
+
"version": kwargs.get("version", getattr(current_tool, "version", DEFAULT_TOOL_VERSION)),
|
|
299
285
|
}
|
|
300
286
|
|
|
301
287
|
# Handle description update
|
|
@@ -355,9 +341,7 @@ class ToolClient(BaseClient):
|
|
|
355
341
|
|
|
356
342
|
try:
|
|
357
343
|
# Prepare upload data
|
|
358
|
-
upload_data = self._prepare_upload_data(
|
|
359
|
-
name=name, framework=framework, description=description, **kwargs
|
|
360
|
-
)
|
|
344
|
+
upload_data = self._prepare_upload_data(name=name, framework=framework, description=description, **kwargs)
|
|
361
345
|
|
|
362
346
|
# Upload file
|
|
363
347
|
return self._upload_tool_file(temp_file_path, upload_data)
|
glaip_sdk/client/validators.py
CHANGED
|
@@ -39,9 +39,7 @@ class ResourceValidator:
|
|
|
39
39
|
if len(found_tools) == 1:
|
|
40
40
|
return str(found_tools[0].id)
|
|
41
41
|
elif len(found_tools) > 1:
|
|
42
|
-
raise AmbiguousResourceError(
|
|
43
|
-
f"Multiple tools found with name '{tool_name}': {[t.id for t in found_tools]}"
|
|
44
|
-
)
|
|
42
|
+
raise AmbiguousResourceError(f"Multiple tools found with name '{tool_name}': {[t.id for t in found_tools]}")
|
|
45
43
|
else:
|
|
46
44
|
raise NotFoundError(f"Tool not found: {tool_name}")
|
|
47
45
|
|
|
@@ -51,9 +49,7 @@ class ResourceValidator:
|
|
|
51
49
|
if len(found_tools) == 1:
|
|
52
50
|
return str(found_tools[0].id)
|
|
53
51
|
elif len(found_tools) > 1:
|
|
54
|
-
raise AmbiguousResourceError(
|
|
55
|
-
f"Multiple tools found with name '{tool.name}': {[t.id for t in found_tools]}"
|
|
56
|
-
)
|
|
52
|
+
raise AmbiguousResourceError(f"Multiple tools found with name '{tool.name}': {[t.id for t in found_tools]}")
|
|
57
53
|
else:
|
|
58
54
|
raise NotFoundError(f"Tool not found: {tool.name}")
|
|
59
55
|
|
|
@@ -73,9 +69,7 @@ class ResourceValidator:
|
|
|
73
69
|
elif hasattr(tool, "name") and tool.name is not None:
|
|
74
70
|
return self._resolve_tool_by_name_attribute(tool, client)
|
|
75
71
|
else:
|
|
76
|
-
raise ValidationError(
|
|
77
|
-
f"Invalid tool reference: {tool} - must have 'id' or 'name' attribute"
|
|
78
|
-
)
|
|
72
|
+
raise ValidationError(f"Invalid tool reference: {tool} - must have 'id' or 'name' attribute")
|
|
79
73
|
|
|
80
74
|
def _process_single_tool(self, tool: str | Tool, client: Any) -> str:
|
|
81
75
|
"""Process a single tool reference and return its ID."""
|
|
@@ -99,22 +93,14 @@ class ResourceValidator:
|
|
|
99
93
|
try:
|
|
100
94
|
tool_id = cls()._process_single_tool(tool, client)
|
|
101
95
|
tool_ids.append(tool_id)
|
|
102
|
-
except (AmbiguousResourceError, NotFoundError) as
|
|
96
|
+
except (AmbiguousResourceError, NotFoundError) as err:
|
|
103
97
|
# Determine the tool name for the error message
|
|
104
|
-
tool_name = (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
raise ValidationError(
|
|
108
|
-
f"Failed to resolve tool name '{tool_name}' to ID: {e}"
|
|
109
|
-
)
|
|
110
|
-
except Exception as e:
|
|
98
|
+
tool_name = tool if isinstance(tool, str) else getattr(tool, "name", str(tool))
|
|
99
|
+
raise ValidationError(f"Failed to resolve tool name '{tool_name}' to ID: {err}") from err
|
|
100
|
+
except Exception as err:
|
|
111
101
|
# For other exceptions, wrap them appropriately
|
|
112
|
-
tool_name = (
|
|
113
|
-
|
|
114
|
-
)
|
|
115
|
-
raise ValidationError(
|
|
116
|
-
f"Failed to resolve tool name '{tool_name}' to ID: {e}"
|
|
117
|
-
)
|
|
102
|
+
tool_name = tool if isinstance(tool, str) else getattr(tool, "name", str(tool))
|
|
103
|
+
raise ValidationError(f"Failed to resolve tool name '{tool_name}' to ID: {err}") from err
|
|
118
104
|
|
|
119
105
|
return tool_ids
|
|
120
106
|
|
|
@@ -158,9 +144,7 @@ class ResourceValidator:
|
|
|
158
144
|
elif hasattr(agent, "name") and agent.name is not None:
|
|
159
145
|
return self._resolve_agent_by_name_attribute(agent, client)
|
|
160
146
|
else:
|
|
161
|
-
raise ValidationError(
|
|
162
|
-
f"Invalid agent reference: {agent} - must have 'id' or 'name' attribute"
|
|
163
|
-
)
|
|
147
|
+
raise ValidationError(f"Invalid agent reference: {agent} - must have 'id' or 'name' attribute")
|
|
164
148
|
|
|
165
149
|
def _process_single_agent(self, agent: str | Any, client: Any) -> str:
|
|
166
150
|
"""Process a single agent reference and return its ID."""
|
|
@@ -184,26 +168,14 @@ class ResourceValidator:
|
|
|
184
168
|
try:
|
|
185
169
|
agent_id = cls()._process_single_agent(agent, client)
|
|
186
170
|
agent_ids.append(agent_id)
|
|
187
|
-
except (AmbiguousResourceError, NotFoundError) as
|
|
171
|
+
except (AmbiguousResourceError, NotFoundError) as err:
|
|
188
172
|
# Determine the agent name for the error message
|
|
189
|
-
agent_name = (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
else getattr(agent, "name", str(agent))
|
|
193
|
-
)
|
|
194
|
-
raise ValidationError(
|
|
195
|
-
f"Failed to resolve agent name '{agent_name}' to ID: {e}"
|
|
196
|
-
)
|
|
197
|
-
except Exception as e:
|
|
173
|
+
agent_name = agent if isinstance(agent, str) else getattr(agent, "name", str(agent))
|
|
174
|
+
raise ValidationError(f"Failed to resolve agent name '{agent_name}' to ID: {err}") from err
|
|
175
|
+
except Exception as err:
|
|
198
176
|
# For other exceptions, wrap them appropriately
|
|
199
|
-
agent_name = (
|
|
200
|
-
|
|
201
|
-
if isinstance(agent, str)
|
|
202
|
-
else getattr(agent, "name", str(agent))
|
|
203
|
-
)
|
|
204
|
-
raise ValidationError(
|
|
205
|
-
f"Failed to resolve agent name '{agent_name}' to ID: {e}"
|
|
206
|
-
)
|
|
177
|
+
agent_name = agent if isinstance(agent, str) else getattr(agent, "name", str(agent))
|
|
178
|
+
raise ValidationError(f"Failed to resolve agent name '{agent_name}' to ID: {err}") from err
|
|
207
179
|
|
|
208
180
|
return agent_ids
|
|
209
181
|
|
|
@@ -213,8 +185,8 @@ class ResourceValidator:
|
|
|
213
185
|
for tool_id in tool_ids:
|
|
214
186
|
try:
|
|
215
187
|
client.get_tool_by_id(tool_id)
|
|
216
|
-
except NotFoundError:
|
|
217
|
-
raise ValidationError(f"Tool not found: {tool_id}")
|
|
188
|
+
except NotFoundError as err:
|
|
189
|
+
raise ValidationError(f"Tool not found: {tool_id}") from err
|
|
218
190
|
|
|
219
191
|
@classmethod
|
|
220
192
|
def validate_agents_exist(cls, agent_ids: list[str], client: Any) -> None:
|
|
@@ -222,5 +194,5 @@ class ResourceValidator:
|
|
|
222
194
|
for agent_id in agent_ids:
|
|
223
195
|
try:
|
|
224
196
|
client.get_agent_by_id(agent_id)
|
|
225
|
-
except NotFoundError:
|
|
226
|
-
raise ValidationError(f"Agent not found: {agent_id}")
|
|
197
|
+
except NotFoundError as err:
|
|
198
|
+
raise ValidationError(f"Agent not found: {agent_id}") from err
|
glaip_sdk/exceptions.py
CHANGED
|
@@ -107,9 +107,7 @@ class AgentTimeoutError(TimeoutError):
|
|
|
107
107
|
agent_name: Optional name of the agent that timed out
|
|
108
108
|
"""
|
|
109
109
|
agent_info = f" for agent '{agent_name}'" if agent_name else ""
|
|
110
|
-
message =
|
|
111
|
-
f"Agent execution timed out after {timeout_seconds} seconds{agent_info}"
|
|
112
|
-
)
|
|
110
|
+
message = f"Agent execution timed out after {timeout_seconds} seconds{agent_info}"
|
|
113
111
|
super().__init__(message)
|
|
114
112
|
self.timeout_seconds = timeout_seconds
|
|
115
113
|
self.agent_name = agent_name
|