glaip-sdk 0.6.5b3__py3-none-any.whl → 0.7.17__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.
Files changed (145) hide show
  1. glaip_sdk/__init__.py +42 -5
  2. glaip_sdk/agents/base.py +362 -39
  3. glaip_sdk/branding.py +113 -2
  4. glaip_sdk/cli/account_store.py +15 -0
  5. glaip_sdk/cli/auth.py +14 -8
  6. glaip_sdk/cli/commands/accounts.py +1 -1
  7. glaip_sdk/cli/commands/agents/__init__.py +116 -0
  8. glaip_sdk/cli/commands/agents/_common.py +562 -0
  9. glaip_sdk/cli/commands/agents/create.py +155 -0
  10. glaip_sdk/cli/commands/agents/delete.py +64 -0
  11. glaip_sdk/cli/commands/agents/get.py +89 -0
  12. glaip_sdk/cli/commands/agents/list.py +129 -0
  13. glaip_sdk/cli/commands/agents/run.py +264 -0
  14. glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
  15. glaip_sdk/cli/commands/agents/update.py +112 -0
  16. glaip_sdk/cli/commands/common_config.py +15 -12
  17. glaip_sdk/cli/commands/configure.py +2 -3
  18. glaip_sdk/cli/commands/mcps/__init__.py +94 -0
  19. glaip_sdk/cli/commands/mcps/_common.py +459 -0
  20. glaip_sdk/cli/commands/mcps/connect.py +82 -0
  21. glaip_sdk/cli/commands/mcps/create.py +152 -0
  22. glaip_sdk/cli/commands/mcps/delete.py +73 -0
  23. glaip_sdk/cli/commands/mcps/get.py +212 -0
  24. glaip_sdk/cli/commands/mcps/list.py +69 -0
  25. glaip_sdk/cli/commands/mcps/tools.py +235 -0
  26. glaip_sdk/cli/commands/mcps/update.py +190 -0
  27. glaip_sdk/cli/commands/models.py +2 -4
  28. glaip_sdk/cli/commands/shared/__init__.py +21 -0
  29. glaip_sdk/cli/commands/shared/formatters.py +91 -0
  30. glaip_sdk/cli/commands/tools/__init__.py +69 -0
  31. glaip_sdk/cli/commands/tools/_common.py +80 -0
  32. glaip_sdk/cli/commands/tools/create.py +228 -0
  33. glaip_sdk/cli/commands/tools/delete.py +61 -0
  34. glaip_sdk/cli/commands/tools/get.py +103 -0
  35. glaip_sdk/cli/commands/tools/list.py +69 -0
  36. glaip_sdk/cli/commands/tools/script.py +49 -0
  37. glaip_sdk/cli/commands/tools/update.py +102 -0
  38. glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
  39. glaip_sdk/cli/commands/transcripts/_common.py +9 -0
  40. glaip_sdk/cli/commands/transcripts/clear.py +5 -0
  41. glaip_sdk/cli/commands/transcripts/detail.py +5 -0
  42. glaip_sdk/cli/commands/{transcripts.py → transcripts_original.py} +2 -1
  43. glaip_sdk/cli/commands/update.py +163 -17
  44. glaip_sdk/cli/config.py +1 -0
  45. glaip_sdk/cli/core/output.py +12 -7
  46. glaip_sdk/cli/entrypoint.py +20 -0
  47. glaip_sdk/cli/main.py +127 -39
  48. glaip_sdk/cli/pager.py +3 -3
  49. glaip_sdk/cli/resolution.py +2 -1
  50. glaip_sdk/cli/slash/accounts_controller.py +112 -32
  51. glaip_sdk/cli/slash/agent_session.py +5 -2
  52. glaip_sdk/cli/slash/prompt.py +11 -0
  53. glaip_sdk/cli/slash/remote_runs_controller.py +3 -1
  54. glaip_sdk/cli/slash/session.py +375 -25
  55. glaip_sdk/cli/slash/tui/__init__.py +28 -1
  56. glaip_sdk/cli/slash/tui/accounts.tcss +97 -6
  57. glaip_sdk/cli/slash/tui/accounts_app.py +1107 -126
  58. glaip_sdk/cli/slash/tui/clipboard.py +195 -0
  59. glaip_sdk/cli/slash/tui/context.py +92 -0
  60. glaip_sdk/cli/slash/tui/indicators.py +341 -0
  61. glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
  62. glaip_sdk/cli/slash/tui/layouts/__init__.py +14 -0
  63. glaip_sdk/cli/slash/tui/layouts/harlequin.py +184 -0
  64. glaip_sdk/cli/slash/tui/loading.py +43 -21
  65. glaip_sdk/cli/slash/tui/remote_runs_app.py +152 -20
  66. glaip_sdk/cli/slash/tui/terminal.py +407 -0
  67. glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
  68. glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
  69. glaip_sdk/cli/slash/tui/theme/manager.py +112 -0
  70. glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
  71. glaip_sdk/cli/slash/tui/toast.py +388 -0
  72. glaip_sdk/cli/transcript/history.py +1 -1
  73. glaip_sdk/cli/transcript/viewer.py +5 -3
  74. glaip_sdk/cli/tui_settings.py +125 -0
  75. glaip_sdk/cli/update_notifier.py +215 -7
  76. glaip_sdk/cli/validators.py +1 -1
  77. glaip_sdk/client/__init__.py +2 -1
  78. glaip_sdk/client/_schedule_payloads.py +89 -0
  79. glaip_sdk/client/agents.py +290 -16
  80. glaip_sdk/client/base.py +25 -0
  81. glaip_sdk/client/hitl.py +136 -0
  82. glaip_sdk/client/main.py +7 -5
  83. glaip_sdk/client/mcps.py +44 -13
  84. glaip_sdk/client/payloads/agent/__init__.py +23 -0
  85. glaip_sdk/client/{_agent_payloads.py → payloads/agent/requests.py} +28 -48
  86. glaip_sdk/client/payloads/agent/responses.py +43 -0
  87. glaip_sdk/client/run_rendering.py +414 -3
  88. glaip_sdk/client/schedules.py +439 -0
  89. glaip_sdk/client/tools.py +57 -26
  90. glaip_sdk/config/constants.py +22 -2
  91. glaip_sdk/guardrails/__init__.py +80 -0
  92. glaip_sdk/guardrails/serializer.py +89 -0
  93. glaip_sdk/hitl/__init__.py +48 -0
  94. glaip_sdk/hitl/base.py +64 -0
  95. glaip_sdk/hitl/callback.py +43 -0
  96. glaip_sdk/hitl/local.py +121 -0
  97. glaip_sdk/hitl/remote.py +523 -0
  98. glaip_sdk/models/__init__.py +47 -1
  99. glaip_sdk/models/_provider_mappings.py +101 -0
  100. glaip_sdk/models/_validation.py +97 -0
  101. glaip_sdk/models/agent.py +2 -1
  102. glaip_sdk/models/agent_runs.py +2 -1
  103. glaip_sdk/models/constants.py +141 -0
  104. glaip_sdk/models/model.py +170 -0
  105. glaip_sdk/models/schedule.py +224 -0
  106. glaip_sdk/payload_schemas/agent.py +1 -0
  107. glaip_sdk/payload_schemas/guardrails.py +34 -0
  108. glaip_sdk/registry/tool.py +273 -66
  109. glaip_sdk/runner/__init__.py +76 -0
  110. glaip_sdk/runner/base.py +84 -0
  111. glaip_sdk/runner/deps.py +115 -0
  112. glaip_sdk/runner/langgraph.py +1055 -0
  113. glaip_sdk/runner/logging_config.py +77 -0
  114. glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
  115. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
  116. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
  117. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +116 -0
  118. glaip_sdk/runner/tool_adapter/__init__.py +18 -0
  119. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
  120. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +242 -0
  121. glaip_sdk/schedules/__init__.py +22 -0
  122. glaip_sdk/schedules/base.py +291 -0
  123. glaip_sdk/tools/base.py +67 -14
  124. glaip_sdk/utils/__init__.py +1 -0
  125. glaip_sdk/utils/a2a/__init__.py +34 -0
  126. glaip_sdk/utils/a2a/event_processor.py +188 -0
  127. glaip_sdk/utils/agent_config.py +8 -2
  128. glaip_sdk/utils/bundler.py +138 -2
  129. glaip_sdk/utils/import_resolver.py +43 -11
  130. glaip_sdk/utils/rendering/renderer/base.py +58 -0
  131. glaip_sdk/utils/runtime_config.py +120 -0
  132. glaip_sdk/utils/sync.py +31 -11
  133. glaip_sdk/utils/tool_detection.py +301 -0
  134. glaip_sdk/utils/tool_storage_provider.py +140 -0
  135. {glaip_sdk-0.6.5b3.dist-info → glaip_sdk-0.7.17.dist-info}/METADATA +49 -38
  136. glaip_sdk-0.7.17.dist-info/RECORD +224 -0
  137. {glaip_sdk-0.6.5b3.dist-info → glaip_sdk-0.7.17.dist-info}/WHEEL +2 -1
  138. glaip_sdk-0.7.17.dist-info/entry_points.txt +2 -0
  139. glaip_sdk-0.7.17.dist-info/top_level.txt +1 -0
  140. glaip_sdk/cli/commands/agents.py +0 -1509
  141. glaip_sdk/cli/commands/mcps.py +0 -1356
  142. glaip_sdk/cli/commands/tools.py +0 -576
  143. glaip_sdk/cli/utils.py +0 -263
  144. glaip_sdk-0.6.5b3.dist-info/RECORD +0 -145
  145. glaip_sdk-0.6.5b3.dist-info/entry_points.txt +0 -3
