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
glaip_sdk/client/agents.py
CHANGED
|
@@ -3,39 +3,45 @@
|
|
|
3
3
|
|
|
4
4
|
Authors:
|
|
5
5
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
6
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
6
7
|
"""
|
|
7
8
|
|
|
9
|
+
import asyncio
|
|
8
10
|
import json
|
|
9
11
|
import logging
|
|
10
12
|
from collections.abc import AsyncGenerator, Callable, Iterator, Mapping
|
|
13
|
+
from contextlib import asynccontextmanager
|
|
11
14
|
from os import PathLike
|
|
12
15
|
from pathlib import Path
|
|
13
16
|
from typing import Any, BinaryIO
|
|
14
17
|
|
|
15
18
|
import httpx
|
|
16
|
-
|
|
19
|
+
from glaip_sdk.agents import Agent
|
|
17
20
|
from glaip_sdk.client._agent_payloads import (
|
|
18
21
|
AgentCreateRequest,
|
|
19
22
|
AgentListParams,
|
|
20
23
|
AgentListResult,
|
|
21
24
|
AgentUpdateRequest,
|
|
22
25
|
)
|
|
26
|
+
from glaip_sdk.client.agent_runs import AgentRunsClient
|
|
23
27
|
from glaip_sdk.client.base import BaseClient
|
|
24
28
|
from glaip_sdk.client.mcps import MCPClient
|
|
25
29
|
from glaip_sdk.client.run_rendering import (
|
|
26
30
|
AgentRunRenderingManager,
|
|
27
31
|
compute_timeout_seconds,
|
|
28
32
|
)
|
|
33
|
+
from glaip_sdk.client.shared import build_shared_config
|
|
29
34
|
from glaip_sdk.client.tools import ToolClient
|
|
30
35
|
from glaip_sdk.config.constants import (
|
|
36
|
+
AGENT_CONFIG_FIELDS,
|
|
31
37
|
DEFAULT_AGENT_FRAMEWORK,
|
|
32
38
|
DEFAULT_AGENT_RUN_TIMEOUT,
|
|
33
39
|
DEFAULT_AGENT_TYPE,
|
|
34
40
|
DEFAULT_AGENT_VERSION,
|
|
35
41
|
DEFAULT_MODEL,
|
|
36
42
|
)
|
|
37
|
-
from glaip_sdk.exceptions import NotFoundError
|
|
38
|
-
from glaip_sdk.models import
|
|
43
|
+
from glaip_sdk.exceptions import NotFoundError, ValidationError
|
|
44
|
+
from glaip_sdk.models import AgentResponse
|
|
39
45
|
from glaip_sdk.payload_schemas.agent import list_server_only_fields
|
|
40
46
|
from glaip_sdk.utils.agent_config import normalize_agent_config_for_import
|
|
41
47
|
from glaip_sdk.utils.client_utils import (
|
|
@@ -67,6 +73,21 @@ _MERGED_SEQUENCE_FIELDS = ("tools", "agents", "mcps")
|
|
|
67
73
|
_DEFAULT_METADATA_TYPE = "custom"
|
|
68
74
|
|
|
69
75
|
|
|
76
|
+
@asynccontextmanager
|
|
77
|
+
async def _async_timeout_guard(
|
|
78
|
+
timeout_seconds: float | None,
|
|
79
|
+
) -> AsyncGenerator[None, None]:
|
|
80
|
+
"""Apply an asyncio timeout when a custom timeout is provided."""
|
|
81
|
+
if timeout_seconds is None:
|
|
82
|
+
yield
|
|
83
|
+
return
|
|
84
|
+
try:
|
|
85
|
+
async with asyncio.timeout(timeout_seconds):
|
|
86
|
+
yield
|
|
87
|
+
except asyncio.TimeoutError as exc:
|
|
88
|
+
raise httpx.TimeoutException(f"Request timed out after {timeout_seconds}s") from exc
|
|
89
|
+
|
|
90
|
+
|
|
70
91
|
def _normalise_sequence(value: Any) -> list[Any] | None:
|
|
71
92
|
"""Normalise optional sequence inputs to plain lists."""
|
|
72
93
|
if value is None:
|
|
@@ -97,9 +118,7 @@ def _merge_override_maps(
|
|
|
97
118
|
for key, value in source.items():
|
|
98
119
|
if value is None:
|
|
99
120
|
continue
|
|
100
|
-
merged[key] = (
|
|
101
|
-
_normalise_sequence(value) if key in _MERGED_SEQUENCE_FIELDS else value
|
|
102
|
-
)
|
|
121
|
+
merged[key] = _normalise_sequence(value) if key in _MERGED_SEQUENCE_FIELDS else value
|
|
103
122
|
return merged
|
|
104
123
|
|
|
105
124
|
|
|
@@ -134,9 +153,7 @@ def _prepare_agent_metadata(value: Any) -> dict[str, Any]:
|
|
|
134
153
|
return prepared
|
|
135
154
|
|
|
136
155
|
|
|
137
|
-
def _load_agent_file_payload(
|
|
138
|
-
file_path: Path, *, model_override: str | None
|
|
139
|
-
) -> dict[str, Any]:
|
|
156
|
+
def _load_agent_file_payload(file_path: Path, *, model_override: str | None) -> dict[str, Any]:
|
|
140
157
|
"""Load agent configuration from disk and normalise legacy fields."""
|
|
141
158
|
if not file_path.exists():
|
|
142
159
|
raise FileNotFoundError(f"Agent configuration file not found: {file_path}")
|
|
@@ -168,9 +185,7 @@ def _prepare_import_payload(
|
|
|
168
185
|
raw_definition = load_resource_from_file(file_path)
|
|
169
186
|
original_refs = _extract_original_refs(raw_definition)
|
|
170
187
|
|
|
171
|
-
base_payload = _load_agent_file_payload(
|
|
172
|
-
file_path, model_override=overrides_dict.get("model")
|
|
173
|
-
)
|
|
188
|
+
base_payload = _load_agent_file_payload(file_path, model_override=overrides_dict.get("model"))
|
|
174
189
|
|
|
175
190
|
cli_args = _build_cli_args(overrides_dict)
|
|
176
191
|
|
|
@@ -199,19 +214,7 @@ def _extract_original_refs(raw_definition: dict) -> dict[str, list]:
|
|
|
199
214
|
|
|
200
215
|
def _build_cli_args(overrides_dict: dict) -> dict[str, Any]:
|
|
201
216
|
"""Build CLI args from overrides, filtering out None values."""
|
|
202
|
-
cli_args = {
|
|
203
|
-
key: overrides_dict.get(key)
|
|
204
|
-
for key in (
|
|
205
|
-
"name",
|
|
206
|
-
"instruction",
|
|
207
|
-
"model",
|
|
208
|
-
"tools",
|
|
209
|
-
"agents",
|
|
210
|
-
"mcps",
|
|
211
|
-
"timeout",
|
|
212
|
-
)
|
|
213
|
-
if overrides_dict.get(key) is not None
|
|
214
|
-
}
|
|
217
|
+
cli_args = {key: overrides_dict.get(key) for key in AGENT_CONFIG_FIELDS if overrides_dict.get(key) is not None}
|
|
215
218
|
|
|
216
219
|
# Normalize sequence fields
|
|
217
220
|
for field in _MERGED_SEQUENCE_FIELDS:
|
|
@@ -223,11 +226,7 @@ def _build_cli_args(overrides_dict: dict) -> dict[str, Any]:
|
|
|
223
226
|
|
|
224
227
|
def _build_additional_args(overrides_dict: dict, cli_args: dict) -> dict[str, Any]:
|
|
225
228
|
"""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
|
-
}
|
|
229
|
+
return {key: value for key, value in overrides_dict.items() if value is not None and key not in cli_args}
|
|
231
230
|
|
|
232
231
|
|
|
233
232
|
def _remove_model_fields_if_needed(merged: dict, overrides_dict: dict) -> None:
|
|
@@ -264,6 +263,7 @@ class AgentClient(BaseClient):
|
|
|
264
263
|
self._renderer_manager = AgentRunRenderingManager(logger)
|
|
265
264
|
self._tool_client: ToolClient | None = None
|
|
266
265
|
self._mcp_client: MCPClient | None = None
|
|
266
|
+
self._runs_client: AgentRunsClient | None = None
|
|
267
267
|
|
|
268
268
|
def list_agents(
|
|
269
269
|
self,
|
|
@@ -278,9 +278,7 @@ class AgentClient(BaseClient):
|
|
|
278
278
|
"""
|
|
279
279
|
if query is not None and kwargs:
|
|
280
280
|
# Both query object and individual parameters provided
|
|
281
|
-
raise ValueError(
|
|
282
|
-
"Provide either `query` or individual filter arguments, not both."
|
|
283
|
-
)
|
|
281
|
+
raise ValueError("Provide either `query` or individual filter arguments, not both.")
|
|
284
282
|
|
|
285
283
|
if query is None:
|
|
286
284
|
# Create query from individual parameters for backward compatibility
|
|
@@ -339,7 +337,19 @@ class AgentClient(BaseClient):
|
|
|
339
337
|
|
|
340
338
|
def get_agent_by_id(self, agent_id: str) -> Agent:
|
|
341
339
|
"""Get agent by ID."""
|
|
342
|
-
|
|
340
|
+
try:
|
|
341
|
+
data = self._request("GET", f"/agents/{agent_id}")
|
|
342
|
+
except ValidationError as exc:
|
|
343
|
+
if exc.status_code == 422:
|
|
344
|
+
message = f"Agent '{agent_id}' not found"
|
|
345
|
+
raise NotFoundError(
|
|
346
|
+
message,
|
|
347
|
+
status_code=404,
|
|
348
|
+
error_type=exc.error_type,
|
|
349
|
+
payload=exc.payload,
|
|
350
|
+
request_id=exc.request_id,
|
|
351
|
+
) from exc
|
|
352
|
+
raise
|
|
343
353
|
|
|
344
354
|
if isinstance(data, str):
|
|
345
355
|
# Some backends may respond with plain text for missing agents.
|
|
@@ -352,7 +362,8 @@ class AgentClient(BaseClient):
|
|
|
352
362
|
status_code=404,
|
|
353
363
|
)
|
|
354
364
|
|
|
355
|
-
|
|
365
|
+
response = AgentResponse(**data)
|
|
366
|
+
return Agent.from_response(response, client=self)
|
|
356
367
|
|
|
357
368
|
def find_agents(self, name: str | None = None) -> list[Agent]:
|
|
358
369
|
"""Find agents by name."""
|
|
@@ -366,15 +377,27 @@ class AgentClient(BaseClient):
|
|
|
366
377
|
# Renderer delegation helpers
|
|
367
378
|
# ------------------------------------------------------------------ #
|
|
368
379
|
def _get_renderer_manager(self) -> AgentRunRenderingManager:
|
|
380
|
+
"""Get or create the renderer manager instance.
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
AgentRunRenderingManager instance.
|
|
384
|
+
"""
|
|
369
385
|
manager = getattr(self, "_renderer_manager", None)
|
|
370
386
|
if manager is None:
|
|
371
387
|
manager = AgentRunRenderingManager(logger)
|
|
372
388
|
self._renderer_manager = manager
|
|
373
389
|
return manager
|
|
374
390
|
|
|
375
|
-
def _create_renderer(
|
|
376
|
-
|
|
377
|
-
|
|
391
|
+
def _create_renderer(self, renderer: RichStreamRenderer | str | None, **kwargs: Any) -> RichStreamRenderer:
|
|
392
|
+
"""Create or return a renderer instance.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
renderer: Renderer instance, string identifier, or None.
|
|
396
|
+
**kwargs: Additional keyword arguments (e.g., verbose).
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
RichStreamRenderer instance.
|
|
400
|
+
"""
|
|
378
401
|
manager = self._get_renderer_manager()
|
|
379
402
|
verbose = kwargs.get("verbose", False)
|
|
380
403
|
if isinstance(renderer, RichStreamRenderer) or hasattr(renderer, "on_start"):
|
|
@@ -389,6 +412,18 @@ class AgentClient(BaseClient):
|
|
|
389
412
|
agent_name: str | None,
|
|
390
413
|
meta: dict[str, Any],
|
|
391
414
|
) -> tuple[str, dict[str, Any], float | None, float | None]:
|
|
415
|
+
"""Process stream events from an HTTP response.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
stream_response: HTTP response stream.
|
|
419
|
+
renderer: Renderer to use for displaying events.
|
|
420
|
+
timeout_seconds: Timeout in seconds.
|
|
421
|
+
agent_name: Optional agent name.
|
|
422
|
+
meta: Metadata dictionary.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Tuple of (final_text, stats_usage, started_monotonic, finished_monotonic).
|
|
426
|
+
"""
|
|
392
427
|
manager = self._get_renderer_manager()
|
|
393
428
|
return manager.process_stream_events(
|
|
394
429
|
stream_response,
|
|
@@ -406,6 +441,18 @@ class AgentClient(BaseClient):
|
|
|
406
441
|
started_monotonic: float | None,
|
|
407
442
|
finished_monotonic: float | None,
|
|
408
443
|
) -> str:
|
|
444
|
+
"""Finalize the renderer and return the final response text.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
renderer: Renderer to finalize.
|
|
448
|
+
final_text: Final text content.
|
|
449
|
+
stats_usage: Usage statistics dictionary.
|
|
450
|
+
started_monotonic: Start time (monotonic).
|
|
451
|
+
finished_monotonic: Finish time (monotonic).
|
|
452
|
+
|
|
453
|
+
Returns:
|
|
454
|
+
Final text string.
|
|
455
|
+
"""
|
|
409
456
|
manager = self._get_renderer_manager()
|
|
410
457
|
return manager.finalize_renderer(
|
|
411
458
|
renderer,
|
|
@@ -416,11 +463,21 @@ class AgentClient(BaseClient):
|
|
|
416
463
|
)
|
|
417
464
|
|
|
418
465
|
def _get_tool_client(self) -> ToolClient:
|
|
466
|
+
"""Get or create the tool client instance.
|
|
467
|
+
|
|
468
|
+
Returns:
|
|
469
|
+
ToolClient instance.
|
|
470
|
+
"""
|
|
419
471
|
if self._tool_client is None:
|
|
420
472
|
self._tool_client = ToolClient(parent_client=self)
|
|
421
473
|
return self._tool_client
|
|
422
474
|
|
|
423
475
|
def _get_mcp_client(self) -> MCPClient:
|
|
476
|
+
"""Get or create the MCP client instance.
|
|
477
|
+
|
|
478
|
+
Returns:
|
|
479
|
+
MCPClient instance.
|
|
480
|
+
"""
|
|
424
481
|
if self._mcp_client is None:
|
|
425
482
|
self._mcp_client = MCPClient(parent_client=self)
|
|
426
483
|
return self._mcp_client
|
|
@@ -430,6 +487,15 @@ class AgentClient(BaseClient):
|
|
|
430
487
|
entry: Any,
|
|
431
488
|
fallback_iter: Iterator[Any] | None,
|
|
432
489
|
) -> tuple[str | None, str | None]:
|
|
490
|
+
"""Normalize a reference entry to extract ID and name.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
entry: Reference entry (string, dict, or other).
|
|
494
|
+
fallback_iter: Optional iterator for fallback values.
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
Tuple of (entry_id, entry_name).
|
|
498
|
+
"""
|
|
433
499
|
entry_id: str | None = None
|
|
434
500
|
entry_name: str | None = None
|
|
435
501
|
|
|
@@ -466,6 +532,19 @@ class AgentClient(BaseClient):
|
|
|
466
532
|
label: str,
|
|
467
533
|
plural_label: str | None = None,
|
|
468
534
|
) -> list[str] | None:
|
|
535
|
+
"""Resolve a list of resource references to IDs.
|
|
536
|
+
|
|
537
|
+
Args:
|
|
538
|
+
items: List of resource references to resolve.
|
|
539
|
+
references: Optional list of reference objects for fallback.
|
|
540
|
+
fetch_by_id: Function to fetch resource by ID.
|
|
541
|
+
find_by_name: Function to find resources by name.
|
|
542
|
+
label: Singular label for error messages.
|
|
543
|
+
plural_label: Plural label for error messages.
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
List of resolved resource IDs, or None if items is empty.
|
|
547
|
+
"""
|
|
469
548
|
if not items:
|
|
470
549
|
return None
|
|
471
550
|
|
|
@@ -497,6 +576,22 @@ class AgentClient(BaseClient):
|
|
|
497
576
|
singular: str,
|
|
498
577
|
plural: str,
|
|
499
578
|
) -> str:
|
|
579
|
+
"""Resolve a single resource reference to an ID.
|
|
580
|
+
|
|
581
|
+
Args:
|
|
582
|
+
entry: Resource reference to resolve.
|
|
583
|
+
fallback_iter: Optional iterator for fallback values.
|
|
584
|
+
fetch_by_id: Function to fetch resource by ID.
|
|
585
|
+
find_by_name: Function to find resources by name.
|
|
586
|
+
singular: Singular label for error messages.
|
|
587
|
+
plural: Plural label for error messages.
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
Resolved resource ID string.
|
|
591
|
+
|
|
592
|
+
Raises:
|
|
593
|
+
ValueError: If the resource cannot be resolved.
|
|
594
|
+
"""
|
|
500
595
|
entry_id, entry_name = self._normalise_reference_entry(entry, fallback_iter)
|
|
501
596
|
|
|
502
597
|
validated_id = self._validate_resource_id(fetch_by_id, entry_id)
|
|
@@ -506,15 +601,21 @@ class AgentClient(BaseClient):
|
|
|
506
601
|
return entry_id
|
|
507
602
|
|
|
508
603
|
if entry_name:
|
|
509
|
-
resolved, success = self._resolve_resource_by_name(
|
|
510
|
-
find_by_name, entry_name, singular, plural
|
|
511
|
-
)
|
|
604
|
+
resolved, success = self._resolve_resource_by_name(find_by_name, entry_name, singular, plural)
|
|
512
605
|
return resolved if success else entry_name
|
|
513
606
|
|
|
514
607
|
raise ValueError(f"{singular} references must include a valid ID or name.")
|
|
515
608
|
|
|
516
609
|
@staticmethod
|
|
517
610
|
def _coerce_reference_value(entry: Any) -> str:
|
|
611
|
+
"""Coerce a reference entry to a string value.
|
|
612
|
+
|
|
613
|
+
Args:
|
|
614
|
+
entry: Reference entry (dict, string, or other).
|
|
615
|
+
|
|
616
|
+
Returns:
|
|
617
|
+
String representation of the reference.
|
|
618
|
+
"""
|
|
518
619
|
if isinstance(entry, dict):
|
|
519
620
|
if entry.get("id"):
|
|
520
621
|
return str(entry["id"])
|
|
@@ -523,9 +624,16 @@ class AgentClient(BaseClient):
|
|
|
523
624
|
return str(entry)
|
|
524
625
|
|
|
525
626
|
@staticmethod
|
|
526
|
-
def _validate_resource_id(
|
|
527
|
-
|
|
528
|
-
|
|
627
|
+
def _validate_resource_id(fetch_by_id: Callable[[str], Any], candidate_id: str | None) -> str | None:
|
|
628
|
+
"""Validate a resource ID by attempting to fetch it.
|
|
629
|
+
|
|
630
|
+
Args:
|
|
631
|
+
fetch_by_id: Function to fetch resource by ID.
|
|
632
|
+
candidate_id: Candidate ID to validate.
|
|
633
|
+
|
|
634
|
+
Returns:
|
|
635
|
+
Validated ID if found, None otherwise.
|
|
636
|
+
"""
|
|
529
637
|
if not candidate_id:
|
|
530
638
|
return None
|
|
531
639
|
try:
|
|
@@ -541,27 +649,33 @@ class AgentClient(BaseClient):
|
|
|
541
649
|
singular: str,
|
|
542
650
|
plural: str,
|
|
543
651
|
) -> tuple[str, bool]:
|
|
652
|
+
"""Resolve a resource by name to an ID.
|
|
653
|
+
|
|
654
|
+
Args:
|
|
655
|
+
find_by_name: Function to find resources by name.
|
|
656
|
+
entry_name: Name of the resource to find.
|
|
657
|
+
singular: Singular label for error messages.
|
|
658
|
+
plural: Plural label for error messages.
|
|
659
|
+
|
|
660
|
+
Returns:
|
|
661
|
+
Tuple of (resolved_id, success).
|
|
662
|
+
|
|
663
|
+
Raises:
|
|
664
|
+
ValueError: If resource not found or multiple matches exist.
|
|
665
|
+
"""
|
|
544
666
|
try:
|
|
545
667
|
matches = find_by_name(entry_name)
|
|
546
668
|
except Exception:
|
|
547
669
|
return entry_name, False
|
|
548
670
|
|
|
549
671
|
if not matches:
|
|
550
|
-
raise ValueError(
|
|
551
|
-
f"{singular} '{entry_name}' not found in current workspace."
|
|
552
|
-
)
|
|
672
|
+
raise ValueError(f"{singular} '{entry_name}' not found in current workspace.")
|
|
553
673
|
if len(matches) > 1:
|
|
554
|
-
exact = [
|
|
555
|
-
m
|
|
556
|
-
for m in matches
|
|
557
|
-
if getattr(m, "name", "").lower() == entry_name.lower()
|
|
558
|
-
]
|
|
674
|
+
exact = [m for m in matches if getattr(m, "name", "").lower() == entry_name.lower()]
|
|
559
675
|
if len(exact) == 1:
|
|
560
676
|
matches = exact
|
|
561
677
|
else:
|
|
562
|
-
raise ValueError(
|
|
563
|
-
f"Multiple {plural} named '{entry_name}'. Please disambiguate."
|
|
564
|
-
)
|
|
678
|
+
raise ValueError(f"Multiple {plural} named '{entry_name}'. Please disambiguate.")
|
|
565
679
|
return str(matches[0].id), True
|
|
566
680
|
|
|
567
681
|
def _resolve_tool_ids(
|
|
@@ -569,6 +683,15 @@ class AgentClient(BaseClient):
|
|
|
569
683
|
tools: list[Any] | None,
|
|
570
684
|
references: list[Any] | None = None,
|
|
571
685
|
) -> list[str] | None:
|
|
686
|
+
"""Resolve tool references to IDs.
|
|
687
|
+
|
|
688
|
+
Args:
|
|
689
|
+
tools: List of tool references to resolve.
|
|
690
|
+
references: Optional list of reference objects for fallback.
|
|
691
|
+
|
|
692
|
+
Returns:
|
|
693
|
+
List of resolved tool IDs, or None if tools is empty.
|
|
694
|
+
"""
|
|
572
695
|
tool_client = self._get_tool_client()
|
|
573
696
|
return self._resolve_resource_ids(
|
|
574
697
|
tools,
|
|
@@ -584,6 +707,15 @@ class AgentClient(BaseClient):
|
|
|
584
707
|
agents: list[Any] | None,
|
|
585
708
|
references: list[Any] | None = None,
|
|
586
709
|
) -> list[str] | None:
|
|
710
|
+
"""Resolve agent references to IDs.
|
|
711
|
+
|
|
712
|
+
Args:
|
|
713
|
+
agents: List of agent references to resolve.
|
|
714
|
+
references: Optional list of reference objects for fallback.
|
|
715
|
+
|
|
716
|
+
Returns:
|
|
717
|
+
List of resolved agent IDs, or None if agents is empty.
|
|
718
|
+
"""
|
|
587
719
|
return self._resolve_resource_ids(
|
|
588
720
|
agents,
|
|
589
721
|
references,
|
|
@@ -598,6 +730,15 @@ class AgentClient(BaseClient):
|
|
|
598
730
|
mcps: list[Any] | None,
|
|
599
731
|
references: list[Any] | None = None,
|
|
600
732
|
) -> list[str] | None:
|
|
733
|
+
"""Resolve MCP references to IDs.
|
|
734
|
+
|
|
735
|
+
Args:
|
|
736
|
+
mcps: List of MCP references to resolve.
|
|
737
|
+
references: Optional list of reference objects for fallback.
|
|
738
|
+
|
|
739
|
+
Returns:
|
|
740
|
+
List of resolved MCP IDs, or None if mcps is empty.
|
|
741
|
+
"""
|
|
601
742
|
mcp_client = self._get_mcp_client()
|
|
602
743
|
return self._resolve_resource_ids(
|
|
603
744
|
mcps,
|
|
@@ -610,9 +751,7 @@ class AgentClient(BaseClient):
|
|
|
610
751
|
|
|
611
752
|
def _create_agent_from_payload(self, payload: Mapping[str, Any]) -> "Agent":
|
|
612
753
|
"""Create an agent using a fully prepared payload mapping."""
|
|
613
|
-
known, extras = _split_known_and_extra(
|
|
614
|
-
payload, AgentCreateRequest.__dataclass_fields__
|
|
615
|
-
)
|
|
754
|
+
known, extras = _split_known_and_extra(payload, AgentCreateRequest.__dataclass_fields__)
|
|
616
755
|
|
|
617
756
|
name = known.pop("name", None)
|
|
618
757
|
instruction = known.pop("instruction", None)
|
|
@@ -691,7 +830,8 @@ class AgentClient(BaseClient):
|
|
|
691
830
|
get_endpoint_fmt=f"{AGENTS_ENDPOINT}{{id}}",
|
|
692
831
|
json=payload_dict,
|
|
693
832
|
)
|
|
694
|
-
|
|
833
|
+
response = AgentResponse(**full_agent_data)
|
|
834
|
+
return Agent.from_response(response, client=self)
|
|
695
835
|
|
|
696
836
|
def create_agent(
|
|
697
837
|
self,
|
|
@@ -721,9 +861,7 @@ class AgentClient(BaseClient):
|
|
|
721
861
|
overrides = _merge_override_maps(base_overrides, kwargs)
|
|
722
862
|
|
|
723
863
|
if file is not None:
|
|
724
|
-
payload = _prepare_import_payload(
|
|
725
|
-
Path(file).expanduser(), overrides, drop_model_fields=True
|
|
726
|
-
)
|
|
864
|
+
payload = _prepare_import_payload(Path(file).expanduser(), overrides, drop_model_fields=True)
|
|
727
865
|
if overrides.get("model") is None:
|
|
728
866
|
payload.pop("model", None)
|
|
729
867
|
else:
|
|
@@ -746,9 +884,7 @@ class AgentClient(BaseClient):
|
|
|
746
884
|
payload: Mapping[str, Any],
|
|
747
885
|
) -> "Agent":
|
|
748
886
|
"""Update an agent using a prepared payload mapping."""
|
|
749
|
-
known, extras = _split_known_and_extra(
|
|
750
|
-
payload, AgentUpdateRequest.__dataclass_fields__
|
|
751
|
-
)
|
|
887
|
+
known, extras = _split_known_and_extra(payload, AgentUpdateRequest.__dataclass_fields__)
|
|
752
888
|
_normalise_sequence_fields(known)
|
|
753
889
|
|
|
754
890
|
tool_refs = extras.pop("_tool_refs", None)
|
|
@@ -790,8 +926,9 @@ class AgentClient(BaseClient):
|
|
|
790
926
|
|
|
791
927
|
payload_dict = request.to_payload(current_agent)
|
|
792
928
|
|
|
793
|
-
|
|
794
|
-
|
|
929
|
+
api_response = self._request("PUT", f"/agents/{agent_id}", json=payload_dict)
|
|
930
|
+
response = AgentResponse(**api_response)
|
|
931
|
+
return Agent.from_response(response, client=self)
|
|
795
932
|
|
|
796
933
|
def update_agent(
|
|
797
934
|
self,
|
|
@@ -818,9 +955,7 @@ class AgentClient(BaseClient):
|
|
|
818
955
|
overrides = _merge_override_maps(base_overrides, kwargs)
|
|
819
956
|
|
|
820
957
|
if file is not None:
|
|
821
|
-
payload = _prepare_import_payload(
|
|
822
|
-
Path(file).expanduser(), overrides, drop_model_fields=True
|
|
823
|
-
)
|
|
958
|
+
payload = _prepare_import_payload(Path(file).expanduser(), overrides, drop_model_fields=True)
|
|
824
959
|
else:
|
|
825
960
|
payload = overrides
|
|
826
961
|
|
|
@@ -840,6 +975,62 @@ class AgentClient(BaseClient):
|
|
|
840
975
|
"""Delete an agent."""
|
|
841
976
|
self._request("DELETE", f"/agents/{agent_id}")
|
|
842
977
|
|
|
978
|
+
def upsert_agent(self, identifier: str | Agent, **kwargs) -> Agent:
|
|
979
|
+
"""Create or update an agent by instance, ID, or name.
|
|
980
|
+
|
|
981
|
+
Args:
|
|
982
|
+
identifier: Agent instance, ID (UUID string), or name
|
|
983
|
+
**kwargs: Agent configuration (instruction, description, tools, etc.)
|
|
984
|
+
|
|
985
|
+
Returns:
|
|
986
|
+
The created or updated agent.
|
|
987
|
+
|
|
988
|
+
Example:
|
|
989
|
+
>>> # By name (creates if not exists)
|
|
990
|
+
>>> agent = client.agents.upsert_agent(
|
|
991
|
+
... "hello_agent",
|
|
992
|
+
... instruction="You are a helpful assistant.",
|
|
993
|
+
... description="A friendly agent",
|
|
994
|
+
... )
|
|
995
|
+
>>> # By instance
|
|
996
|
+
>>> agent = client.agents.upsert_agent(existing_agent, description="Updated")
|
|
997
|
+
>>> # By ID
|
|
998
|
+
>>> agent = client.agents.upsert_agent("uuid-here", description="Updated")
|
|
999
|
+
"""
|
|
1000
|
+
# Handle Agent instance
|
|
1001
|
+
if isinstance(identifier, Agent):
|
|
1002
|
+
if identifier.id:
|
|
1003
|
+
logger.info("Updating agent by instance: %s", identifier.name)
|
|
1004
|
+
return self.update_agent(identifier.id, name=identifier.name, **kwargs)
|
|
1005
|
+
identifier = identifier.name
|
|
1006
|
+
|
|
1007
|
+
# Handle string (ID or name)
|
|
1008
|
+
if isinstance(identifier, str):
|
|
1009
|
+
# Check if it's a UUID
|
|
1010
|
+
if is_uuid(identifier):
|
|
1011
|
+
logger.info("Updating agent by ID: %s", identifier)
|
|
1012
|
+
return self.update_agent(identifier, **kwargs)
|
|
1013
|
+
|
|
1014
|
+
# It's a name - find or create
|
|
1015
|
+
return self._upsert_agent_by_name(identifier, **kwargs)
|
|
1016
|
+
|
|
1017
|
+
raise ValueError(f"Invalid identifier type: {type(identifier)}")
|
|
1018
|
+
|
|
1019
|
+
def _upsert_agent_by_name(self, name: str, **kwargs) -> Agent:
|
|
1020
|
+
"""Find agent by name and update, or create if not found."""
|
|
1021
|
+
existing = self.find_agents(name)
|
|
1022
|
+
|
|
1023
|
+
if len(existing) == 1:
|
|
1024
|
+
logger.info("Updating existing agent: %s", name)
|
|
1025
|
+
return self.update_agent(existing[0].id, name=name, **kwargs)
|
|
1026
|
+
|
|
1027
|
+
if len(existing) > 1:
|
|
1028
|
+
raise ValueError(f"Multiple agents found with name '{name}'")
|
|
1029
|
+
|
|
1030
|
+
# Create new agent
|
|
1031
|
+
logger.info("Creating new agent: %s", name)
|
|
1032
|
+
return self.create_agent(name=name, **kwargs)
|
|
1033
|
+
|
|
843
1034
|
def _prepare_sync_request_data(
|
|
844
1035
|
self,
|
|
845
1036
|
message: str,
|
|
@@ -882,9 +1073,7 @@ class AgentClient(BaseClient):
|
|
|
882
1073
|
payload["tty"] = True
|
|
883
1074
|
return payload, None, None, headers, None
|
|
884
1075
|
|
|
885
|
-
def _get_timeout_values(
|
|
886
|
-
self, timeout: float | None, **kwargs: Any
|
|
887
|
-
) -> tuple[float, float]:
|
|
1076
|
+
def _get_timeout_values(self, timeout: float | None, **kwargs: Any) -> tuple[float, float]:
|
|
888
1077
|
"""Get request timeout and execution timeout values.
|
|
889
1078
|
|
|
890
1079
|
Args:
|
|
@@ -906,9 +1095,32 @@ class AgentClient(BaseClient):
|
|
|
906
1095
|
tty: bool = False,
|
|
907
1096
|
*,
|
|
908
1097
|
renderer: RichStreamRenderer | str | None = "auto",
|
|
1098
|
+
runtime_config: dict[str, Any] | None = None,
|
|
909
1099
|
**kwargs,
|
|
910
1100
|
) -> str:
|
|
911
|
-
"""Run an agent with a message, streaming via a renderer.
|
|
1101
|
+
"""Run an agent with a message, streaming via a renderer.
|
|
1102
|
+
|
|
1103
|
+
Args:
|
|
1104
|
+
agent_id: The ID of the agent to run.
|
|
1105
|
+
message: The message to send to the agent.
|
|
1106
|
+
files: Optional list of files to include with the request.
|
|
1107
|
+
tty: Whether to enable TTY mode.
|
|
1108
|
+
renderer: Renderer for streaming output.
|
|
1109
|
+
runtime_config: Optional runtime configuration for tools, MCPs, and agents.
|
|
1110
|
+
Keys should be platform IDs. Example:
|
|
1111
|
+
{
|
|
1112
|
+
"tool_configs": {"tool-id": {"param": "value"}},
|
|
1113
|
+
"mcp_configs": {"mcp-id": {"setting": "on"}},
|
|
1114
|
+
"agent_config": {"planning": True},
|
|
1115
|
+
}
|
|
1116
|
+
**kwargs: Additional arguments to pass to the run API.
|
|
1117
|
+
|
|
1118
|
+
Returns:
|
|
1119
|
+
The agent's response as a string.
|
|
1120
|
+
"""
|
|
1121
|
+
# Include runtime_config in kwargs only when caller hasn't already provided it
|
|
1122
|
+
if runtime_config is not None and "runtime_config" not in kwargs:
|
|
1123
|
+
kwargs["runtime_config"] = runtime_config
|
|
912
1124
|
(
|
|
913
1125
|
payload,
|
|
914
1126
|
data_payload,
|
|
@@ -1009,9 +1221,7 @@ class AgentClient(BaseClient):
|
|
|
1009
1221
|
headers = {"Accept": SSE_CONTENT_TYPE}
|
|
1010
1222
|
return payload, None, None, headers
|
|
1011
1223
|
|
|
1012
|
-
def _create_async_client_config(
|
|
1013
|
-
self, timeout: float | None, headers: dict | None
|
|
1014
|
-
) -> dict:
|
|
1224
|
+
def _create_async_client_config(self, timeout: float | None, headers: dict | None) -> dict:
|
|
1015
1225
|
"""Create async client configuration with proper headers and timeout."""
|
|
1016
1226
|
config = self._build_async_client(timeout or self.timeout)
|
|
1017
1227
|
if headers:
|
|
@@ -1040,9 +1250,7 @@ class AgentClient(BaseClient):
|
|
|
1040
1250
|
) as stream_response:
|
|
1041
1251
|
stream_response.raise_for_status()
|
|
1042
1252
|
|
|
1043
|
-
async for event in aiter_sse_events(
|
|
1044
|
-
stream_response, timeout_seconds, agent_name
|
|
1045
|
-
):
|
|
1253
|
+
async for event in aiter_sse_events(stream_response, timeout_seconds, agent_name):
|
|
1046
1254
|
try:
|
|
1047
1255
|
chunk = json.loads(event["data"])
|
|
1048
1256
|
yield chunk
|
|
@@ -1056,7 +1264,8 @@ class AgentClient(BaseClient):
|
|
|
1056
1264
|
message: str,
|
|
1057
1265
|
files: list[str | BinaryIO] | None = None,
|
|
1058
1266
|
*,
|
|
1059
|
-
|
|
1267
|
+
request_timeout: float | None = None,
|
|
1268
|
+
runtime_config: dict[str, Any] | None = None,
|
|
1060
1269
|
**kwargs,
|
|
1061
1270
|
) -> AsyncGenerator[dict, None]:
|
|
1062
1271
|
"""Async run an agent with a message, yielding streaming JSON chunks.
|
|
@@ -1065,7 +1274,14 @@ class AgentClient(BaseClient):
|
|
|
1065
1274
|
agent_id: ID of the agent to run
|
|
1066
1275
|
message: Message to send to the agent
|
|
1067
1276
|
files: Optional list of files to include
|
|
1068
|
-
|
|
1277
|
+
request_timeout: Optional request timeout in seconds (defaults to client timeout)
|
|
1278
|
+
runtime_config: Optional runtime configuration for tools, MCPs, and agents.
|
|
1279
|
+
Keys should be platform IDs. Example:
|
|
1280
|
+
{
|
|
1281
|
+
"tool_configs": {"tool-id": {"param": "value"}},
|
|
1282
|
+
"mcp_configs": {"mcp-id": {"setting": "on"}},
|
|
1283
|
+
"agent_config": {"planning": True},
|
|
1284
|
+
}
|
|
1069
1285
|
**kwargs: Additional arguments (chat_history, pii_mapping, etc.)
|
|
1070
1286
|
|
|
1071
1287
|
Yields:
|
|
@@ -1076,20 +1292,25 @@ class AgentClient(BaseClient):
|
|
|
1076
1292
|
httpx.TimeoutException: When general timeout occurs
|
|
1077
1293
|
Exception: For other unexpected errors
|
|
1078
1294
|
"""
|
|
1295
|
+
# Include runtime_config in kwargs only when caller hasn't already provided it
|
|
1296
|
+
if runtime_config is not None and "runtime_config" not in kwargs:
|
|
1297
|
+
kwargs["runtime_config"] = runtime_config
|
|
1298
|
+
# Derive timeout values for request/control flow
|
|
1299
|
+
legacy_timeout = kwargs.get("timeout")
|
|
1300
|
+
http_timeout_override = request_timeout if request_timeout is not None else legacy_timeout
|
|
1301
|
+
http_timeout = http_timeout_override or self.timeout
|
|
1302
|
+
|
|
1079
1303
|
# Prepare request data
|
|
1080
|
-
payload, data_payload, files_payload, headers = self._prepare_request_data(
|
|
1081
|
-
message, files, **kwargs
|
|
1082
|
-
)
|
|
1304
|
+
payload, data_payload, files_payload, headers = self._prepare_request_data(message, files, **kwargs)
|
|
1083
1305
|
|
|
1084
1306
|
# Create async client configuration
|
|
1085
|
-
async_client_config = self._create_async_client_config(
|
|
1307
|
+
async_client_config = self._create_async_client_config(http_timeout_override, headers)
|
|
1086
1308
|
|
|
1087
1309
|
# Get execution timeout for streaming control
|
|
1088
1310
|
timeout_seconds = kwargs.get("timeout", DEFAULT_AGENT_RUN_TIMEOUT)
|
|
1089
1311
|
agent_name = kwargs.get("agent_name")
|
|
1090
1312
|
|
|
1091
|
-
|
|
1092
|
-
# Create async client and stream response
|
|
1313
|
+
async def _chunk_stream() -> AsyncGenerator[dict, None]:
|
|
1093
1314
|
async with httpx.AsyncClient(**async_client_config) as async_client:
|
|
1094
1315
|
async for chunk in self._stream_agent_response(
|
|
1095
1316
|
async_client,
|
|
@@ -1103,7 +1324,14 @@ class AgentClient(BaseClient):
|
|
|
1103
1324
|
):
|
|
1104
1325
|
yield chunk
|
|
1105
1326
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1327
|
+
async with _async_timeout_guard(http_timeout):
|
|
1328
|
+
async for chunk in _chunk_stream():
|
|
1329
|
+
yield chunk
|
|
1330
|
+
|
|
1331
|
+
@property
|
|
1332
|
+
def runs(self) -> "AgentRunsClient":
|
|
1333
|
+
"""Get the agent runs client."""
|
|
1334
|
+
if self._runs_client is None:
|
|
1335
|
+
shared_config = build_shared_config(self)
|
|
1336
|
+
self._runs_client = AgentRunsClient(**shared_config)
|
|
1337
|
+
return self._runs_client
|