glaip-sdk 0.6.10__py3-none-any.whl → 0.7.27__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 +42 -5
- glaip_sdk/agents/base.py +295 -37
- glaip_sdk/agents/component.py +233 -0
- glaip_sdk/branding.py +113 -2
- glaip_sdk/cli/account_store.py +15 -0
- glaip_sdk/cli/auth.py +14 -8
- glaip_sdk/cli/commands/accounts.py +1 -1
- glaip_sdk/cli/commands/agents/__init__.py +116 -0
- glaip_sdk/cli/commands/agents/_common.py +562 -0
- glaip_sdk/cli/commands/agents/create.py +155 -0
- glaip_sdk/cli/commands/agents/delete.py +64 -0
- glaip_sdk/cli/commands/agents/get.py +89 -0
- glaip_sdk/cli/commands/agents/list.py +129 -0
- glaip_sdk/cli/commands/agents/run.py +264 -0
- glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
- glaip_sdk/cli/commands/agents/update.py +112 -0
- glaip_sdk/cli/commands/common_config.py +15 -12
- glaip_sdk/cli/commands/configure.py +1 -2
- glaip_sdk/cli/commands/mcps/__init__.py +94 -0
- glaip_sdk/cli/commands/mcps/_common.py +459 -0
- glaip_sdk/cli/commands/mcps/connect.py +82 -0
- glaip_sdk/cli/commands/mcps/create.py +152 -0
- glaip_sdk/cli/commands/mcps/delete.py +73 -0
- glaip_sdk/cli/commands/mcps/get.py +212 -0
- glaip_sdk/cli/commands/mcps/list.py +69 -0
- glaip_sdk/cli/commands/mcps/tools.py +235 -0
- glaip_sdk/cli/commands/mcps/update.py +190 -0
- glaip_sdk/cli/commands/models.py +2 -4
- glaip_sdk/cli/commands/shared/__init__.py +21 -0
- glaip_sdk/cli/commands/shared/formatters.py +91 -0
- glaip_sdk/cli/commands/tools/__init__.py +69 -0
- glaip_sdk/cli/commands/tools/_common.py +80 -0
- glaip_sdk/cli/commands/tools/create.py +228 -0
- glaip_sdk/cli/commands/tools/delete.py +61 -0
- glaip_sdk/cli/commands/tools/get.py +103 -0
- glaip_sdk/cli/commands/tools/list.py +69 -0
- glaip_sdk/cli/commands/tools/script.py +49 -0
- glaip_sdk/cli/commands/tools/update.py +102 -0
- glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
- glaip_sdk/cli/commands/transcripts/_common.py +9 -0
- glaip_sdk/cli/commands/transcripts/clear.py +5 -0
- glaip_sdk/cli/commands/transcripts/detail.py +5 -0
- glaip_sdk/cli/commands/{transcripts.py → transcripts_original.py} +2 -1
- glaip_sdk/cli/commands/update.py +163 -17
- glaip_sdk/cli/config.py +1 -0
- glaip_sdk/cli/core/output.py +12 -7
- glaip_sdk/cli/entrypoint.py +20 -0
- glaip_sdk/cli/main.py +127 -39
- glaip_sdk/cli/pager.py +3 -3
- glaip_sdk/cli/resolution.py +2 -1
- glaip_sdk/cli/slash/accounts_controller.py +3 -1
- glaip_sdk/cli/slash/agent_session.py +1 -1
- glaip_sdk/cli/slash/remote_runs_controller.py +3 -1
- glaip_sdk/cli/slash/session.py +343 -20
- glaip_sdk/cli/slash/tui/__init__.py +29 -1
- glaip_sdk/cli/slash/tui/accounts.tcss +97 -6
- glaip_sdk/cli/slash/tui/accounts_app.py +1117 -126
- glaip_sdk/cli/slash/tui/clipboard.py +316 -0
- glaip_sdk/cli/slash/tui/context.py +92 -0
- glaip_sdk/cli/slash/tui/indicators.py +341 -0
- glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
- glaip_sdk/cli/slash/tui/layouts/__init__.py +14 -0
- glaip_sdk/cli/slash/tui/layouts/harlequin.py +184 -0
- glaip_sdk/cli/slash/tui/loading.py +43 -21
- glaip_sdk/cli/slash/tui/remote_runs_app.py +178 -20
- glaip_sdk/cli/slash/tui/terminal.py +407 -0
- glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
- glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
- glaip_sdk/cli/slash/tui/theme/manager.py +112 -0
- glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
- glaip_sdk/cli/slash/tui/toast.py +388 -0
- glaip_sdk/cli/transcript/history.py +1 -1
- glaip_sdk/cli/transcript/viewer.py +1 -1
- glaip_sdk/cli/tui_settings.py +125 -0
- glaip_sdk/cli/update_notifier.py +215 -7
- glaip_sdk/cli/validators.py +1 -1
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_schedule_payloads.py +89 -0
- glaip_sdk/client/agents.py +290 -16
- glaip_sdk/client/base.py +25 -0
- glaip_sdk/client/hitl.py +136 -0
- glaip_sdk/client/main.py +7 -5
- glaip_sdk/client/mcps.py +44 -13
- glaip_sdk/client/payloads/agent/__init__.py +23 -0
- glaip_sdk/client/{_agent_payloads.py → payloads/agent/requests.py} +28 -48
- glaip_sdk/client/payloads/agent/responses.py +43 -0
- glaip_sdk/client/run_rendering.py +414 -3
- glaip_sdk/client/schedules.py +439 -0
- glaip_sdk/client/tools.py +52 -23
- glaip_sdk/config/constants.py +22 -2
- glaip_sdk/guardrails/__init__.py +80 -0
- glaip_sdk/guardrails/serializer.py +91 -0
- glaip_sdk/hitl/__init__.py +48 -0
- glaip_sdk/hitl/base.py +64 -0
- glaip_sdk/hitl/callback.py +43 -0
- glaip_sdk/hitl/local.py +121 -0
- glaip_sdk/hitl/remote.py +523 -0
- glaip_sdk/models/__init__.py +47 -1
- glaip_sdk/models/_provider_mappings.py +101 -0
- glaip_sdk/models/_validation.py +97 -0
- glaip_sdk/models/agent.py +2 -1
- glaip_sdk/models/agent_runs.py +2 -1
- glaip_sdk/models/constants.py +141 -0
- glaip_sdk/models/model.py +170 -0
- glaip_sdk/models/schedule.py +224 -0
- glaip_sdk/payload_schemas/agent.py +1 -0
- glaip_sdk/payload_schemas/guardrails.py +34 -0
- glaip_sdk/ptc.py +145 -0
- glaip_sdk/registry/tool.py +270 -57
- glaip_sdk/runner/__init__.py +20 -3
- glaip_sdk/runner/deps.py +6 -6
- glaip_sdk/runner/langgraph.py +427 -39
- glaip_sdk/runner/logging_config.py +77 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +30 -9
- glaip_sdk/runner/ptc_adapter.py +98 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +25 -2
- glaip_sdk/schedules/__init__.py +22 -0
- glaip_sdk/schedules/base.py +291 -0
- glaip_sdk/tools/base.py +67 -14
- glaip_sdk/utils/__init__.py +1 -0
- glaip_sdk/utils/agent_config.py +8 -2
- glaip_sdk/utils/bundler.py +138 -2
- glaip_sdk/utils/import_resolver.py +427 -49
- glaip_sdk/utils/rendering/renderer/base.py +58 -0
- glaip_sdk/utils/runtime_config.py +3 -2
- glaip_sdk/utils/sync.py +31 -11
- glaip_sdk/utils/tool_detection.py +274 -6
- glaip_sdk/utils/tool_storage_provider.py +140 -0
- {glaip_sdk-0.6.10.dist-info → glaip_sdk-0.7.27.dist-info}/METADATA +51 -40
- glaip_sdk-0.7.27.dist-info/RECORD +227 -0
- {glaip_sdk-0.6.10.dist-info → glaip_sdk-0.7.27.dist-info}/WHEEL +2 -1
- glaip_sdk-0.7.27.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.7.27.dist-info/top_level.txt +1 -0
- glaip_sdk/cli/commands/agents.py +0 -1509
- glaip_sdk/cli/commands/mcps.py +0 -1356
- glaip_sdk/cli/commands/tools.py +0 -576
- glaip_sdk/cli/utils.py +0 -263
- glaip_sdk-0.6.10.dist-info/RECORD +0 -159
- glaip_sdk-0.6.10.dist-info/entry_points.txt +0 -3
glaip_sdk/__init__.py
CHANGED
|
@@ -4,12 +4,49 @@ Authors:
|
|
|
4
4
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import importlib
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
7
12
|
from glaip_sdk._version import __version__
|
|
8
|
-
from glaip_sdk.client import Client
|
|
9
|
-
from glaip_sdk.exceptions import AIPError
|
|
10
|
-
from glaip_sdk.agents import Agent
|
|
11
|
-
from glaip_sdk.tools import Tool
|
|
12
|
-
from glaip_sdk.mcps import MCP
|
|
13
13
|
|
|
14
|
+
if TYPE_CHECKING: # pragma: no cover - import only for type checking
|
|
15
|
+
from glaip_sdk.agents import Agent
|
|
16
|
+
from glaip_sdk.client import Client
|
|
17
|
+
from glaip_sdk.exceptions import AIPError
|
|
18
|
+
from glaip_sdk.mcps import MCP
|
|
19
|
+
from glaip_sdk.tools import Tool
|
|
14
20
|
|
|
15
21
|
__all__ = ["Client", "Agent", "Tool", "MCP", "AIPError", "__version__"]
|
|
22
|
+
|
|
23
|
+
_LAZY_IMPORTS: dict[str, tuple[str, str]] = {
|
|
24
|
+
"Client": ("glaip_sdk.client", "Client"),
|
|
25
|
+
"Agent": ("glaip_sdk.agents", "Agent"),
|
|
26
|
+
"Tool": ("glaip_sdk.tools", "Tool"),
|
|
27
|
+
"MCP": ("glaip_sdk.mcps", "MCP"),
|
|
28
|
+
"AIPError": ("glaip_sdk.exceptions", "AIPError"),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def __getattr__(name: str) -> Any:
|
|
33
|
+
"""Lazy attribute access for public SDK symbols to defer heavy imports."""
|
|
34
|
+
if name == "__version__":
|
|
35
|
+
# Import __version__ when accessed via __getattr__
|
|
36
|
+
# This ensures coverage even if __version__ was removed from __dict__ for testing
|
|
37
|
+
from glaip_sdk._version import __version__ as version # noqa: PLC0415
|
|
38
|
+
|
|
39
|
+
globals()["__version__"] = version
|
|
40
|
+
return version
|
|
41
|
+
if name in _LAZY_IMPORTS:
|
|
42
|
+
module_path, attr_name = _LAZY_IMPORTS[name]
|
|
43
|
+
module = importlib.import_module(module_path)
|
|
44
|
+
attr = getattr(module, attr_name)
|
|
45
|
+
globals()[name] = attr
|
|
46
|
+
return attr
|
|
47
|
+
raise AttributeError(f"module 'glaip_sdk' has no attribute {name!r}")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def __dir__() -> list[str]:
|
|
51
|
+
"""Return module attributes for dir()."""
|
|
52
|
+
return sorted(__all__)
|
glaip_sdk/agents/base.py
CHANGED
|
@@ -46,25 +46,22 @@ import inspect
|
|
|
46
46
|
import logging
|
|
47
47
|
import warnings
|
|
48
48
|
from collections.abc import AsyncGenerator
|
|
49
|
-
|
|
50
|
-
|
|
51
49
|
from pathlib import Path
|
|
52
50
|
from typing import TYPE_CHECKING, Any
|
|
53
51
|
|
|
54
52
|
from glaip_sdk.registry import get_agent_registry, get_mcp_registry, get_tool_registry
|
|
55
|
-
from glaip_sdk.runner import get_default_runner
|
|
56
|
-
from glaip_sdk.runner.deps import (
|
|
57
|
-
check_local_runtime_available,
|
|
58
|
-
get_local_runtime_missing_message,
|
|
59
|
-
)
|
|
60
|
-
from glaip_sdk.utils.discovery import find_agent
|
|
61
53
|
from glaip_sdk.utils.resource_refs import is_uuid
|
|
62
|
-
from glaip_sdk.utils.runtime_config import normalize_runtime_config_keys
|
|
63
54
|
|
|
64
55
|
if TYPE_CHECKING:
|
|
65
|
-
from glaip_sdk.
|
|
56
|
+
from glaip_sdk.client.schedules import AgentScheduleManager
|
|
57
|
+
from glaip_sdk.guardrails import GuardrailManager
|
|
58
|
+
from glaip_sdk.models import AgentResponse, Model
|
|
59
|
+
from glaip_sdk.ptc import PTC
|
|
66
60
|
from glaip_sdk.registry import AgentRegistry, MCPRegistry, ToolRegistry
|
|
67
61
|
|
|
62
|
+
# Import model validation utility
|
|
63
|
+
from glaip_sdk.models._validation import _validate_model
|
|
64
|
+
|
|
68
65
|
logger = logging.getLogger(__name__)
|
|
69
66
|
|
|
70
67
|
_AGENT_NOT_DEPLOYED_MSG = "Agent must be deployed before running. Call deploy() first."
|
|
@@ -106,11 +103,11 @@ class Agent:
|
|
|
106
103
|
- instruction: Agent instruction text (required)
|
|
107
104
|
- description: Agent description (default: "")
|
|
108
105
|
- tools: List of tools (default: [])
|
|
106
|
+
- model: Optional model override (default: None)
|
|
109
107
|
- agents: List of sub-agents (default: [])
|
|
110
108
|
- mcps: List of MCPs (default: [])
|
|
111
109
|
- timeout: Timeout in seconds (default: 300)
|
|
112
110
|
- metadata: Optional metadata dict (default: None)
|
|
113
|
-
- model: Optional model override (default: None)
|
|
114
111
|
- framework: Agent framework (default: "langchain")
|
|
115
112
|
- version: Agent version (default: "1.0.0")
|
|
116
113
|
- agent_type: Agent type (default: "config")
|
|
@@ -137,7 +134,9 @@ class Agent:
|
|
|
137
134
|
tools: list | None = None,
|
|
138
135
|
agents: list | None = None,
|
|
139
136
|
mcps: list | None = None,
|
|
140
|
-
model: str | None = _UNSET, # type: ignore[assignment]
|
|
137
|
+
model: str | Model | None = _UNSET, # type: ignore[assignment]
|
|
138
|
+
guardrail: GuardrailManager | None = None,
|
|
139
|
+
ptc: PTC | None = None,
|
|
141
140
|
_client: Any = None,
|
|
142
141
|
**kwargs: Any,
|
|
143
142
|
) -> None:
|
|
@@ -154,8 +153,11 @@ class Agent:
|
|
|
154
153
|
tools: List of tools (Tool classes, SDK Tool objects, or strings).
|
|
155
154
|
agents: List of sub-agents (Agent classes, instances, or strings).
|
|
156
155
|
mcps: List of MCPs.
|
|
157
|
-
model: Model identifier.
|
|
156
|
+
model: Model identifier or Model configuration object.
|
|
157
|
+
guardrail: The guardrail manager for content safety.
|
|
158
|
+
ptc: PTC configuration for local runs (sandbox code execution).
|
|
158
159
|
_client: Internal client reference (set automatically).
|
|
160
|
+
|
|
159
161
|
**kwargs: Additional configuration parameters:
|
|
160
162
|
- timeout: Execution timeout in seconds.
|
|
161
163
|
- metadata: Optional metadata dictionary.
|
|
@@ -166,6 +168,7 @@ class Agent:
|
|
|
166
168
|
- tool_configs: Per-tool configuration overrides.
|
|
167
169
|
- mcp_configs: Per-MCP configuration overrides.
|
|
168
170
|
- a2a_profile: A2A profile configuration.
|
|
171
|
+
- ptc: PTC configuration (local runs only).
|
|
169
172
|
"""
|
|
170
173
|
# Instance attributes for deployed agents
|
|
171
174
|
self._id = id
|
|
@@ -180,7 +183,9 @@ class Agent:
|
|
|
180
183
|
self._tools = tools
|
|
181
184
|
self._agents = agents
|
|
182
185
|
self._mcps = mcps
|
|
183
|
-
self._model = model
|
|
186
|
+
self._model = self._validate_and_set_model(model)
|
|
187
|
+
self._guardrail = guardrail
|
|
188
|
+
self._ptc = ptc
|
|
184
189
|
self._language_model_id: str | None = None
|
|
185
190
|
# Extract parameters from kwargs with _UNSET defaults
|
|
186
191
|
self._timeout = kwargs.pop("timeout", Agent._UNSET) # type: ignore[assignment]
|
|
@@ -188,9 +193,25 @@ class Agent:
|
|
|
188
193
|
self._framework = kwargs.pop("framework", Agent._UNSET) # type: ignore[assignment]
|
|
189
194
|
self._version = kwargs.pop("version", Agent._UNSET) # type: ignore[assignment]
|
|
190
195
|
self._agent_type = kwargs.pop("agent_type", Agent._UNSET) # type: ignore[assignment]
|
|
196
|
+
|
|
197
|
+
# Handle 'type' as a legacy alias for 'agent_type'
|
|
198
|
+
legacy_type = kwargs.pop("type", Agent._UNSET)
|
|
199
|
+
if legacy_type is not Agent._UNSET:
|
|
200
|
+
warnings.warn(
|
|
201
|
+
"The 'type' parameter is deprecated and will be removed in a future version. Use 'agent_type' instead.",
|
|
202
|
+
DeprecationWarning,
|
|
203
|
+
stacklevel=2,
|
|
204
|
+
)
|
|
205
|
+
if self._agent_type is Agent._UNSET:
|
|
206
|
+
self._agent_type = legacy_type
|
|
207
|
+
|
|
191
208
|
self._agent_config = kwargs.pop("agent_config", Agent._UNSET) # type: ignore[assignment]
|
|
192
209
|
self._tool_configs = kwargs.pop("tool_configs", Agent._UNSET) # type: ignore[assignment]
|
|
193
|
-
|
|
210
|
+
mcp_configs = kwargs.pop("mcp_configs", Agent._UNSET)
|
|
211
|
+
if mcp_configs is not Agent._UNSET and isinstance(mcp_configs, dict):
|
|
212
|
+
self._mcp_configs = self._normalize_mcp_configs(mcp_configs)
|
|
213
|
+
else:
|
|
214
|
+
self._mcp_configs = mcp_configs # type: ignore[assignment]
|
|
194
215
|
self._a2a_profile = kwargs.pop("a2a_profile", Agent._UNSET) # type: ignore[assignment]
|
|
195
216
|
|
|
196
217
|
# Warn about unexpected kwargs
|
|
@@ -201,6 +222,30 @@ class Agent:
|
|
|
201
222
|
stacklevel=2,
|
|
202
223
|
)
|
|
203
224
|
|
|
225
|
+
def _validate_and_set_model(self, model: str | Any) -> str | Any:
|
|
226
|
+
"""Validate and normalize model parameter.
|
|
227
|
+
|
|
228
|
+
Supports both string model identifiers and Model objects:
|
|
229
|
+
- String: Simple model identifier (e.g., "openai/gpt-4o" or OpenAI.GPT_4O)
|
|
230
|
+
- Model: Model object with credentials/hyperparameters for local execution
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
model: Model identifier (string) or Model object.
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
Validated model (string or Model object).
|
|
237
|
+
"""
|
|
238
|
+
if model is None or model is Agent._UNSET:
|
|
239
|
+
return model
|
|
240
|
+
|
|
241
|
+
from glaip_sdk.models import Model # noqa: PLC0415
|
|
242
|
+
|
|
243
|
+
if isinstance(model, str):
|
|
244
|
+
return _validate_model(model)
|
|
245
|
+
elif isinstance(model, Model):
|
|
246
|
+
return model
|
|
247
|
+
return model
|
|
248
|
+
|
|
204
249
|
# ─────────────────────────────────────────────────────────────────
|
|
205
250
|
# Properties (override in subclasses OR pass to __init__)
|
|
206
251
|
# ─────────────────────────────────────────────────────────────────
|
|
@@ -345,11 +390,11 @@ class Agent:
|
|
|
345
390
|
return None
|
|
346
391
|
|
|
347
392
|
@property
|
|
348
|
-
def model(self) -> str | None:
|
|
393
|
+
def model(self) -> str | Model | None:
|
|
349
394
|
"""Optional model override.
|
|
350
395
|
|
|
351
396
|
Returns:
|
|
352
|
-
Model identifier string or None to use default.
|
|
397
|
+
Model identifier string, Model object, or None to use default.
|
|
353
398
|
"""
|
|
354
399
|
if self._model is not self._UNSET:
|
|
355
400
|
return self._model
|
|
@@ -460,6 +505,16 @@ class Agent:
|
|
|
460
505
|
return self._mcp_configs
|
|
461
506
|
return None
|
|
462
507
|
|
|
508
|
+
@property
|
|
509
|
+
def guardrail(self) -> GuardrailManager | None:
|
|
510
|
+
"""The guardrail manager for content safety."""
|
|
511
|
+
return self._guardrail
|
|
512
|
+
|
|
513
|
+
@property
|
|
514
|
+
def ptc(self) -> PTC | None:
|
|
515
|
+
"""PTC configuration for local runs (sandbox code execution)."""
|
|
516
|
+
return self._ptc
|
|
517
|
+
|
|
463
518
|
@property
|
|
464
519
|
def a2a_profile(self) -> dict[str, Any] | None:
|
|
465
520
|
"""A2A (Agent-to-Agent) profile configuration.
|
|
@@ -506,6 +561,15 @@ class Agent:
|
|
|
506
561
|
"""
|
|
507
562
|
logger.info("Deploying agent: %s", self.name)
|
|
508
563
|
|
|
564
|
+
if self._ptc is not None:
|
|
565
|
+
warnings.warn(
|
|
566
|
+
"PTC (Programmatic Tool Calling) is configured but not supported for remote deployments yet. "
|
|
567
|
+
"PTC will only work for local runs (agent.run(..., local=True)). "
|
|
568
|
+
"The PTC configuration will not be included in the deployed agent.",
|
|
569
|
+
UserWarning,
|
|
570
|
+
stacklevel=2,
|
|
571
|
+
)
|
|
572
|
+
|
|
509
573
|
# Resolve tools FIRST - this uploads them and populates the registry
|
|
510
574
|
tool_ids = self._resolve_tools(get_tool_registry())
|
|
511
575
|
|
|
@@ -520,6 +584,8 @@ class Agent:
|
|
|
520
584
|
from glaip_sdk.utils.client import get_client # noqa: PLC0415
|
|
521
585
|
|
|
522
586
|
client = get_client()
|
|
587
|
+
from glaip_sdk.utils.discovery import find_agent # noqa: PLC0415
|
|
588
|
+
|
|
523
589
|
response = self._create_or_update_agent(config, client, find_agent)
|
|
524
590
|
|
|
525
591
|
# Update self with deployed info
|
|
@@ -545,19 +611,33 @@ class Agent:
|
|
|
545
611
|
"framework": self.framework,
|
|
546
612
|
"version": self.version,
|
|
547
613
|
"agent_type": self.agent_type,
|
|
548
|
-
"model": self.model,
|
|
549
614
|
}
|
|
550
615
|
|
|
616
|
+
if self.model:
|
|
617
|
+
if isinstance(self.model, str):
|
|
618
|
+
config["model"] = self.model
|
|
619
|
+
else:
|
|
620
|
+
config["model"] = self.model.id
|
|
621
|
+
|
|
551
622
|
# Handle metadata (default to empty dict if None)
|
|
552
623
|
config["metadata"] = self.metadata or {}
|
|
553
624
|
|
|
554
625
|
# Handle agent_config with timeout
|
|
555
626
|
# The timeout property is a convenience that maps to agent_config.execution_timeout
|
|
556
|
-
|
|
627
|
+
raw_config = self.agent_config if self.agent_config is not self._UNSET else {}
|
|
628
|
+
agent_config = dict(raw_config) if raw_config else {}
|
|
629
|
+
|
|
557
630
|
if self.timeout and "execution_timeout" not in agent_config:
|
|
558
631
|
agent_config["execution_timeout"] = self.timeout
|
|
559
|
-
|
|
560
|
-
|
|
632
|
+
|
|
633
|
+
if self.guardrail:
|
|
634
|
+
from glaip_sdk.guardrails.serializer import ( # noqa: PLC0415
|
|
635
|
+
serialize_guardrail_manager,
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
agent_config["guardrails"] = serialize_guardrail_manager(self.guardrail)
|
|
639
|
+
|
|
640
|
+
config["agent_config"] = agent_config
|
|
561
641
|
|
|
562
642
|
# Handle tool_configs - resolve tool names/classes to IDs
|
|
563
643
|
if self.tool_configs:
|
|
@@ -589,11 +669,20 @@ class Agent:
|
|
|
589
669
|
|
|
590
670
|
Returns:
|
|
591
671
|
List of resolved MCP IDs for the API payload.
|
|
672
|
+
|
|
673
|
+
Raises:
|
|
674
|
+
ValueError: If an MCP fails to resolve to a valid ID.
|
|
592
675
|
"""
|
|
593
676
|
if not self.mcps:
|
|
594
677
|
return []
|
|
595
678
|
|
|
596
|
-
|
|
679
|
+
resolved_ids: list[str] = []
|
|
680
|
+
for mcp_ref in self.mcps:
|
|
681
|
+
mcp = registry.resolve(mcp_ref)
|
|
682
|
+
if not mcp.id:
|
|
683
|
+
raise ValueError(f"Failed to resolve ID for MCP: {mcp_ref}")
|
|
684
|
+
resolved_ids.append(mcp.id)
|
|
685
|
+
return resolved_ids
|
|
597
686
|
|
|
598
687
|
def _resolve_tools(self, registry: ToolRegistry) -> list[str]:
|
|
599
688
|
"""Resolve tool references to IDs using ToolRegistry.
|
|
@@ -607,12 +696,20 @@ class Agent:
|
|
|
607
696
|
|
|
608
697
|
Returns:
|
|
609
698
|
List of resolved tool IDs for the API payload.
|
|
699
|
+
|
|
700
|
+
Raises:
|
|
701
|
+
ValueError: If a tool fails to resolve to a valid ID.
|
|
610
702
|
"""
|
|
611
703
|
if not self.tools:
|
|
612
704
|
return []
|
|
613
705
|
|
|
614
|
-
|
|
615
|
-
|
|
706
|
+
resolved_ids: list[str] = []
|
|
707
|
+
for tool_ref in self.tools:
|
|
708
|
+
tool = registry.resolve(tool_ref)
|
|
709
|
+
if not tool.id:
|
|
710
|
+
raise ValueError(f"Failed to resolve ID for tool: {tool_ref}")
|
|
711
|
+
resolved_ids.append(tool.id)
|
|
712
|
+
return resolved_ids
|
|
616
713
|
|
|
617
714
|
def _resolve_tool_configs(self, registry: ToolRegistry) -> dict[str, Any]:
|
|
618
715
|
"""Resolve tool_configs keys from tool names/classes to tool IDs.
|
|
@@ -655,6 +752,8 @@ class Agent:
|
|
|
655
752
|
try:
|
|
656
753
|
# Resolve key (tool name/class) to Tool object, get ID
|
|
657
754
|
tool = registry.resolve(key)
|
|
755
|
+
if not tool.id:
|
|
756
|
+
raise ValueError(f"Resolved tool has no ID: {key}")
|
|
658
757
|
resolved[tool.id] = config
|
|
659
758
|
except (ValueError, KeyError) as e:
|
|
660
759
|
raise ValueError(f"Failed to resolve tool config key: {key}") from e
|
|
@@ -690,6 +789,8 @@ class Agent:
|
|
|
690
789
|
resolved_id = key
|
|
691
790
|
else:
|
|
692
791
|
mcp = registry.resolve(key)
|
|
792
|
+
if not mcp.id:
|
|
793
|
+
raise ValueError(f"Resolved MCP has no ID: {key}")
|
|
693
794
|
resolved_id = mcp.id
|
|
694
795
|
|
|
695
796
|
if resolved_id in resolved:
|
|
@@ -705,7 +806,48 @@ class Agent:
|
|
|
705
806
|
|
|
706
807
|
return resolved
|
|
707
808
|
|
|
708
|
-
def
|
|
809
|
+
def _normalize_mcp_configs(self, mcp_configs: dict[Any, Any]) -> dict[Any, Any]:
|
|
810
|
+
"""Normalize mcp_configs by wrapping misplaced transport keys in 'config'.
|
|
811
|
+
|
|
812
|
+
This ensures that flat transport settings (e.g. {'url': '...'}) provided
|
|
813
|
+
by the user are correctly moved into the 'config' block required by the
|
|
814
|
+
Platform, ensuring parity between local and remote execution.
|
|
815
|
+
|
|
816
|
+
Args:
|
|
817
|
+
mcp_configs: The raw mcp_configs dictionary.
|
|
818
|
+
|
|
819
|
+
Returns:
|
|
820
|
+
Normalized mcp_configs dictionary.
|
|
821
|
+
"""
|
|
822
|
+
from glaip_sdk.runner.langgraph import _MCP_TRANSPORT_KEYS # noqa: PLC0415
|
|
823
|
+
|
|
824
|
+
normalized = {}
|
|
825
|
+
for mcp_key, override in mcp_configs.items():
|
|
826
|
+
if not isinstance(override, dict):
|
|
827
|
+
normalized[mcp_key] = override
|
|
828
|
+
continue
|
|
829
|
+
|
|
830
|
+
misplaced = {k: v for k, v in override.items() if k in _MCP_TRANSPORT_KEYS}
|
|
831
|
+
|
|
832
|
+
if misplaced:
|
|
833
|
+
new_override = override.copy()
|
|
834
|
+
config_block = new_override.get("config", {})
|
|
835
|
+
if not isinstance(config_block, dict):
|
|
836
|
+
config_block = {}
|
|
837
|
+
|
|
838
|
+
config_block.update(misplaced)
|
|
839
|
+
new_override["config"] = config_block
|
|
840
|
+
|
|
841
|
+
for k in misplaced:
|
|
842
|
+
new_override.pop(k, None)
|
|
843
|
+
|
|
844
|
+
normalized[mcp_key] = new_override
|
|
845
|
+
else:
|
|
846
|
+
normalized[mcp_key] = override
|
|
847
|
+
|
|
848
|
+
return normalized
|
|
849
|
+
|
|
850
|
+
def _resolve_agents(self, registry: AgentRegistry) -> list[str]:
|
|
709
851
|
"""Resolve sub-agent references using AgentRegistry.
|
|
710
852
|
|
|
711
853
|
Uses the global AgentRegistry to cache Agent objects across deployments.
|
|
@@ -717,12 +859,20 @@ class Agent:
|
|
|
717
859
|
|
|
718
860
|
Returns:
|
|
719
861
|
List of resolved agent IDs for the API payload.
|
|
862
|
+
|
|
863
|
+
Raises:
|
|
864
|
+
ValueError: If an agent fails to resolve to a valid ID.
|
|
720
865
|
"""
|
|
721
866
|
if not self.agents:
|
|
722
867
|
return []
|
|
723
868
|
|
|
724
|
-
|
|
725
|
-
|
|
869
|
+
resolved_ids: list[str] = []
|
|
870
|
+
for agent_ref in self.agents:
|
|
871
|
+
agent = registry.resolve(agent_ref)
|
|
872
|
+
if not agent.id:
|
|
873
|
+
raise ValueError(f"Failed to resolve ID for agent: {agent_ref}")
|
|
874
|
+
resolved_ids.append(agent.id)
|
|
875
|
+
return resolved_ids
|
|
726
876
|
|
|
727
877
|
def _create_or_update_agent(
|
|
728
878
|
self,
|
|
@@ -798,6 +948,19 @@ class Agent:
|
|
|
798
948
|
|
|
799
949
|
return content
|
|
800
950
|
|
|
951
|
+
def to_component(self) -> Any:
|
|
952
|
+
"""Convert this Agent into a pipeline-compatible Component.
|
|
953
|
+
|
|
954
|
+
The returned AgentComponent wraps this agent instance and allows it
|
|
955
|
+
to be used within a Pipeline (from gllm-pipeline).
|
|
956
|
+
|
|
957
|
+
Returns:
|
|
958
|
+
An AgentComponent instance wrapping this agent.
|
|
959
|
+
"""
|
|
960
|
+
from glaip_sdk.agents.component import AgentComponent # noqa: PLC0415
|
|
961
|
+
|
|
962
|
+
return AgentComponent(self)
|
|
963
|
+
|
|
801
964
|
# =========================================================================
|
|
802
965
|
# API Methods - Available after deploy()
|
|
803
966
|
# =========================================================================
|
|
@@ -806,19 +969,42 @@ class Agent:
|
|
|
806
969
|
"""Return a dict representation of the Agent.
|
|
807
970
|
|
|
808
971
|
Provides Pydantic-style serialization for backward compatibility.
|
|
972
|
+
This implementation avoids triggering external tool resolution to ensure
|
|
973
|
+
it remains robust even when the environment is not fully configured.
|
|
809
974
|
|
|
810
975
|
Args:
|
|
811
976
|
exclude_none: If True, exclude None values from the output.
|
|
812
977
|
|
|
813
978
|
Returns:
|
|
814
|
-
Dictionary containing Agent attributes.
|
|
979
|
+
Dictionary containing Agent attributes. Note: Mutable fields (dicts, lists)
|
|
980
|
+
are returned as references. Modify with caution or make a deep copy if needed.
|
|
815
981
|
"""
|
|
982
|
+
# Map convenience timeout to agent_config if not already present
|
|
983
|
+
agent_config = self.agent_config if self.agent_config is not self._UNSET else {}
|
|
984
|
+
agent_config = dict(agent_config) if agent_config else {}
|
|
985
|
+
|
|
986
|
+
if self.timeout and "execution_timeout" not in agent_config:
|
|
987
|
+
agent_config["execution_timeout"] = self.timeout
|
|
988
|
+
|
|
989
|
+
# Handle guardrail serialization without full config build
|
|
990
|
+
if self.guardrail:
|
|
991
|
+
try:
|
|
992
|
+
from glaip_sdk.guardrails.serializer import ( # noqa: PLC0415
|
|
993
|
+
serialize_guardrail_manager,
|
|
994
|
+
)
|
|
995
|
+
|
|
996
|
+
agent_config["guardrails"] = serialize_guardrail_manager(self.guardrail)
|
|
997
|
+
except ImportError: # pragma: no cover
|
|
998
|
+
# Serializer not available (optional dependency); skip guardrail data
|
|
999
|
+
pass
|
|
1000
|
+
|
|
816
1001
|
data = {
|
|
817
1002
|
"id": self._id,
|
|
818
1003
|
"name": self.name,
|
|
819
1004
|
"instruction": self.instruction,
|
|
820
1005
|
"description": self.description,
|
|
821
|
-
"
|
|
1006
|
+
"agent_type": self.agent_type,
|
|
1007
|
+
"type": self.agent_type, # Legacy key for backward compatibility
|
|
822
1008
|
"framework": self.framework,
|
|
823
1009
|
"version": self.version,
|
|
824
1010
|
"tools": self.tools,
|
|
@@ -826,13 +1012,16 @@ class Agent:
|
|
|
826
1012
|
"mcps": self.mcps,
|
|
827
1013
|
"timeout": self.timeout,
|
|
828
1014
|
"metadata": self.metadata,
|
|
829
|
-
"
|
|
1015
|
+
"model": self.model,
|
|
1016
|
+
"agent_config": agent_config,
|
|
830
1017
|
"tool_configs": self.tool_configs,
|
|
831
1018
|
"mcp_configs": self.mcp_configs,
|
|
832
1019
|
"a2a_profile": self.a2a_profile,
|
|
1020
|
+
"guardrail": self.guardrail,
|
|
833
1021
|
"created_at": self._created_at,
|
|
834
1022
|
"updated_at": self._updated_at,
|
|
835
1023
|
}
|
|
1024
|
+
|
|
836
1025
|
if exclude_none:
|
|
837
1026
|
return {k: v for k, v in data.items() if v is not None}
|
|
838
1027
|
return data
|
|
@@ -849,6 +1038,36 @@ class Agent:
|
|
|
849
1038
|
self._client = client
|
|
850
1039
|
return self
|
|
851
1040
|
|
|
1041
|
+
@property
|
|
1042
|
+
def schedule(self) -> AgentScheduleManager:
|
|
1043
|
+
"""Get the schedule manager for this agent.
|
|
1044
|
+
|
|
1045
|
+
Provides a convenient interface for managing schedules scoped to this agent.
|
|
1046
|
+
|
|
1047
|
+
Returns:
|
|
1048
|
+
AgentScheduleManager for schedule operations
|
|
1049
|
+
|
|
1050
|
+
Raises:
|
|
1051
|
+
ValueError: If agent is not deployed
|
|
1052
|
+
RuntimeError: If agent is not bound to a client
|
|
1053
|
+
|
|
1054
|
+
Example:
|
|
1055
|
+
>>> agent = client.get_agent_by_id("agent-id")
|
|
1056
|
+
>>> schedules = agent.schedule.list()
|
|
1057
|
+
>>> new_schedule = agent.schedule.create(
|
|
1058
|
+
... input="Daily task",
|
|
1059
|
+
... schedule="0 9 * * 1-5"
|
|
1060
|
+
... )
|
|
1061
|
+
"""
|
|
1062
|
+
if not self.id:
|
|
1063
|
+
raise ValueError(_AGENT_NOT_DEPLOYED_MSG)
|
|
1064
|
+
if not self._client:
|
|
1065
|
+
raise RuntimeError(_CLIENT_NOT_AVAILABLE_MSG)
|
|
1066
|
+
|
|
1067
|
+
from glaip_sdk.client.schedules import AgentScheduleManager # noqa: PLC0415
|
|
1068
|
+
|
|
1069
|
+
return AgentScheduleManager(self, self._client.schedules)
|
|
1070
|
+
|
|
852
1071
|
def _prepare_run_kwargs(
|
|
853
1072
|
self,
|
|
854
1073
|
message: str,
|
|
@@ -885,6 +1104,10 @@ class Agent:
|
|
|
885
1104
|
}
|
|
886
1105
|
|
|
887
1106
|
if runtime_config is not None:
|
|
1107
|
+
from glaip_sdk.utils.runtime_config import ( # noqa: PLC0415
|
|
1108
|
+
normalize_runtime_config_keys,
|
|
1109
|
+
)
|
|
1110
|
+
|
|
888
1111
|
call_kwargs["runtime_config"] = normalize_runtime_config_keys(
|
|
889
1112
|
runtime_config,
|
|
890
1113
|
tool_registry=get_tool_registry(),
|
|
@@ -893,6 +1116,10 @@ class Agent:
|
|
|
893
1116
|
)
|
|
894
1117
|
|
|
895
1118
|
call_kwargs.update(kwargs)
|
|
1119
|
+
|
|
1120
|
+
memory_user_id = call_kwargs.get("memory_user_id")
|
|
1121
|
+
if memory_user_id and not call_kwargs.get("user_id"):
|
|
1122
|
+
call_kwargs["user_id"] = memory_user_id
|
|
896
1123
|
return agent_client, call_kwargs
|
|
897
1124
|
|
|
898
1125
|
def _get_local_runner_or_raise(self) -> Any:
|
|
@@ -904,9 +1131,24 @@ class Agent:
|
|
|
904
1131
|
Raises:
|
|
905
1132
|
ValueError: If local runtime is not available.
|
|
906
1133
|
"""
|
|
1134
|
+
from glaip_sdk.runner import get_default_runner # noqa: PLC0415
|
|
1135
|
+
from glaip_sdk.runner.deps import ( # noqa: PLC0415
|
|
1136
|
+
check_local_runtime_available,
|
|
1137
|
+
get_local_runtime_missing_message,
|
|
1138
|
+
)
|
|
1139
|
+
|
|
907
1140
|
if check_local_runtime_available():
|
|
908
1141
|
return get_default_runner()
|
|
909
|
-
|
|
1142
|
+
|
|
1143
|
+
# If agent is not deployed, it *must* use local runtime
|
|
1144
|
+
if not self.id:
|
|
1145
|
+
raise ValueError(f"{_AGENT_NOT_DEPLOYED_MSG}\n\n{get_local_runtime_missing_message()}")
|
|
1146
|
+
|
|
1147
|
+
# If agent IS deployed but local execution was forced (local=True)
|
|
1148
|
+
raise ValueError(
|
|
1149
|
+
f"Local execution override was requested, but local runtime is missing.\n\n"
|
|
1150
|
+
f"{get_local_runtime_missing_message()}"
|
|
1151
|
+
)
|
|
910
1152
|
|
|
911
1153
|
def _prepare_local_runner_kwargs(
|
|
912
1154
|
self,
|
|
@@ -941,6 +1183,7 @@ class Agent:
|
|
|
941
1183
|
self,
|
|
942
1184
|
message: str,
|
|
943
1185
|
verbose: bool = False,
|
|
1186
|
+
local: bool = False,
|
|
944
1187
|
runtime_config: dict[str, Any] | None = None,
|
|
945
1188
|
chat_history: list[dict[str, str]] | None = None,
|
|
946
1189
|
**kwargs: Any,
|
|
@@ -953,9 +1196,13 @@ class Agent:
|
|
|
953
1196
|
- **Local**: When the agent is not deployed and glaip-sdk[local] is installed,
|
|
954
1197
|
execution happens locally via aip-agents (no server required).
|
|
955
1198
|
|
|
1199
|
+
You can force local execution for a deployed agent by passing `local=True`.
|
|
1200
|
+
|
|
956
1201
|
Args:
|
|
957
1202
|
message: The message to send to the agent.
|
|
958
1203
|
verbose: If True, print streaming output to console. Defaults to False.
|
|
1204
|
+
local: If True, force local execution even if the agent is deployed.
|
|
1205
|
+
Defaults to False.
|
|
959
1206
|
runtime_config: Optional runtime configuration for tools, MCPs, and agents.
|
|
960
1207
|
Keys can be SDK objects, UUIDs, or names. Example:
|
|
961
1208
|
{
|
|
@@ -977,16 +1224,19 @@ class Agent:
|
|
|
977
1224
|
RuntimeError: If server-backed execution fails due to client issues.
|
|
978
1225
|
"""
|
|
979
1226
|
# Backend routing: deployed agents use server, undeployed use local (if available)
|
|
980
|
-
if self.id:
|
|
1227
|
+
if self.id and not local:
|
|
981
1228
|
# Server-backed execution path (agent is deployed)
|
|
982
1229
|
agent_client, call_kwargs = self._prepare_run_kwargs(
|
|
983
|
-
message,
|
|
1230
|
+
message,
|
|
1231
|
+
verbose,
|
|
1232
|
+
runtime_config or kwargs.get("runtime_config"),
|
|
1233
|
+
**kwargs,
|
|
984
1234
|
)
|
|
985
1235
|
if chat_history is not None:
|
|
986
1236
|
call_kwargs["chat_history"] = chat_history
|
|
987
1237
|
return agent_client.run_agent(**call_kwargs)
|
|
988
1238
|
|
|
989
|
-
# Local execution path (agent is not deployed)
|
|
1239
|
+
# Local execution path (agent is not deployed OR local=True)
|
|
990
1240
|
runner = self._get_local_runner_or_raise()
|
|
991
1241
|
local_kwargs = self._prepare_local_runner_kwargs(message, verbose, runtime_config, chat_history, **kwargs)
|
|
992
1242
|
return runner.run(**local_kwargs)
|
|
@@ -995,6 +1245,7 @@ class Agent:
|
|
|
995
1245
|
self,
|
|
996
1246
|
message: str,
|
|
997
1247
|
verbose: bool = False,
|
|
1248
|
+
local: bool = False,
|
|
998
1249
|
runtime_config: dict[str, Any] | None = None,
|
|
999
1250
|
chat_history: list[dict[str, str]] | None = None,
|
|
1000
1251
|
**kwargs: Any,
|
|
@@ -1007,9 +1258,13 @@ class Agent:
|
|
|
1007
1258
|
- **Local**: When the agent is not deployed and glaip-sdk[local] is installed,
|
|
1008
1259
|
execution happens locally via aip-agents (no server required).
|
|
1009
1260
|
|
|
1261
|
+
You can force local execution for a deployed agent by passing `local=True`.
|
|
1262
|
+
|
|
1010
1263
|
Args:
|
|
1011
1264
|
message: The message to send to the agent.
|
|
1012
1265
|
verbose: If True, print streaming output to console. Defaults to False.
|
|
1266
|
+
local: If True, force local execution even if the agent is deployed.
|
|
1267
|
+
Defaults to False.
|
|
1013
1268
|
runtime_config: Optional runtime configuration for tools, MCPs, and agents.
|
|
1014
1269
|
Keys can be SDK objects, UUIDs, or names. Example:
|
|
1015
1270
|
{
|
|
@@ -1031,10 +1286,13 @@ class Agent:
|
|
|
1031
1286
|
RuntimeError: If server-backed execution fails due to client issues.
|
|
1032
1287
|
"""
|
|
1033
1288
|
# Backend routing: deployed agents use server, undeployed use local (if available)
|
|
1034
|
-
if self.id:
|
|
1289
|
+
if self.id and not local:
|
|
1035
1290
|
# Server-backed execution path (agent is deployed)
|
|
1036
1291
|
agent_client, call_kwargs = self._prepare_run_kwargs(
|
|
1037
|
-
message,
|
|
1292
|
+
message,
|
|
1293
|
+
verbose,
|
|
1294
|
+
runtime_config or kwargs.get("runtime_config"),
|
|
1295
|
+
**kwargs,
|
|
1038
1296
|
)
|
|
1039
1297
|
if chat_history is not None:
|
|
1040
1298
|
call_kwargs["chat_history"] = chat_history
|
|
@@ -1043,7 +1301,7 @@ class Agent:
|
|
|
1043
1301
|
yield chunk
|
|
1044
1302
|
return
|
|
1045
1303
|
|
|
1046
|
-
# Local execution path (agent is not deployed)
|
|
1304
|
+
# Local execution path (agent is not deployed OR local=True)
|
|
1047
1305
|
runner = self._get_local_runner_or_raise()
|
|
1048
1306
|
local_kwargs = self._prepare_local_runner_kwargs(message, verbose, runtime_config, chat_history, **kwargs)
|
|
1049
1307
|
result = await runner.arun(**local_kwargs)
|