glaip-sdk 0.1.0__py3-none-any.whl → 0.6.10__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 +1191 -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 +251 -173
- glaip_sdk/cli/commands/common_config.py +101 -0
- glaip_sdk/cli/commands/configure.py +735 -143
- glaip_sdk/cli/commands/mcps.py +266 -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 +578 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +65 -29
- glaip_sdk/cli/slash/prompt.py +24 -10
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +807 -225
- 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 +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 +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 +79 -499
- glaip_sdk/cli/update_notifier.py +177 -24
- glaip_sdk/cli/utils.py +242 -1308
- 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 +136 -101
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +163 -34
- glaip_sdk/client/validators.py +20 -48
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/exceptions.py +1 -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 +232 -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 +706 -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 +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 +7 -35
- 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 +3 -6
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -49
- glaip_sdk/utils/rendering/renderer/base.py +258 -1577
- glaip_sdk/utils/rendering/renderer/config.py +1 -5
- 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 +10 -51
- 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 +1 -3
- 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 +1 -3
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +76 -517
- 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 +29 -26
- glaip_sdk/utils/runtime_config.py +425 -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.1.0.dist-info → glaip_sdk-0.6.10.dist-info}/METADATA +42 -4
- glaip_sdk-0.6.10.dist-info/RECORD +159 -0
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.6.10.dist-info}/WHEEL +1 -1
- glaip_sdk/models.py +0 -259
- glaip_sdk-0.1.0.dist-info/RECORD +0 -82
- {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.6.10.dist-info}/entry_points.txt +0 -0
glaip_sdk/cli/validators.py
CHANGED
|
@@ -13,6 +13,7 @@ from typing import Any
|
|
|
13
13
|
|
|
14
14
|
import click
|
|
15
15
|
|
|
16
|
+
from glaip_sdk.cli.utils import handle_best_effort_check
|
|
16
17
|
from glaip_sdk.utils.validation import (
|
|
17
18
|
coerce_timeout,
|
|
18
19
|
validate_agent_instruction,
|
|
@@ -42,7 +43,7 @@ def validate_agent_name_cli(name: str) -> str:
|
|
|
42
43
|
try:
|
|
43
44
|
return validate_agent_name(name)
|
|
44
45
|
except ValueError as e:
|
|
45
|
-
raise click.ClickException(str(e))
|
|
46
|
+
raise click.ClickException(str(e)) from e
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
def validate_agent_instruction_cli(instruction: str) -> str:
|
|
@@ -60,7 +61,7 @@ def validate_agent_instruction_cli(instruction: str) -> str:
|
|
|
60
61
|
try:
|
|
61
62
|
return validate_agent_instruction(instruction)
|
|
62
63
|
except ValueError as e:
|
|
63
|
-
raise click.ClickException(str(e))
|
|
64
|
+
raise click.ClickException(str(e)) from e
|
|
64
65
|
|
|
65
66
|
|
|
66
67
|
def validate_timeout_cli(timeout: int) -> int:
|
|
@@ -78,7 +79,7 @@ def validate_timeout_cli(timeout: int) -> int:
|
|
|
78
79
|
try:
|
|
79
80
|
return validate_timeout(timeout)
|
|
80
81
|
except ValueError as e:
|
|
81
|
-
raise click.ClickException(str(e))
|
|
82
|
+
raise click.ClickException(str(e)) from e
|
|
82
83
|
|
|
83
84
|
|
|
84
85
|
def validate_tool_name_cli(name: str) -> str:
|
|
@@ -96,7 +97,7 @@ def validate_tool_name_cli(name: str) -> str:
|
|
|
96
97
|
try:
|
|
97
98
|
return validate_tool_name(name)
|
|
98
99
|
except ValueError as e:
|
|
99
|
-
raise click.ClickException(str(e))
|
|
100
|
+
raise click.ClickException(str(e)) from e
|
|
100
101
|
|
|
101
102
|
|
|
102
103
|
def validate_mcp_name_cli(name: str) -> str:
|
|
@@ -114,7 +115,7 @@ def validate_mcp_name_cli(name: str) -> str:
|
|
|
114
115
|
try:
|
|
115
116
|
return validate_mcp_name(name)
|
|
116
117
|
except ValueError as e:
|
|
117
|
-
raise click.ClickException(str(e))
|
|
118
|
+
raise click.ClickException(str(e)) from e
|
|
118
119
|
|
|
119
120
|
|
|
120
121
|
def validate_file_path_cli(file_path: str | Path, must_exist: bool = True) -> Path:
|
|
@@ -133,7 +134,7 @@ def validate_file_path_cli(file_path: str | Path, must_exist: bool = True) -> Pa
|
|
|
133
134
|
try:
|
|
134
135
|
return validate_file_path(file_path, must_exist)
|
|
135
136
|
except ValueError as e:
|
|
136
|
-
raise click.ClickException(str(e))
|
|
137
|
+
raise click.ClickException(str(e)) from e
|
|
137
138
|
|
|
138
139
|
|
|
139
140
|
def validate_directory_path_cli(dir_path: str | Path, must_exist: bool = True) -> Path:
|
|
@@ -152,7 +153,7 @@ def validate_directory_path_cli(dir_path: str | Path, must_exist: bool = True) -
|
|
|
152
153
|
try:
|
|
153
154
|
return validate_directory_path(dir_path, must_exist)
|
|
154
155
|
except ValueError as e:
|
|
155
|
-
raise click.ClickException(str(e))
|
|
156
|
+
raise click.ClickException(str(e)) from e
|
|
156
157
|
|
|
157
158
|
|
|
158
159
|
def validate_url_cli(url: str) -> str:
|
|
@@ -170,7 +171,7 @@ def validate_url_cli(url: str) -> str:
|
|
|
170
171
|
try:
|
|
171
172
|
return validate_url(url)
|
|
172
173
|
except ValueError as e:
|
|
173
|
-
raise click.ClickException(str(e))
|
|
174
|
+
raise click.ClickException(str(e)) from e
|
|
174
175
|
|
|
175
176
|
|
|
176
177
|
def validate_api_key_cli(api_key: str) -> str:
|
|
@@ -188,7 +189,7 @@ def validate_api_key_cli(api_key: str) -> str:
|
|
|
188
189
|
try:
|
|
189
190
|
return validate_api_key(api_key)
|
|
190
191
|
except ValueError as e:
|
|
191
|
-
raise click.ClickException(str(e))
|
|
192
|
+
raise click.ClickException(str(e)) from e
|
|
192
193
|
|
|
193
194
|
|
|
194
195
|
def coerce_timeout_cli(value: int | float | str) -> int:
|
|
@@ -206,7 +207,7 @@ def coerce_timeout_cli(value: int | float | str) -> int:
|
|
|
206
207
|
try:
|
|
207
208
|
return coerce_timeout(value)
|
|
208
209
|
except ValueError as e:
|
|
209
|
-
raise click.ClickException(str(e))
|
|
210
|
+
raise click.ClickException(str(e)) from e
|
|
210
211
|
|
|
211
212
|
|
|
212
213
|
def validate_name_uniqueness_cli(
|
|
@@ -226,15 +227,12 @@ def validate_name_uniqueness_cli(
|
|
|
226
227
|
Raises:
|
|
227
228
|
click.ClickException: If name is not unique
|
|
228
229
|
"""
|
|
229
|
-
|
|
230
|
+
|
|
231
|
+
def _check_duplicate() -> None:
|
|
230
232
|
existing = finder_func(name=name)
|
|
231
233
|
if existing:
|
|
232
234
|
raise click.ClickException(
|
|
233
|
-
f"A {resource_type.lower()} named '{name}' already exists. "
|
|
234
|
-
"Please choose a unique name."
|
|
235
|
+
f"A {resource_type.lower()} named '{name}' already exists. Please choose a unique name."
|
|
235
236
|
)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
except Exception:
|
|
239
|
-
# Non-fatal: best-effort duplicate check
|
|
240
|
-
pass
|
|
237
|
+
|
|
238
|
+
handle_best_effort_check(_check_duplicate)
|
glaip_sdk/client/__init__.py
CHANGED
|
@@ -15,10 +15,7 @@ from glaip_sdk.config.constants import (
|
|
|
15
15
|
DEFAULT_AGENT_VERSION,
|
|
16
16
|
DEFAULT_MODEL,
|
|
17
17
|
)
|
|
18
|
-
from glaip_sdk.payload_schemas.agent import
|
|
19
|
-
AgentImportOperation,
|
|
20
|
-
get_import_field_plan,
|
|
21
|
-
)
|
|
18
|
+
from glaip_sdk.payload_schemas.agent import AgentImportOperation, get_import_field_plan
|
|
22
19
|
from glaip_sdk.utils.client_utils import extract_ids
|
|
23
20
|
|
|
24
21
|
_LM_CONFLICT_KEYS = {
|
|
@@ -209,6 +206,11 @@ class AgentListParams:
|
|
|
209
206
|
return params
|
|
210
207
|
|
|
211
208
|
def _base_filter_params(self) -> dict[str, Any]:
|
|
209
|
+
"""Build base filter parameters from non-None fields.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Dictionary of filter parameters with non-None values.
|
|
213
|
+
"""
|
|
212
214
|
return {
|
|
213
215
|
key: value
|
|
214
216
|
for key, value in (
|
|
@@ -221,6 +223,11 @@ class AgentListParams:
|
|
|
221
223
|
}
|
|
222
224
|
|
|
223
225
|
def _apply_pagination_params(self, params: dict[str, Any]) -> None:
|
|
226
|
+
"""Apply pagination parameters to the params dictionary.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
params: Dictionary to update with pagination parameters.
|
|
230
|
+
"""
|
|
224
231
|
if self.limit is not None:
|
|
225
232
|
if not 1 <= self.limit <= 100:
|
|
226
233
|
raise ValueError("limit must be between 1 and 100 inclusive")
|
|
@@ -238,6 +245,11 @@ class AgentListParams:
|
|
|
238
245
|
params["sync_langflow_agents"] = str(self.sync_langflow_agents).lower()
|
|
239
246
|
|
|
240
247
|
def _apply_timestamp_filters(self, params: dict[str, Any]) -> None:
|
|
248
|
+
"""Apply timestamp filter parameters to the params dictionary.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
params: Dictionary to update with timestamp filter parameters.
|
|
252
|
+
"""
|
|
241
253
|
timestamp_filters = {
|
|
242
254
|
"created_at_start": self.created_at_start,
|
|
243
255
|
"created_at_end": self.created_at_end,
|
|
@@ -249,6 +261,11 @@ class AgentListParams:
|
|
|
249
261
|
params[key] = value
|
|
250
262
|
|
|
251
263
|
def _apply_metadata_filters(self, params: dict[str, Any]) -> None:
|
|
264
|
+
"""Apply metadata filter parameters to the params dictionary.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
params: Dictionary to update with metadata filter parameters.
|
|
268
|
+
"""
|
|
252
269
|
if not self.metadata:
|
|
253
270
|
return
|
|
254
271
|
for key, value in self.metadata.items():
|
|
@@ -269,12 +286,22 @@ class AgentListResult:
|
|
|
269
286
|
message: str | None = None
|
|
270
287
|
|
|
271
288
|
def __len__(self) -> int: # pragma: no cover - simple delegation
|
|
289
|
+
"""Return the number of items in the result list."""
|
|
272
290
|
return len(self.items)
|
|
273
291
|
|
|
274
292
|
def __iter__(self): # pragma: no cover - simple delegation
|
|
293
|
+
"""Return an iterator over the items in the result list."""
|
|
275
294
|
return iter(self.items)
|
|
276
295
|
|
|
277
296
|
def __getitem__(self, index: int) -> Any: # pragma: no cover - simple delegation
|
|
297
|
+
"""Get an item from the result list by index.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
index: Index of the item to retrieve.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
The item at the specified index.
|
|
304
|
+
"""
|
|
278
305
|
return self.items[index]
|
|
279
306
|
|
|
280
307
|
|
|
@@ -348,9 +375,7 @@ class AgentCreateRequest:
|
|
|
348
375
|
payload["tool_configs"] = _copy_structure(self.tool_configs)
|
|
349
376
|
|
|
350
377
|
effective_agent_config = _sanitize_agent_config(self.agent_config)
|
|
351
|
-
effective_agent_config = _merge_execution_timeout(
|
|
352
|
-
effective_agent_config, self.timeout
|
|
353
|
-
)
|
|
378
|
+
effective_agent_config = _merge_execution_timeout(effective_agent_config, self.timeout)
|
|
354
379
|
if effective_agent_config:
|
|
355
380
|
payload["agent_config"] = effective_agent_config
|
|
356
381
|
|
|
@@ -407,31 +432,25 @@ __all__ = [
|
|
|
407
432
|
]
|
|
408
433
|
|
|
409
434
|
|
|
410
|
-
def _build_base_update_payload(
|
|
411
|
-
request
|
|
412
|
-
)
|
|
435
|
+
def _build_base_update_payload(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
|
|
436
|
+
"""Populate immutable agent update fields using request data or existing agent defaults."""
|
|
437
|
+
# Support both "agent_type" (runtime class) and "type" (API response) attributes
|
|
438
|
+
current_type = getattr(current_agent, "agent_type", None) or getattr(current_agent, "type", None)
|
|
413
439
|
return {
|
|
414
|
-
"name": request.name.strip()
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
"type": request.agent_type
|
|
421
|
-
or getattr(current_agent, "
|
|
422
|
-
or
|
|
423
|
-
"framework": request.framework
|
|
424
|
-
or getattr(current_agent, "framework", None)
|
|
425
|
-
or DEFAULT_AGENT_FRAMEWORK,
|
|
426
|
-
"version": request.version
|
|
427
|
-
or getattr(current_agent, "version", None)
|
|
428
|
-
or DEFAULT_AGENT_VERSION,
|
|
440
|
+
"name": (request.name.strip() if request.name is not None else getattr(current_agent, "name", None)),
|
|
441
|
+
"instruction": (
|
|
442
|
+
request.instruction.strip()
|
|
443
|
+
if request.instruction is not None
|
|
444
|
+
else getattr(current_agent, "instruction", None)
|
|
445
|
+
),
|
|
446
|
+
"type": request.agent_type or current_type or DEFAULT_AGENT_TYPE,
|
|
447
|
+
"framework": request.framework or getattr(current_agent, "framework", None) or DEFAULT_AGENT_FRAMEWORK,
|
|
448
|
+
"version": request.version or getattr(current_agent, "version", None) or DEFAULT_AGENT_VERSION,
|
|
429
449
|
}
|
|
430
450
|
|
|
431
451
|
|
|
432
|
-
def _resolve_update_language_model_fields(
|
|
433
|
-
request
|
|
434
|
-
) -> dict[str, Any]:
|
|
452
|
+
def _resolve_update_language_model_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
|
|
453
|
+
"""Resolve the language-model portion of an update request with sensible fallbacks."""
|
|
435
454
|
fields = resolve_language_model_fields(
|
|
436
455
|
model=request.model,
|
|
437
456
|
language_model_id=request.language_model_id,
|
|
@@ -443,9 +462,8 @@ def _resolve_update_language_model_fields(
|
|
|
443
462
|
return fields
|
|
444
463
|
|
|
445
464
|
|
|
446
|
-
def _collect_optional_update_fields(
|
|
447
|
-
|
|
448
|
-
) -> dict[str, Any]:
|
|
465
|
+
def _collect_optional_update_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
|
|
466
|
+
"""Collect optional agent fields, preserving current values when updates are absent."""
|
|
449
467
|
result: dict[str, Any] = {}
|
|
450
468
|
|
|
451
469
|
for field_name, value in (
|
|
@@ -483,9 +501,8 @@ def _collect_optional_update_fields(
|
|
|
483
501
|
return result
|
|
484
502
|
|
|
485
503
|
|
|
486
|
-
def _collect_relationship_fields(
|
|
487
|
-
|
|
488
|
-
) -> dict[str, Any]:
|
|
504
|
+
def _collect_relationship_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
|
|
505
|
+
"""Return relationship identifiers (tools/agents/mcps) for an update request."""
|
|
489
506
|
return {
|
|
490
507
|
"tools": _resolve_relation_ids(request.tools, current_agent, "tools"),
|
|
491
508
|
"agents": _resolve_relation_ids(request.agents, current_agent, "agents"),
|
|
@@ -493,9 +510,8 @@ def _collect_relationship_fields(
|
|
|
493
510
|
}
|
|
494
511
|
|
|
495
512
|
|
|
496
|
-
def _resolve_agent_config_update(
|
|
497
|
-
|
|
498
|
-
) -> dict[str, Any] | None:
|
|
513
|
+
def _resolve_agent_config_update(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any] | None:
|
|
514
|
+
"""Determine the agent_config payload to send, if any."""
|
|
499
515
|
effective_agent_config = _sanitize_agent_config(request.agent_config)
|
|
500
516
|
if effective_agent_config is not None:
|
|
501
517
|
return effective_agent_config
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Agent runs client for AIP SDK.
|
|
3
|
+
|
|
4
|
+
Authors:
|
|
5
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
from glaip_sdk.client.base import BaseClient
|
|
13
|
+
from glaip_sdk.exceptions import TimeoutError, ValidationError
|
|
14
|
+
from glaip_sdk.models.agent_runs import RunSummary, RunsPage, RunWithOutput
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AgentRunsClient(BaseClient):
|
|
18
|
+
"""Client for agent run operations."""
|
|
19
|
+
|
|
20
|
+
def list_runs(
|
|
21
|
+
self,
|
|
22
|
+
agent_id: str,
|
|
23
|
+
*,
|
|
24
|
+
limit: int = 20,
|
|
25
|
+
page: int = 1,
|
|
26
|
+
) -> RunsPage:
|
|
27
|
+
"""List agent runs with pagination.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
agent_id: UUID of the agent
|
|
31
|
+
limit: Number of runs per page (1-100, default 20)
|
|
32
|
+
page: Page number (1-based, default 1)
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
RunsPage containing paginated run summaries
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
ValidationError: If pagination parameters are invalid
|
|
39
|
+
NotFoundError: If agent is not found
|
|
40
|
+
AuthenticationError: If authentication fails
|
|
41
|
+
TimeoutError: If request times out (30s default)
|
|
42
|
+
"""
|
|
43
|
+
self._validate_pagination_params(limit, page)
|
|
44
|
+
envelope = self._fetch_runs_envelope(agent_id, limit, page)
|
|
45
|
+
normalized_data = self._normalize_runs_payload(envelope.get("data"))
|
|
46
|
+
runs = [RunSummary(**item) for item in normalized_data]
|
|
47
|
+
return self._build_runs_page(envelope, runs, limit, page)
|
|
48
|
+
|
|
49
|
+
def _fetch_runs_envelope(self, agent_id: str, limit: int, page: int) -> dict[str, Any]:
|
|
50
|
+
params = {"limit": limit, "page": page}
|
|
51
|
+
try:
|
|
52
|
+
envelope = self._request_with_envelope(
|
|
53
|
+
"GET",
|
|
54
|
+
f"/agents/{agent_id}/runs",
|
|
55
|
+
params=params,
|
|
56
|
+
)
|
|
57
|
+
except httpx.TimeoutException as e:
|
|
58
|
+
raise TimeoutError(f"Request timed out after {self._timeout}s while fetching agent runs") from e
|
|
59
|
+
|
|
60
|
+
if isinstance(envelope, dict):
|
|
61
|
+
return envelope
|
|
62
|
+
return {"data": envelope}
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def _validate_pagination_params(limit: int, page: int) -> None:
|
|
66
|
+
if limit < 1 or limit > 100:
|
|
67
|
+
raise ValidationError("limit must be between 1 and 100")
|
|
68
|
+
if page < 1:
|
|
69
|
+
raise ValidationError("page must be >= 1")
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def _normalize_runs_payload(data_payload: Any) -> list[Any]:
|
|
73
|
+
if not data_payload:
|
|
74
|
+
return []
|
|
75
|
+
normalized_data: list[Any] = []
|
|
76
|
+
for item in data_payload:
|
|
77
|
+
normalized_data.append(AgentRunsClient._normalize_run_item(item))
|
|
78
|
+
return normalized_data
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def _normalize_run_item(item: Any) -> Any:
|
|
82
|
+
if isinstance(item, dict):
|
|
83
|
+
if item.get("config") is None:
|
|
84
|
+
item["config"] = {}
|
|
85
|
+
schedule_id = item.get("schedule_id")
|
|
86
|
+
if schedule_id == "None" or schedule_id == "":
|
|
87
|
+
item["schedule_id"] = None
|
|
88
|
+
return item
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def _build_runs_page(
|
|
92
|
+
envelope: dict[str, Any],
|
|
93
|
+
runs: list[RunSummary],
|
|
94
|
+
limit: int,
|
|
95
|
+
page: int,
|
|
96
|
+
) -> RunsPage:
|
|
97
|
+
return RunsPage(
|
|
98
|
+
data=runs,
|
|
99
|
+
total=envelope.get("total", 0),
|
|
100
|
+
page=envelope.get("page", page),
|
|
101
|
+
limit=envelope.get("limit", limit),
|
|
102
|
+
has_next=envelope.get("has_next", False),
|
|
103
|
+
has_prev=envelope.get("has_prev", False),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def get_run(
|
|
107
|
+
self,
|
|
108
|
+
agent_id: str,
|
|
109
|
+
run_id: str,
|
|
110
|
+
) -> RunWithOutput:
|
|
111
|
+
"""Get detailed run information including SSE event stream.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
agent_id: UUID of the agent
|
|
115
|
+
run_id: UUID of the run
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
RunWithOutput containing complete run details and event stream
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
NotFoundError: If run or agent is not found
|
|
122
|
+
AuthenticationError: If authentication fails
|
|
123
|
+
TimeoutError: If request times out (30s default)
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
envelope = self._request_with_envelope(
|
|
127
|
+
"GET",
|
|
128
|
+
f"/agents/{agent_id}/runs/{run_id}",
|
|
129
|
+
)
|
|
130
|
+
except httpx.TimeoutException as e:
|
|
131
|
+
raise TimeoutError(f"Request timed out after {self._timeout}s while fetching run detail") from e
|
|
132
|
+
|
|
133
|
+
if not isinstance(envelope, dict):
|
|
134
|
+
envelope = {"data": envelope}
|
|
135
|
+
|
|
136
|
+
data = envelope.get("data") or {}
|
|
137
|
+
# Normalize config, output, and schedule_id fields
|
|
138
|
+
if data.get("config") is None:
|
|
139
|
+
data["config"] = {}
|
|
140
|
+
if data.get("output") is None:
|
|
141
|
+
data["output"] = []
|
|
142
|
+
# Normalize schedule_id: convert string "None" to None
|
|
143
|
+
schedule_id = data.get("schedule_id")
|
|
144
|
+
if schedule_id == "None" or schedule_id == "":
|
|
145
|
+
data["schedule_id"] = None
|
|
146
|
+
|
|
147
|
+
return RunWithOutput(**data)
|