glaip_sdk/client/main.py CHANGED
@@ -12,13 +12,15 @@ from typing import TYPE_CHECKING, Any
12
12
 
13
13
  from glaip_sdk.client.agents import AgentClient
14
14
  from glaip_sdk.client.base import BaseClient
15
+ from glaip_sdk.client.hitl import HITLClient
15
16
  from glaip_sdk.client.mcps import MCPClient
17
+ from glaip_sdk.client.schedules import ScheduleClient
16
18
  from glaip_sdk.client.shared import build_shared_config
17
19
  from glaip_sdk.client.tools import ToolClient
18
20
 
19
21
  if TYPE_CHECKING: # pragma: no cover
20
22
  from glaip_sdk.agents import Agent
21
- from glaip_sdk.client._agent_payloads import AgentListResult
23
+ from glaip_sdk.client.payloads.agent import AgentListResult
22
24
  from glaip_sdk.mcps import MCP
23
25
  from glaip_sdk.tools import Tool
24
26
 
@@ -38,6 +40,8 @@ class Client(BaseClient):
38
40
  self.agents = AgentClient(**shared_config)
39
41
  self.tools = ToolClient(**shared_config)
40
42
  self.mcps = MCPClient(**shared_config)
43
+ self.schedules = ScheduleClient(**shared_config)
44
+ self.hitl = HITLClient(**shared_config)
41
45
 
