glaip-sdk 0.6.19__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/agents/base.py +283 -30
- 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 +1 -1
- 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/entrypoint.py +20 -0
- glaip_sdk/cli/main.py +112 -35
- 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 +293 -17
- 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 +109 -30
- 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 +35 -2
- glaip_sdk/hitl/base.py +64 -0
- glaip_sdk/hitl/callback.py +43 -0
- glaip_sdk/hitl/local.py +1 -31
- 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 +4 -1
- glaip_sdk/runner/langgraph.py +251 -27
- 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/runtime_config.py +3 -2
- glaip_sdk/utils/sync.py +31 -11
- glaip_sdk/utils/tool_detection.py +274 -6
- {glaip_sdk-0.6.19.dist-info → glaip_sdk-0.7.27.dist-info}/METADATA +22 -8
- glaip_sdk-0.7.27.dist-info/RECORD +227 -0
- {glaip_sdk-0.6.19.dist-info → glaip_sdk-0.7.27.dist-info}/WHEEL +1 -1
- glaip_sdk-0.7.27.dist-info/entry_points.txt +2 -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.19.dist-info/RECORD +0 -163
- glaip_sdk-0.6.19.dist-info/entry_points.txt +0 -2
- {glaip_sdk-0.6.19.dist-info → glaip_sdk-0.7.27.dist-info}/top_level.txt +0 -0
glaip_sdk/agents/base.py
CHANGED
|
@@ -46,8 +46,6 @@ 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
|
|
|
@@ -55,9 +53,15 @@ from glaip_sdk.registry import get_agent_registry, get_mcp_registry, get_tool_re
|
|
|
55
53
|
from glaip_sdk.utils.resource_refs import is_uuid
|
|
56
54
|
|
|
57
55
|
if TYPE_CHECKING:
|
|
58
|
-
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
|
|
59
60
|
from glaip_sdk.registry import AgentRegistry, MCPRegistry, ToolRegistry
|
|
60
61
|
|
|
62
|
+
# Import model validation utility
|
|
63
|
+
from glaip_sdk.models._validation import _validate_model
|
|
64
|
+
|
|
61
65
|
logger = logging.getLogger(__name__)
|
|
62
66
|
|
|
63
67
|
_AGENT_NOT_DEPLOYED_MSG = "Agent must be deployed before running. Call deploy() first."
|
|
@@ -99,11 +103,11 @@ class Agent:
|
|
|
99
103
|
- instruction: Agent instruction text (required)
|
|
100
104
|
- description: Agent description (default: "")
|
|
101
105
|
- tools: List of tools (default: [])
|
|
106
|
+
- model: Optional model override (default: None)
|
|
102
107
|
- agents: List of sub-agents (default: [])
|
|
103
108
|
- mcps: List of MCPs (default: [])
|
|
104
109
|
- timeout: Timeout in seconds (default: 300)
|
|
105
110
|
- metadata: Optional metadata dict (default: None)
|
|
106
|
-
- model: Optional model override (default: None)
|
|
107
111
|
- framework: Agent framework (default: "langchain")
|
|
108
112
|
- version: Agent version (default: "1.0.0")
|
|
109
113
|
- agent_type: Agent type (default: "config")
|
|
@@ -130,7 +134,9 @@ class Agent:
|
|
|
130
134
|
tools: list | None = None,
|
|
131
135
|
agents: list | None = None,
|
|
132
136
|
mcps: list | None = None,
|
|
133
|
-
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,
|
|
134
140
|
_client: Any = None,
|
|
135
141
|
**kwargs: Any,
|
|
136
142
|
) -> None:
|
|
@@ -147,8 +153,11 @@ class Agent:
|
|
|
147
153
|
tools: List of tools (Tool classes, SDK Tool objects, or strings).
|
|
148
154
|
agents: List of sub-agents (Agent classes, instances, or strings).
|
|
149
155
|
mcps: List of MCPs.
|
|
150
|
-
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).
|
|
151
159
|
_client: Internal client reference (set automatically).
|
|
160
|
+
|
|
152
161
|
**kwargs: Additional configuration parameters:
|
|
153
162
|
- timeout: Execution timeout in seconds.
|
|
154
163
|
- metadata: Optional metadata dictionary.
|
|
@@ -159,6 +168,7 @@ class Agent:
|
|
|
159
168
|
- tool_configs: Per-tool configuration overrides.
|
|
160
169
|
- mcp_configs: Per-MCP configuration overrides.
|
|
161
170
|
- a2a_profile: A2A profile configuration.
|
|
171
|
+
- ptc: PTC configuration (local runs only).
|
|
162
172
|
"""
|
|
163
173
|
# Instance attributes for deployed agents
|
|
164
174
|
self._id = id
|
|
@@ -173,7 +183,9 @@ class Agent:
|
|
|
173
183
|
self._tools = tools
|
|
174
184
|
self._agents = agents
|
|
175
185
|
self._mcps = mcps
|
|
176
|
-
self._model = model
|
|
186
|
+
self._model = self._validate_and_set_model(model)
|
|
187
|
+
self._guardrail = guardrail
|
|
188
|
+
self._ptc = ptc
|
|
177
189
|
self._language_model_id: str | None = None
|
|
178
190
|
# Extract parameters from kwargs with _UNSET defaults
|
|
179
191
|
self._timeout = kwargs.pop("timeout", Agent._UNSET) # type: ignore[assignment]
|
|
@@ -181,9 +193,25 @@ class Agent:
|
|
|
181
193
|
self._framework = kwargs.pop("framework", Agent._UNSET) # type: ignore[assignment]
|
|
182
194
|
self._version = kwargs.pop("version", Agent._UNSET) # type: ignore[assignment]
|
|
183
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
|
+
|
|
184
208
|
self._agent_config = kwargs.pop("agent_config", Agent._UNSET) # type: ignore[assignment]
|
|
185
209
|
self._tool_configs = kwargs.pop("tool_configs", Agent._UNSET) # type: ignore[assignment]
|
|
186
|
-
|
|
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]
|
|
187
215
|
self._a2a_profile = kwargs.pop("a2a_profile", Agent._UNSET) # type: ignore[assignment]
|
|
188
216
|
|
|
189
217
|
# Warn about unexpected kwargs
|
|
@@ -194,6 +222,30 @@ class Agent:
|
|
|
194
222
|
stacklevel=2,
|
|
195
223
|
)
|
|
196
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
|
+
|
|
197
249
|
# ─────────────────────────────────────────────────────────────────
|
|
198
250
|
# Properties (override in subclasses OR pass to __init__)
|
|
199
251
|
# ─────────────────────────────────────────────────────────────────
|
|
@@ -338,11 +390,11 @@ class Agent:
|
|
|
338
390
|
return None
|
|
339
391
|
|
|
340
392
|
@property
|
|
341
|
-
def model(self) -> str | None:
|
|
393
|
+
def model(self) -> str | Model | None:
|
|
342
394
|
"""Optional model override.
|
|
343
395
|
|
|
344
396
|
Returns:
|
|
345
|
-
Model identifier string or None to use default.
|
|
397
|
+
Model identifier string, Model object, or None to use default.
|
|
346
398
|
"""
|
|
347
399
|
if self._model is not self._UNSET:
|
|
348
400
|
return self._model
|
|
@@ -453,6 +505,16 @@ class Agent:
|
|
|
453
505
|
return self._mcp_configs
|
|
454
506
|
return None
|
|
455
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
|
+
|
|
456
518
|
@property
|
|
457
519
|
def a2a_profile(self) -> dict[str, Any] | None:
|
|
458
520
|
"""A2A (Agent-to-Agent) profile configuration.
|
|
@@ -499,6 +561,15 @@ class Agent:
|
|
|
499
561
|
"""
|
|
500
562
|
logger.info("Deploying agent: %s", self.name)
|
|
501
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
|
+
|
|
502
573
|
# Resolve tools FIRST - this uploads them and populates the registry
|
|
503
574
|
tool_ids = self._resolve_tools(get_tool_registry())
|
|
504
575
|
|
|
@@ -540,19 +611,33 @@ class Agent:
|
|
|
540
611
|
"framework": self.framework,
|
|
541
612
|
"version": self.version,
|
|
542
613
|
"agent_type": self.agent_type,
|
|
543
|
-
"model": self.model,
|
|
544
614
|
}
|
|
545
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
|
+
|
|
546
622
|
# Handle metadata (default to empty dict if None)
|
|
547
623
|
config["metadata"] = self.metadata or {}
|
|
548
624
|
|
|
549
625
|
# Handle agent_config with timeout
|
|
550
626
|
# The timeout property is a convenience that maps to agent_config.execution_timeout
|
|
551
|
-
|
|
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
|
+
|
|
552
630
|
if self.timeout and "execution_timeout" not in agent_config:
|
|
553
631
|
agent_config["execution_timeout"] = self.timeout
|
|
554
|
-
|
|
555
|
-
|
|
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
|
|
556
641
|
|
|
557
642
|
# Handle tool_configs - resolve tool names/classes to IDs
|
|
558
643
|
if self.tool_configs:
|
|
@@ -584,11 +669,20 @@ class Agent:
|
|
|
584
669
|
|
|
585
670
|
Returns:
|
|
586
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.
|
|
587
675
|
"""
|
|
588
676
|
if not self.mcps:
|
|
589
677
|
return []
|
|
590
678
|
|
|
591
|
-
|
|
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
|
|
592
686
|
|
|
593
687
|
def _resolve_tools(self, registry: ToolRegistry) -> list[str]:
|
|
594
688
|
"""Resolve tool references to IDs using ToolRegistry.
|
|
@@ -602,12 +696,20 @@ class Agent:
|
|
|
602
696
|
|
|
603
697
|
Returns:
|
|
604
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.
|
|
605
702
|
"""
|
|
606
703
|
if not self.tools:
|
|
607
704
|
return []
|
|
608
705
|
|
|
609
|
-
|
|
610
|
-
|
|
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
|
|
611
713
|
|
|
612
714
|
def _resolve_tool_configs(self, registry: ToolRegistry) -> dict[str, Any]:
|
|
613
715
|
"""Resolve tool_configs keys from tool names/classes to tool IDs.
|
|
@@ -650,6 +752,8 @@ class Agent:
|
|
|
650
752
|
try:
|
|
651
753
|
# Resolve key (tool name/class) to Tool object, get ID
|
|
652
754
|
tool = registry.resolve(key)
|
|
755
|
+
if not tool.id:
|
|
756
|
+
raise ValueError(f"Resolved tool has no ID: {key}")
|
|
653
757
|
resolved[tool.id] = config
|
|
654
758
|
except (ValueError, KeyError) as e:
|
|
655
759
|
raise ValueError(f"Failed to resolve tool config key: {key}") from e
|
|
@@ -685,6 +789,8 @@ class Agent:
|
|
|
685
789
|
resolved_id = key
|
|
686
790
|
else:
|
|
687
791
|
mcp = registry.resolve(key)
|
|
792
|
+
if not mcp.id:
|
|
793
|
+
raise ValueError(f"Resolved MCP has no ID: {key}")
|
|
688
794
|
resolved_id = mcp.id
|
|
689
795
|
|
|
690
796
|
if resolved_id in resolved:
|
|
@@ -700,7 +806,48 @@ class Agent:
|
|
|
700
806
|
|
|
701
807
|
return resolved
|
|
702
808
|
|
|
703
|
-
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]:
|
|
704
851
|
"""Resolve sub-agent references using AgentRegistry.
|
|
705
852
|
|
|
706
853
|
Uses the global AgentRegistry to cache Agent objects across deployments.
|
|
@@ -712,12 +859,20 @@ class Agent:
|
|
|
712
859
|
|
|
713
860
|
Returns:
|
|
714
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.
|
|
715
865
|
"""
|
|
716
866
|
if not self.agents:
|
|
717
867
|
return []
|
|
718
868
|
|
|
719
|
-
|
|
720
|
-
|
|
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
|
|
721
876
|
|
|
722
877
|
def _create_or_update_agent(
|
|
723
878
|
self,
|
|
@@ -793,6 +948,19 @@ class Agent:
|
|
|
793
948
|
|
|
794
949
|
return content
|
|
795
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
|
+
|
|
796
964
|
# =========================================================================
|
|
797
965
|
# API Methods - Available after deploy()
|
|
798
966
|
# =========================================================================
|
|
@@ -801,19 +969,42 @@ class Agent:
|
|
|
801
969
|
"""Return a dict representation of the Agent.
|
|
802
970
|
|
|
803
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.
|
|
804
974
|
|
|
805
975
|
Args:
|
|
806
976
|
exclude_none: If True, exclude None values from the output.
|
|
807
977
|
|
|
808
978
|
Returns:
|
|
809
|
-
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.
|
|
810
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
|
+
|
|
811
1001
|
data = {
|
|
812
1002
|
"id": self._id,
|
|
813
1003
|
"name": self.name,
|
|
814
1004
|
"instruction": self.instruction,
|
|
815
1005
|
"description": self.description,
|
|
816
|
-
"
|
|
1006
|
+
"agent_type": self.agent_type,
|
|
1007
|
+
"type": self.agent_type, # Legacy key for backward compatibility
|
|
817
1008
|
"framework": self.framework,
|
|
818
1009
|
"version": self.version,
|
|
819
1010
|
"tools": self.tools,
|
|
@@ -821,13 +1012,16 @@ class Agent:
|
|
|
821
1012
|
"mcps": self.mcps,
|
|
822
1013
|
"timeout": self.timeout,
|
|
823
1014
|
"metadata": self.metadata,
|
|
824
|
-
"
|
|
1015
|
+
"model": self.model,
|
|
1016
|
+
"agent_config": agent_config,
|
|
825
1017
|
"tool_configs": self.tool_configs,
|
|
826
1018
|
"mcp_configs": self.mcp_configs,
|
|
827
1019
|
"a2a_profile": self.a2a_profile,
|
|
1020
|
+
"guardrail": self.guardrail,
|
|
828
1021
|
"created_at": self._created_at,
|
|
829
1022
|
"updated_at": self._updated_at,
|
|
830
1023
|
}
|
|
1024
|
+
|
|
831
1025
|
if exclude_none:
|
|
832
1026
|
return {k: v for k, v in data.items() if v is not None}
|
|
833
1027
|
return data
|
|
@@ -844,6 +1038,36 @@ class Agent:
|
|
|
844
1038
|
self._client = client
|
|
845
1039
|
return self
|
|
846
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
|
+
|
|
847
1071
|
def _prepare_run_kwargs(
|
|
848
1072
|
self,
|
|
849
1073
|
message: str,
|
|
@@ -892,6 +1116,10 @@ class Agent:
|
|
|
892
1116
|
)
|
|
893
1117
|
|
|
894
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
|
|
895
1123
|
return agent_client, call_kwargs
|
|
896
1124
|
|
|
897
1125
|
def _get_local_runner_or_raise(self) -> Any:
|
|
@@ -911,7 +1139,16 @@ class Agent:
|
|
|
911
1139
|
|
|
912
1140
|
if check_local_runtime_available():
|
|
913
1141
|
return get_default_runner()
|
|
914
|
-
|
|
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
|
+
)
|
|
915
1152
|
|
|
916
1153
|
def _prepare_local_runner_kwargs(
|
|
917
1154
|
self,
|
|
@@ -946,6 +1183,7 @@ class Agent:
|
|
|
946
1183
|
self,
|
|
947
1184
|
message: str,
|
|
948
1185
|
verbose: bool = False,
|
|
1186
|
+
local: bool = False,
|
|
949
1187
|
runtime_config: dict[str, Any] | None = None,
|
|
950
1188
|
chat_history: list[dict[str, str]] | None = None,
|
|
951
1189
|
**kwargs: Any,
|
|
@@ -958,9 +1196,13 @@ class Agent:
|
|
|
958
1196
|
- **Local**: When the agent is not deployed and glaip-sdk[local] is installed,
|
|
959
1197
|
execution happens locally via aip-agents (no server required).
|
|
960
1198
|
|
|
1199
|
+
You can force local execution for a deployed agent by passing `local=True`.
|
|
1200
|
+
|
|
961
1201
|
Args:
|
|
962
1202
|
message: The message to send to the agent.
|
|
963
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.
|
|
964
1206
|
runtime_config: Optional runtime configuration for tools, MCPs, and agents.
|
|
965
1207
|
Keys can be SDK objects, UUIDs, or names. Example:
|
|
966
1208
|
{
|
|
@@ -982,16 +1224,19 @@ class Agent:
|
|
|
982
1224
|
RuntimeError: If server-backed execution fails due to client issues.
|
|
983
1225
|
"""
|
|
984
1226
|
# Backend routing: deployed agents use server, undeployed use local (if available)
|
|
985
|
-
if self.id:
|
|
1227
|
+
if self.id and not local:
|
|
986
1228
|
# Server-backed execution path (agent is deployed)
|
|
987
1229
|
agent_client, call_kwargs = self._prepare_run_kwargs(
|
|
988
|
-
message,
|
|
1230
|
+
message,
|
|
1231
|
+
verbose,
|
|
1232
|
+
runtime_config or kwargs.get("runtime_config"),
|
|
1233
|
+
**kwargs,
|
|
989
1234
|
)
|
|
990
1235
|
if chat_history is not None:
|
|
991
1236
|
call_kwargs["chat_history"] = chat_history
|
|
992
1237
|
return agent_client.run_agent(**call_kwargs)
|
|
993
1238
|
|
|
994
|
-
# Local execution path (agent is not deployed)
|
|
1239
|
+
# Local execution path (agent is not deployed OR local=True)
|
|
995
1240
|
runner = self._get_local_runner_or_raise()
|
|
996
1241
|
local_kwargs = self._prepare_local_runner_kwargs(message, verbose, runtime_config, chat_history, **kwargs)
|
|
997
1242
|
return runner.run(**local_kwargs)
|
|
@@ -1000,6 +1245,7 @@ class Agent:
|
|
|
1000
1245
|
self,
|
|
1001
1246
|
message: str,
|
|
1002
1247
|
verbose: bool = False,
|
|
1248
|
+
local: bool = False,
|
|
1003
1249
|
runtime_config: dict[str, Any] | None = None,
|
|
1004
1250
|
chat_history: list[dict[str, str]] | None = None,
|
|
1005
1251
|
**kwargs: Any,
|
|
@@ -1012,9 +1258,13 @@ class Agent:
|
|
|
1012
1258
|
- **Local**: When the agent is not deployed and glaip-sdk[local] is installed,
|
|
1013
1259
|
execution happens locally via aip-agents (no server required).
|
|
1014
1260
|
|
|
1261
|
+
You can force local execution for a deployed agent by passing `local=True`.
|
|
1262
|
+
|
|
1015
1263
|
Args:
|
|
1016
1264
|
message: The message to send to the agent.
|
|
1017
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.
|
|
1018
1268
|
runtime_config: Optional runtime configuration for tools, MCPs, and agents.
|
|
1019
1269
|
Keys can be SDK objects, UUIDs, or names. Example:
|
|
1020
1270
|
{
|
|
@@ -1036,10 +1286,13 @@ class Agent:
|
|
|
1036
1286
|
RuntimeError: If server-backed execution fails due to client issues.
|
|
1037
1287
|
"""
|
|
1038
1288
|
# Backend routing: deployed agents use server, undeployed use local (if available)
|
|
1039
|
-
if self.id:
|
|
1289
|
+
if self.id and not local:
|
|
1040
1290
|
# Server-backed execution path (agent is deployed)
|
|
1041
1291
|
agent_client, call_kwargs = self._prepare_run_kwargs(
|
|
1042
|
-
message,
|
|
1292
|
+
message,
|
|
1293
|
+
verbose,
|
|
1294
|
+
runtime_config or kwargs.get("runtime_config"),
|
|
1295
|
+
**kwargs,
|
|
1043
1296
|
)
|
|
1044
1297
|
if chat_history is not None:
|
|
1045
1298
|
call_kwargs["chat_history"] = chat_history
|
|
@@ -1048,7 +1301,7 @@ class Agent:
|
|
|
1048
1301
|
yield chunk
|
|
1049
1302
|
return
|
|
1050
1303
|
|
|
1051
|
-
# Local execution path (agent is not deployed)
|
|
1304
|
+
# Local execution path (agent is not deployed OR local=True)
|
|
1052
1305
|
runner = self._get_local_runner_or_raise()
|
|
1053
1306
|
local_kwargs = self._prepare_local_runner_kwargs(message, verbose, runtime_config, chat_history, **kwargs)
|
|
1054
1307
|
result = await runner.arun(**local_kwargs)
|