42
46
  # ---- Core API Methods (Public Interface) ----
43
47
 
@@ -208,10 +212,6 @@ class Client(BaseClient):
208
212
  return self.mcps.get_mcp_tools_from_config(config)
209
213
 
210
214
  # Language Models
211
- def list_language_models(self) -> list[dict]:
212
- """List available language models."""
213
- data = self._request("GET", "/language-models")
214
- return data or []
215
215
 
216
216
  # ---- Timeout propagation ----
217
217
  @property
@@ -236,6 +236,8 @@ class Client(BaseClient):
236
236
  self.tools.http_client = self.http_client
237
237
  if hasattr(self, "mcps"):
238
238
  self.mcps.http_client = self.http_client
239
+ if hasattr(self, "schedules"):
240
+ self.schedules.http_client = self.http_client
239
241
  except Exception:
240
242
  pass
241
243
 
glaip_sdk/client/mcps.py CHANGED
@@ -85,26 +85,56 @@ class MCPClient(BaseClient):
85
85
  response = MCPResponse(**full_mcp_data)
86
86
  return MCP.from_response(response, client=self)
87
87
 
88
- def update_mcp(self, mcp_id: str, **kwargs) -> MCP:
88
+ def update_mcp(self, mcp_id: str | MCP, **kwargs) -> MCP:
89
89
  """Update an existing MCP.
90
90
 
91
- Automatically chooses between PUT (full update) and PATCH (partial update)
92
- based on the provided fields:
93
- - Uses PUT if name, config, and transport are all provided (full update)
94
- - Uses PATCH otherwise (partial update)
91
+ Notes:
92
+ - Payload construction is centralized via ``_build_update_payload`` so required
93
+ defaults (e.g., ``type``) and value normalization stay consistent across SDK and CLI.
94
+ - For backward compatibility, still chooses PATCH vs PUT based on which fields the
95
+ caller provided, but uses the SDK payload builder for the final payload.
95
96
  """
96
- # Check if all required fields for full update are provided
97
+ # Backward-compatible: allow passing an MCP instance to avoid an extra fetch.
98
+ if isinstance(mcp_id, MCP):
99
+ current_mcp = mcp_id
100
+ if not current_mcp.id:
101
+ raise ValueError("MCP instance has no id; cannot update.")
102
+ mcp_id_value = str(current_mcp.id)
103
+ else:
104
+ current_mcp = None
105
+ mcp_id_value = mcp_id
106
+
97
107
  required_fields = {"name", "config", "transport"}
98
108
  provided_fields = set(kwargs.keys())
109
+ method = "PUT" if required_fields.issubset(provided_fields) else "PATCH"
110
+
111
+ if not kwargs:
112
+ data = self._request(method, f"{MCPS_ENDPOINT}{mcp_id_value}", json={})
113
+ response = MCPResponse(**data)
114
+ return MCP.from_response(response, client=self)
115
+
116
+ if current_mcp is None:
117
+ current_mcp = self.get_mcp_by_id(mcp_id_value)
118
+
119
+ payload_kwargs = kwargs.copy()
120
+ name = payload_kwargs.pop("name", None)
121
+ description = payload_kwargs.pop("description", None)
122
+ full_payload = self._build_update_payload(
123
+ current_mcp=current_mcp,
124
+ name=name,
125
+ description=description,
126
+ **payload_kwargs,
127
+ )
99
128
 
100
- if required_fields.issubset(provided_fields):
101
- # All required fields provided - use full update (PUT)
102
- method = "PUT"
129
+ if method == "PUT":
130
+ json_payload = full_payload
103
131
  else:
104
- # Partial update - use PATCH
105
- method = "PATCH"
132
+ json_payload = {key: full_payload[key] for key in provided_fields if key in full_payload}
133
+ json_payload["type"] = full_payload["type"]
134
+ if "config" in provided_fields and "transport" not in provided_fields and "transport" in full_payload:
135
+ json_payload["transport"] = full_payload["transport"]
106
136
 
107
- data = self._request(method, f"{MCPS_ENDPOINT}{mcp_id}", json=kwargs)
137
+ data = self._request(method, f"{MCPS_ENDPOINT}{mcp_id_value}", json=json_payload)
108
138
  response = MCPResponse(**data)
109
139
  return MCP.from_response(response, client=self)
110
140
 
@@ -188,7 +218,8 @@ class MCPClient(BaseClient):
188
218
  **kwargs,
189
219
  ) -> MCP:
190
220
  """Find by name and update, or create if not found."""
191
- existing = self.find_mcps(name)
221
+ all_mcps = self.list_mcps()
222
+ existing = [mcp for mcp in all_mcps if mcp.name.lower() == name.lower()]
192
223
 
193
224
  if len(existing) == 1:
194
225
  logger.info("Updating existing MCP: %s", name)
@@ -0,0 +1,23 @@
1
+ """Agent payload types for requests and responses.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from glaip_sdk.client.payloads.agent.requests import (
8
+ AgentCreateRequest,
9
+ AgentListParams,
10
+ AgentUpdateRequest,
11
+ merge_payload_fields,
12
+ resolve_language_model_fields,
13
+ )
14
+ from glaip_sdk.client.payloads.agent.responses import AgentListResult
15
+
16
+ __all__ = [
17
+ "AgentCreateRequest",
18
+ "AgentListParams",
19
+ "AgentListResult",
20
+ "AgentUpdateRequest",
21
+ "merge_payload_fields",
22
+ "resolve_language_model_fields",
23
+ ]
@@ -1,11 +1,15 @@
1
- #!/usr/bin/env python3
2
- """Shared helpers for Agent client payload construction and query handling."""
1
+ """Agent request payload types and helpers.
3
2
 
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ # pylint: disable=duplicate-code
4
8
  from __future__ import annotations
5
9
 
6
10
  from collections.abc import Callable, Mapping, MutableMapping, Sequence
7
11
  from copy import deepcopy
8
- from dataclasses import dataclass, field
12
+ from dataclasses import dataclass
9
13
  from typing import Any
10
14
 
11
15
  from glaip_sdk.config.constants import (
@@ -13,8 +17,8 @@ from glaip_sdk.config.constants import (
13
17
  DEFAULT_AGENT_PROVIDER,
14
18
  DEFAULT_AGENT_TYPE,
15
19
  DEFAULT_AGENT_VERSION,
16
- DEFAULT_MODEL,
17
20
  )
21
+ from glaip_sdk.models.constants import DEFAULT_MODEL
18
22
  from glaip_sdk.payload_schemas.agent import AgentImportOperation, get_import_field_plan
19
23
  from glaip_sdk.utils.client_utils import extract_ids
20
24
 
@@ -96,6 +100,11 @@ def resolve_language_model_fields(
96
100
  resolved_model = model_name or model or default_model
97
101
  resolved_provider = provider if provider is not None else default_provider
98
102
 
103
+ if resolved_model and isinstance(resolved_model, str) and "/" in resolved_model:
104
+ parts = resolved_model.split("/", 1)
105
+ resolved_provider = parts[0]
106
+ resolved_model = parts[1]
107
+
99
108
  result: dict[str, Any] = {}
100
109
  if resolved_model is not None:
101
110
  result["model_name"] = resolved_model
@@ -273,38 +282,6 @@ class AgentListParams:
273
282
  params[f"metadata.{key}"] = value
274
283
 
275
284
 
276
- @dataclass(slots=True)
277
- class AgentListResult:
278
- """Structured response for list_agents that retains pagination metadata."""
279
-
280
- items: list[Any] = field(default_factory=list)
281
- total: int | None = None
282
- page: int | None = None
283
- limit: int | None = None
284
- has_next: bool | None = None
285
- has_prev: bool | None = None
286
- message: str | None = None
287
-
288
- def __len__(self) -> int: # pragma: no cover - simple delegation
289
- """Return the number of items in the result list."""
290
- return len(self.items)
291
-
292
- def __iter__(self): # pragma: no cover - simple delegation
293
- """Return an iterator over the items in the result list."""
294
- return iter(self.items)
295
-
296
- def __getitem__(self, index: int) -> Any: # pragma: no cover - simple delegation
297
- """Get an item from the result list by index.
298
-
299
- Args:
300
- index: Index of the item to retrieve.
301
-
302
- Returns:
303
- The item at the specified index.
304
- """
305
- return self.items[index]
306
-
307
-
308
285
  @dataclass(slots=True)
309
286
  class AgentCreateRequest:
310
287
  """Declarative representation of an agent creation payload."""
@@ -422,16 +399,6 @@ class AgentUpdateRequest:
422
399
  return payload
423
400
 
424
401
 
425
- __all__ = [
426
- "AgentCreateRequest",
427
- "AgentListParams",
428
- "AgentListResult",
429
- "AgentUpdateRequest",
430
- "merge_payload_fields",
431
- "resolve_language_model_fields",
432
- ]
433
-
434
-
435
402
  def _build_base_update_payload(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
436
403
  """Populate immutable agent update fields using request data or existing agent defaults."""
437
404
  # Support both "agent_type" (runtime class) and "type" (API response) attributes
@@ -451,14 +418,27 @@ def _build_base_update_payload(request: AgentUpdateRequest, current_agent: Any)
451
418
 
452
419
  def _resolve_update_language_model_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
453
420
  """Resolve the language-model portion of an update request with sensible fallbacks."""
421
+ # Check if any LM inputs were provided
422
+ has_lm_inputs = any(
423
+ [
424
+ request.model is not None,
425
+ request.language_model_id is not None,
426
+ request.provider is not None,
427
+ request.model_name is not None,
428
+ ]
429
+ )
430
+
431
+ if not has_lm_inputs:
432
+ # No LM inputs provided - preserve existing fields
433
+ return _existing_language_model_fields(current_agent)
434
+
435
+ # LM inputs provided - resolve them (may return defaults if only partial info)
454
436
  fields = resolve_language_model_fields(
455
437
  model=request.model,
456
438
  language_model_id=request.language_model_id,
457
439
  provider=request.provider,
458
440
  model_name=request.model_name,
459
441
  )
460
- if not fields:
461
- fields = _existing_language_model_fields(current_agent)
462
442
  return fields
463
443
 
464
444
 
@@ -0,0 +1,43 @@
1
+ """Agent response payload types.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ # pylint: disable=duplicate-code
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+ from typing import Any
12
+
13
+
14
+ @dataclass(slots=True)
15
+ class AgentListResult:
16
+ """Structured response for list_agents that retains pagination metadata."""
17
+
18
+ items: list[Any] = field(default_factory=list)
19
+ total: int | None = None
20
+ page: int | None = None
21
+ limit: int | None = None
22
+ has_next: bool | None = None
23
+ has_prev: bool | None = None
24
+ message: str | None = None
25
+
26
+ def __len__(self) -> int: # pragma: no cover - simple delegation
27
+ """Return the number of items in the result list."""
28
+ return len(self.items)
29
+
30
+ def __iter__(self): # pragma: no cover - simple delegation
31
+ """Return an iterator over the items in the result list."""
32
+ return iter(self.items)
33
+
34
+ def __getitem__(self, index: int) -> Any: # pragma: no cover - simple delegation
35
+ """Get an item from the result list by index.
36
+
37
+ Args:
38
+ index: Index of the item to retrieve.
39
+
40
+ Returns:
41
+ The item at the specified index.
42
+ """
43
+ return self.items[index]