glaip-sdk 0.6.12__py3-none-any.whl → 0.6.15__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 (156) hide show
  1. glaip_sdk/__init__.py +42 -5
  2. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.15.dist-info}/METADATA +32 -37
  3. glaip_sdk-0.6.15.dist-info/RECORD +12 -0
  4. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.15.dist-info}/WHEEL +2 -1
  5. glaip_sdk-0.6.15.dist-info/entry_points.txt +2 -0
  6. glaip_sdk-0.6.15.dist-info/top_level.txt +1 -0
  7. glaip_sdk/agents/__init__.py +0 -27
  8. glaip_sdk/agents/base.py +0 -1191
  9. glaip_sdk/cli/__init__.py +0 -9
  10. glaip_sdk/cli/account_store.py +0 -540
  11. glaip_sdk/cli/agent_config.py +0 -78
  12. glaip_sdk/cli/auth.py +0 -699
  13. glaip_sdk/cli/commands/__init__.py +0 -5
  14. glaip_sdk/cli/commands/accounts.py +0 -746
  15. glaip_sdk/cli/commands/agents.py +0 -1509
  16. glaip_sdk/cli/commands/common_config.py +0 -101
  17. glaip_sdk/cli/commands/configure.py +0 -896
  18. glaip_sdk/cli/commands/mcps.py +0 -1356
  19. glaip_sdk/cli/commands/models.py +0 -69
  20. glaip_sdk/cli/commands/tools.py +0 -576
  21. glaip_sdk/cli/commands/transcripts.py +0 -755
  22. glaip_sdk/cli/commands/update.py +0 -61
  23. glaip_sdk/cli/config.py +0 -95
  24. glaip_sdk/cli/constants.py +0 -38
  25. glaip_sdk/cli/context.py +0 -150
  26. glaip_sdk/cli/core/__init__.py +0 -79
  27. glaip_sdk/cli/core/context.py +0 -124
  28. glaip_sdk/cli/core/output.py +0 -846
  29. glaip_sdk/cli/core/prompting.py +0 -649
  30. glaip_sdk/cli/core/rendering.py +0 -187
  31. glaip_sdk/cli/display.py +0 -355
  32. glaip_sdk/cli/hints.py +0 -57
  33. glaip_sdk/cli/io.py +0 -112
  34. glaip_sdk/cli/main.py +0 -604
  35. glaip_sdk/cli/masking.py +0 -136
  36. glaip_sdk/cli/mcp_validators.py +0 -287
  37. glaip_sdk/cli/pager.py +0 -266
  38. glaip_sdk/cli/parsers/__init__.py +0 -7
  39. glaip_sdk/cli/parsers/json_input.py +0 -177
  40. glaip_sdk/cli/resolution.py +0 -67
  41. glaip_sdk/cli/rich_helpers.py +0 -27
  42. glaip_sdk/cli/slash/__init__.py +0 -15
  43. glaip_sdk/cli/slash/accounts_controller.py +0 -578
  44. glaip_sdk/cli/slash/accounts_shared.py +0 -75
  45. glaip_sdk/cli/slash/agent_session.py +0 -285
  46. glaip_sdk/cli/slash/prompt.py +0 -256
  47. glaip_sdk/cli/slash/remote_runs_controller.py +0 -566
  48. glaip_sdk/cli/slash/session.py +0 -1708
  49. glaip_sdk/cli/slash/tui/__init__.py +0 -9
  50. glaip_sdk/cli/slash/tui/accounts_app.py +0 -876
  51. glaip_sdk/cli/slash/tui/background_tasks.py +0 -72
  52. glaip_sdk/cli/slash/tui/loading.py +0 -58
  53. glaip_sdk/cli/slash/tui/remote_runs_app.py +0 -628
  54. glaip_sdk/cli/transcript/__init__.py +0 -31
  55. glaip_sdk/cli/transcript/cache.py +0 -536
  56. glaip_sdk/cli/transcript/capture.py +0 -329
  57. glaip_sdk/cli/transcript/export.py +0 -38
  58. glaip_sdk/cli/transcript/history.py +0 -815
  59. glaip_sdk/cli/transcript/launcher.py +0 -77
  60. glaip_sdk/cli/transcript/viewer.py +0 -374
  61. glaip_sdk/cli/update_notifier.py +0 -290
  62. glaip_sdk/cli/utils.py +0 -263
  63. glaip_sdk/cli/validators.py +0 -238
  64. glaip_sdk/client/__init__.py +0 -11
  65. glaip_sdk/client/_agent_payloads.py +0 -520
  66. glaip_sdk/client/agent_runs.py +0 -147
  67. glaip_sdk/client/agents.py +0 -1335
  68. glaip_sdk/client/base.py +0 -502
  69. glaip_sdk/client/main.py +0 -249
  70. glaip_sdk/client/mcps.py +0 -370
  71. glaip_sdk/client/run_rendering.py +0 -700
  72. glaip_sdk/client/shared.py +0 -21
  73. glaip_sdk/client/tools.py +0 -661
  74. glaip_sdk/client/validators.py +0 -198
  75. glaip_sdk/config/constants.py +0 -52
  76. glaip_sdk/mcps/__init__.py +0 -21
  77. glaip_sdk/mcps/base.py +0 -345
  78. glaip_sdk/models/__init__.py +0 -90
  79. glaip_sdk/models/agent.py +0 -47
  80. glaip_sdk/models/agent_runs.py +0 -116
  81. glaip_sdk/models/common.py +0 -42
  82. glaip_sdk/models/mcp.py +0 -33
  83. glaip_sdk/models/tool.py +0 -33
  84. glaip_sdk/payload_schemas/__init__.py +0 -7
  85. glaip_sdk/payload_schemas/agent.py +0 -85
  86. glaip_sdk/registry/__init__.py +0 -55
  87. glaip_sdk/registry/agent.py +0 -164
  88. glaip_sdk/registry/base.py +0 -139
  89. glaip_sdk/registry/mcp.py +0 -253
  90. glaip_sdk/registry/tool.py +0 -232
  91. glaip_sdk/runner/__init__.py +0 -59
  92. glaip_sdk/runner/base.py +0 -84
  93. glaip_sdk/runner/deps.py +0 -115
  94. glaip_sdk/runner/langgraph.py +0 -782
  95. glaip_sdk/runner/mcp_adapter/__init__.py +0 -13
  96. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +0 -43
  97. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +0 -257
  98. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +0 -95
  99. glaip_sdk/runner/tool_adapter/__init__.py +0 -18
  100. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +0 -44
  101. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +0 -219
  102. glaip_sdk/tools/__init__.py +0 -22
  103. glaip_sdk/tools/base.py +0 -435
  104. glaip_sdk/utils/__init__.py +0 -86
  105. glaip_sdk/utils/a2a/__init__.py +0 -34
  106. glaip_sdk/utils/a2a/event_processor.py +0 -188
  107. glaip_sdk/utils/agent_config.py +0 -194
  108. glaip_sdk/utils/bundler.py +0 -267
  109. glaip_sdk/utils/client.py +0 -111
  110. glaip_sdk/utils/client_utils.py +0 -486
  111. glaip_sdk/utils/datetime_helpers.py +0 -58
  112. glaip_sdk/utils/discovery.py +0 -78
  113. glaip_sdk/utils/display.py +0 -135
  114. glaip_sdk/utils/export.py +0 -143
  115. glaip_sdk/utils/general.py +0 -61
  116. glaip_sdk/utils/import_export.py +0 -168
  117. glaip_sdk/utils/import_resolver.py +0 -492
  118. glaip_sdk/utils/instructions.py +0 -101
  119. glaip_sdk/utils/rendering/__init__.py +0 -115
  120. glaip_sdk/utils/rendering/formatting.py +0 -264
  121. glaip_sdk/utils/rendering/layout/__init__.py +0 -64
  122. glaip_sdk/utils/rendering/layout/panels.py +0 -156
  123. glaip_sdk/utils/rendering/layout/progress.py +0 -202
  124. glaip_sdk/utils/rendering/layout/summary.py +0 -74
  125. glaip_sdk/utils/rendering/layout/transcript.py +0 -606
  126. glaip_sdk/utils/rendering/models.py +0 -85
  127. glaip_sdk/utils/rendering/renderer/__init__.py +0 -55
  128. glaip_sdk/utils/rendering/renderer/base.py +0 -1024
  129. glaip_sdk/utils/rendering/renderer/config.py +0 -27
  130. glaip_sdk/utils/rendering/renderer/console.py +0 -55
  131. glaip_sdk/utils/rendering/renderer/debug.py +0 -178
  132. glaip_sdk/utils/rendering/renderer/factory.py +0 -138
  133. glaip_sdk/utils/rendering/renderer/stream.py +0 -202
  134. glaip_sdk/utils/rendering/renderer/summary_window.py +0 -79
  135. glaip_sdk/utils/rendering/renderer/thinking.py +0 -273
  136. glaip_sdk/utils/rendering/renderer/toggle.py +0 -182
  137. glaip_sdk/utils/rendering/renderer/tool_panels.py +0 -442
  138. glaip_sdk/utils/rendering/renderer/transcript_mode.py +0 -162
  139. glaip_sdk/utils/rendering/state.py +0 -204
  140. glaip_sdk/utils/rendering/step_tree_state.py +0 -100
  141. glaip_sdk/utils/rendering/steps/__init__.py +0 -34
  142. glaip_sdk/utils/rendering/steps/event_processor.py +0 -778
  143. glaip_sdk/utils/rendering/steps/format.py +0 -176
  144. glaip_sdk/utils/rendering/steps/manager.py +0 -387
  145. glaip_sdk/utils/rendering/timing.py +0 -36
  146. glaip_sdk/utils/rendering/viewer/__init__.py +0 -21
  147. glaip_sdk/utils/rendering/viewer/presenter.py +0 -184
  148. glaip_sdk/utils/resource_refs.py +0 -195
  149. glaip_sdk/utils/run_renderer.py +0 -41
  150. glaip_sdk/utils/runtime_config.py +0 -425
  151. glaip_sdk/utils/serialization.py +0 -424
  152. glaip_sdk/utils/sync.py +0 -142
  153. glaip_sdk/utils/tool_detection.py +0 -33
  154. glaip_sdk/utils/validation.py +0 -264
  155. glaip_sdk-0.6.12.dist-info/RECORD +0 -159
  156. glaip_sdk-0.6.12.dist-info/entry_points.txt +0 -3
@@ -1,139 +0,0 @@
1
- """Abstract base registry for caching platform objects.
2
-
3
- This module provides the BaseRegistry abstract class that serves as the
4
- foundation for type-specific registries (AgentRegistry, ToolRegistry, MCPRegistry).
5
-
6
- The registry pattern provides:
7
- - In-memory caching to avoid redundant API calls
8
- - Transparent resolution of various reference types
9
- - Simple invalidation and cache management
10
-
11
- Authors:
12
- Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
13
- """
14
-
15
- from __future__ import annotations
16
-
17
- import logging
18
- from abc import ABC, abstractmethod
19
- from typing import Any, Generic, TypeVar
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
-
24
- T = TypeVar("T")
25
-
26
-
27
- class BaseRegistry(ABC, Generic[T]):
28
- """Abstract base registry for caching platform objects.
29
-
30
- Provides a caching layer between local code and the AIP platform.
31
- Subclasses implement type-specific resolution logic.
32
-
33
- The registry follows a simple flow:
34
- 1. Check if reference is already a platform object → return as-is
35
- 2. Extract name from reference
36
- 3. Check cache → return if found
37
- 4. Resolve via subclass logic → cache and return
38
-
39
- Attributes:
40
- _cache: Internal cache mapping names to objects.
41
-
42
- Example:
43
- >>> class MyRegistry(BaseRegistry):
44
- ... def _extract_name(self, ref: Any) -> str:
45
- ... return ref.name if hasattr(ref, 'name') else str(ref)
46
- ...
47
- ... def _resolve_and_cache(self, ref: Any, name: str) -> MyType:
48
- ... obj = fetch_from_platform(name)
49
- ... self._cache[name] = obj
50
- ... return obj
51
- """
52
-
53
- def __init__(self) -> None:
54
- """Initialize the registry with an empty cache."""
55
- self._cache: dict[str, T] = {}
56
-
57
- def resolve(self, ref: Any) -> T:
58
- """Resolve a reference to a platform object.
59
-
60
- This is the main entry point for the registry. It handles:
61
- - Cached references (returned from cache)
62
- - New references (resolved via subclass, then cached)
63
-
64
- Args:
65
- ref: A reference to resolve. Can be a class, string name,
66
- or platform object depending on the registry type.
67
-
68
- Returns:
69
- The resolved platform object.
70
-
71
- Raises:
72
- ValueError: If the reference cannot be resolved.
73
- """
74
- name = self._extract_name(ref)
75
-
76
- if name in self._cache:
77
- logger.debug("Cache hit: %s", name)
78
- return self._cache[name]
79
-
80
- return self._resolve_and_cache(ref, name)
81
-
82
- def get(self, name: str) -> T | None:
83
- """Get a cached object by name.
84
-
85
- Args:
86
- name: The name of the object to retrieve.
87
-
88
- Returns:
89
- The cached object, or None if not found.
90
- """
91
- return self._cache.get(name)
92
-
93
- def invalidate(self, name: str) -> None:
94
- """Remove an object from the cache.
95
-
96
- Use this to force a re-fetch on the next resolve call.
97
-
98
- Args:
99
- name: The name of the object to invalidate.
100
- """
101
- self._cache.pop(name, None)
102
- logger.debug("Invalidated cache entry: %s", name)
103
-
104
- def clear(self) -> None:
105
- """Clear all cached entries."""
106
- self._cache.clear()
107
- logger.debug("Cleared registry cache")
108
-
109
- @abstractmethod
110
- def _extract_name(self, ref: Any) -> str:
111
- """Extract the name from a reference.
112
-
113
- Args:
114
- ref: The reference to extract a name from.
115
-
116
- Returns:
117
- The extracted name string.
118
-
119
- Raises:
120
- ValueError: If name cannot be extracted.
121
- """
122
-
123
- @abstractmethod
124
- def _resolve_and_cache(self, ref: Any, name: str) -> T:
125
- """Resolve the reference and cache the result.
126
-
127
- Subclasses implement type-specific resolution logic here.
128
- This method MUST cache the result in self._cache[name].
129
-
130
- Args:
131
- ref: The reference to resolve.
132
- name: The extracted name for caching.
133
-
134
- Returns:
135
- The resolved platform object.
136
-
137
- Raises:
138
- ValueError: If resolution fails.
139
- """
glaip_sdk/registry/mcp.py DELETED
@@ -1,253 +0,0 @@
1
- """MCP registry for glaip_sdk.
2
-
3
- This module provides the MCPRegistry that caches MCPs (Model Context Protocols)
4
- to avoid redundant API calls when deploying agents with MCPs.
5
-
6
- Authors:
7
- Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
8
- """
9
-
10
- from __future__ import annotations
11
-
12
- import logging
13
- from typing import TYPE_CHECKING, Any
14
-
15
- from glaip_sdk.registry.base import BaseRegistry
16
- from glaip_sdk.utils.resource_refs import is_uuid
17
-
18
- if TYPE_CHECKING:
19
- from glaip_sdk.mcps import MCP
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
-
24
- class MCPRegistry(BaseRegistry["MCP"]):
25
- """Registry for MCPs (Model Context Protocols).
26
-
27
- Resolves MCP references to glaip_sdk.models.MCP objects.
28
- Caches results to avoid redundant API calls.
29
-
30
- Handles:
31
- - glaip_sdk.models.MCP → return as-is (uses mcp.id)
32
- - String names/IDs → lookup on platform, cache, return MCP
33
-
34
- Attributes:
35
- _cache: Internal cache mapping names to MCP objects.
36
-
37
- Example:
38
- >>> registry = get_mcp_registry()
39
- >>> mcp = registry.resolve("arxiv-mcp")
40
- >>> print(mcp.id)
41
- """
42
-
43
- def _extract_name(self, ref: Any) -> str:
44
- """Extract MCP name from a reference.
45
-
46
- Args:
47
- ref: An MCP object, dict, or string name.
48
-
49
- Returns:
50
- The extracted MCP name.
51
-
52
- Raises:
53
- ValueError: If name cannot be extracted from the reference.
54
- """
55
- # String name
56
- if isinstance(ref, str):
57
- return ref
58
-
59
- # Dict from API response - extract name or id
60
- if isinstance(ref, dict):
61
- return ref.get("name") or ref.get("id") or ""
62
-
63
- # Already resolved MCP (glaip_sdk.models.MCP)
64
- if hasattr(ref, "id") and hasattr(ref, "name") and not isinstance(ref, type):
65
- return ref.name or ref.id
66
-
67
- raise ValueError(f"Cannot extract name from: {ref}")
68
-
69
- def _resolve_and_cache(self, ref: Any, name: str) -> MCP:
70
- """Resolve MCP reference - find by name/ID or create if needed.
71
-
72
- Args:
73
- ref: The MCP reference to resolve.
74
- name: The extracted MCP name.
75
-
76
- Returns:
77
- The resolved glaip_sdk.models.MCP object.
78
-
79
- Raises:
80
- ValueError: If the MCP cannot be resolved.
81
- """
82
- # MCP object (check if already has ID)
83
- if hasattr(ref, "id") and hasattr(ref, "name") and not isinstance(ref, type):
84
- if ref.id is not None:
85
- # Already resolved MCP with ID - just cache and return
86
- logger.debug("Caching already resolved MCP: %s", name)
87
- self._cache[name] = ref
88
- return ref
89
-
90
- # MCP without ID - need to look up or create
91
- return self._lookup_or_create_mcp(ref, name)
92
-
93
- # Dict from API response - use ID directly if available
94
- if isinstance(ref, dict):
95
- mcp_id = ref.get("id")
96
- if mcp_id:
97
- from glaip_sdk.mcps.base import MCP # noqa: PLC0415
98
-
99
- mcp = MCP(id=mcp_id, name=ref.get("name", ""))
100
- self._cache[name] = mcp
101
- return mcp
102
- raise ValueError(f"MCP dict missing 'id': {ref}")
103
-
104
- # String name - look up on platform
105
- if isinstance(ref, str):
106
- return self._lookup_mcp_by_name(name)
107
-
108
- raise ValueError(f"Could not resolve MCP reference: {ref}")
109
-
110
- def _lookup_or_create_mcp(self, ref: Any, name: str) -> MCP:
111
- """Look up or create an MCP from a reference.
112
-
113
- Args:
114
- ref: The MCP reference with config details.
115
- name: The extracted MCP name.
116
-
117
- Returns:
118
- The resolved or created glaip_sdk.models.MCP object.
119
- """
120
- # Check if this MCP is lookup-only (e.g., from MCP.from_native)
121
- if getattr(ref, "_lookup_only", False):
122
- return self._lookup_native_mcp(name)
123
-
124
- return self._upsert_mcp_from_ref(ref, name)
125
-
126
- def _lookup_native_mcp(self, name: str) -> MCP:
127
- """Look up a native MCP that must exist on the platform.
128
-
129
- Used for MCP.from_native() references that should not be created.
130
-
131
- Args:
132
- name: The MCP name to look up.
133
-
134
- Returns:
135
- The found MCP.
136
-
137
- Raises:
138
- ValueError: If MCP not found or multiple found.
139
- """
140
- from glaip_sdk.utils.client import get_client # noqa: PLC0415
141
-
142
- client = get_client()
143
- logger.info("Looking up native MCP: %s", name)
144
-
145
- results = client.find_mcps(name)
146
- exact_matches = [mcp for mcp in results if getattr(mcp, "name", None) == name]
147
- if len(exact_matches) == 1:
148
- mcp = exact_matches[0]
149
- self._cache[name] = mcp
150
- return mcp
151
- if len(exact_matches) > 1:
152
- raise ValueError(f"Multiple MCPs found with name '{name}'")
153
- raise ValueError(f"MCP not found on platform: {name}")
154
-
155
- def _upsert_mcp_from_ref(self, ref: Any, name: str) -> MCP:
156
- """Create or update an MCP from a reference with config.
157
-
158
- Args:
159
- ref: The MCP reference with config details.
160
- name: The extracted MCP name.
161
-
162
- Returns:
163
- The created or updated MCP.
164
- """
165
- from glaip_sdk.utils.client import get_client # noqa: PLC0415
166
-
167
- client = get_client()
168
- logger.info("Upserting MCP: %s", name)
169
-
170
- mcp = client.mcps.upsert_mcp(
171
- name,
172
- description=getattr(ref, "description", None),
173
- config=getattr(ref, "config", None),
174
- transport=getattr(ref, "transport", None),
175
- metadata=getattr(ref, "metadata", None),
176
- authentication=getattr(ref, "authentication", None),
177
- )
178
- self._cache[name] = mcp
179
- return mcp
180
-
181
- def _lookup_mcp_by_name(self, name: str) -> MCP:
182
- """Look up MCP by name or ID on the platform.
183
-
184
- Args:
185
- name: The MCP name or ID to look up.
186
-
187
- Returns:
188
- The resolved glaip_sdk.models.MCP object.
189
-
190
- Raises:
191
- ValueError: If the MCP cannot be found.
192
- """
193
- # Lazy imports to avoid circular dependency
194
- from glaip_sdk.utils.client import get_client # noqa: PLC0415
195
-
196
- client = get_client()
197
- logger.info("Looking up MCP by name: %s", name)
198
-
199
- # Check if it's a valid UUID
200
- if is_uuid(name):
201
- mcp = client.get_mcp_by_id(name)
202
- if mcp:
203
- self._cache[name] = mcp
204
- return mcp
205
- else:
206
- results = client.find_mcps(name)
207
- exact_matches = [mcp for mcp in results if getattr(mcp, "name", None) == name]
208
- if len(exact_matches) == 1:
209
- mcp = exact_matches[0]
210
- self._cache[name] = mcp
211
- return mcp
212
- if len(exact_matches) > 1:
213
- raise ValueError(f"Multiple MCPs found with name '{name}'")
214
-
215
- raise ValueError(f"MCP not found on platform: {name}")
216
-
217
-
218
- class _MCPRegistrySingleton:
219
- """Singleton holder for MCPRegistry to avoid global statement."""
220
-
221
- _instance: MCPRegistry | None = None
222
-
223
- @classmethod
224
- def get_instance(cls) -> MCPRegistry:
225
- """Get or create the singleton instance.
226
-
227
- Returns:
228
- The global MCPRegistry instance.
229
- """
230
- if cls._instance is None:
231
- cls._instance = MCPRegistry()
232
- return cls._instance
233
-
234
- @classmethod
235
- def reset(cls) -> None:
236
- """Reset the singleton instance (for testing)."""
237
- cls._instance = None
238
-
239
-
240
- def get_mcp_registry() -> MCPRegistry:
241
- """Get the singleton MCPRegistry instance.
242
-
243
- Returns a global MCPRegistry that caches MCPs across the session.
244
-
245
- Returns:
246
- The global MCPRegistry instance.
247
-
248
- Example:
249
- >>> from glaip_sdk.registry import get_mcp_registry
250
- >>> registry = get_mcp_registry()
251
- >>> mcp = registry.resolve("arxiv-mcp")
252
- """
253
- return _MCPRegistrySingleton.get_instance()
@@ -1,232 +0,0 @@
1
- """Tool registry for glaip_sdk.
2
-
3
- This module provides the ToolRegistry that caches deployed tools
4
- to avoid redundant API calls when deploying agents with tools.
5
-
6
- Authors:
7
- Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
8
- """
9
-
10
- from __future__ import annotations
11
-
12
- import logging
13
- from typing import TYPE_CHECKING, Any
14
-
15
- from glaip_sdk.registry.base import BaseRegistry
16
-
17
- if TYPE_CHECKING:
18
- from glaip_sdk.tools import Tool
19
-
20
- logger = logging.getLogger(__name__)
21
-
22
-
23
- class ToolRegistry(BaseRegistry["Tool"]):
24
- """Registry for tools.
25
-
26
- Resolves tool references to glaip_sdk.models.Tool objects.
27
- Caches results to avoid redundant API calls and duplicate uploads.
28
-
29
- Handles:
30
- - Tool classes (LangChain BaseTool subclasses) → upload, cache, return Tool
31
- - glaip_sdk.models.Tool → return as-is (uses tool.id)
32
- - String names → lookup on platform, cache, return Tool
33
-
34
- Attributes:
35
- _cache: Internal cache mapping names to Tool objects.
36
-
37
- Example:
38
- >>> registry = get_tool_registry()
39
- >>> tool = registry.resolve(WebSearchTool)
40
- >>> print(tool.id)
41
- """
42
-
43
- def _get_name_from_model_fields(self, ref: type) -> str | None:
44
- """Extract name from Pydantic model_fields if available."""
45
- model_fields = getattr(ref, "model_fields", {})
46
- if "name" not in model_fields:
47
- return None
48
- field_info = model_fields["name"]
49
- default = getattr(field_info, "default", None)
50
- return default if isinstance(default, str) else None
51
-
52
- def _get_string_attr(self, obj: Any, attr: str) -> str | None:
53
- """Get attribute if it's a string, otherwise None."""
54
- value = getattr(obj, attr, None)
55
- return value if isinstance(value, str) else None
56
-
57
- def _extract_name(self, ref: Any) -> str:
58
- """Extract tool name from a reference.
59
-
60
- Args:
61
- ref: A tool class, instance, dict, or string name.
62
-
63
- Returns:
64
- The extracted tool name.
65
-
66
- Raises:
67
- ValueError: If name cannot be extracted from the reference.
68
- """
69
- if isinstance(ref, str):
70
- return ref
71
-
72
- # Dict from API response - extract name or id
73
- if isinstance(ref, dict):
74
- return ref.get("name") or ref.get("id") or ""
75
-
76
- # Tool instance (not a class) with name attribute
77
- if not isinstance(ref, type):
78
- name = self._get_string_attr(ref, "name")
79
- if name:
80
- return name
81
-
82
- # Tool class - try direct attribute first, then model_fields
83
- if isinstance(ref, type):
84
- name = self._get_string_attr(ref, "name") or self._get_name_from_model_fields(ref)
85
- if name:
86
- return name
87
-
88
- raise ValueError(f"Cannot extract name from: {ref}")
89
-
90
- def _resolve_and_cache(self, ref: Any, name: str) -> Tool:
91
- """Resolve tool reference - upload if class, find if string/native.
92
-
93
- Args:
94
- ref: The tool reference to resolve.
95
- name: The extracted tool name.
96
-
97
- Returns:
98
- The resolved glaip_sdk.models.Tool object.
99
-
100
- Raises:
101
- ValueError: If the tool cannot be resolved.
102
- """
103
- # Lazy imports to avoid circular dependency
104
- from glaip_sdk.utils.discovery import find_tool # noqa: PLC0415
105
- from glaip_sdk.utils.sync import update_or_create_tool # noqa: PLC0415
106
-
107
- # Already deployed tool (glaip_sdk.models.Tool with ID) - just cache and return
108
- if hasattr(ref, "id") and hasattr(ref, "name") and not isinstance(ref, type):
109
- if ref.id is not None:
110
- logger.debug("Caching already deployed tool: %s", name)
111
- self._cache[name] = ref
112
- return ref
113
-
114
- # Tool without ID (e.g., Tool.from_native()) - look up on platform
115
- logger.info("Looking up native tool: %s", name)
116
- tool = find_tool(name)
117
- if tool:
118
- self._cache[name] = tool
119
- return tool
120
- raise ValueError(f"Native tool not found on platform: {name}")
121
-
122
- # Custom tool class - upload it
123
- if self._is_custom_tool(ref):
124
- logger.info("Uploading custom tool: %s", name)
125
- tool = update_or_create_tool(ref)
126
- self._cache[name] = tool
127
- if tool.id:
128
- self._cache[tool.id] = tool
129
- return tool
130
-
131
- # Dict from API response - use ID directly if available
132
- if isinstance(ref, dict):
133
- tool_id = ref.get("id")
134
- if tool_id:
135
- from glaip_sdk.tools.base import Tool # noqa: PLC0415
136
-
137
- tool = Tool(id=tool_id, name=ref.get("name", ""))
138
- self._cache[name] = tool
139
- return tool
140
- raise ValueError(f"Tool dict missing 'id': {ref}")
141
-
142
- # String name - look up on platform (could be native or existing tool)
143
- if isinstance(ref, str):
144
- logger.info("Looking up tool by name: %s", name)
145
- tool = find_tool(name)
146
- if tool:
147
- self._cache[name] = tool
148
- return tool
149
- raise ValueError(f"Tool not found on platform: {name}")
150
-
151
- raise ValueError(f"Could not resolve tool reference: {ref}")
152
-
153
- def _is_custom_tool(self, ref: Any) -> bool:
154
- """Check if reference is a custom tool class/instance.
155
-
156
- Args:
157
- ref: The reference to check.
158
-
159
- Returns:
160
- True if ref is a custom tool that needs uploading.
161
- """
162
- try:
163
- from glaip_sdk.utils.tool_detection import ( # noqa: PLC0415
164
- is_langchain_tool,
165
- )
166
- except ImportError:
167
- return False
168
-
169
- return is_langchain_tool(ref)
170
-
171
- def resolve(self, ref: Any) -> Tool:
172
- """Resolve a tool reference to a platform Tool object.
173
-
174
- Overrides base resolve to handle SDK tools differently.
175
-
176
- Args:
177
- ref: The tool reference to resolve.
178
-
179
- Returns:
180
- The resolved glaip_sdk.models.Tool object.
181
- """
182
- # Check if it's a Tool instance (not a class)
183
- if hasattr(ref, "id") and hasattr(ref, "name") and not isinstance(ref, type):
184
- # If Tool has an ID, it's already deployed - return as-is
185
- if ref.id is not None:
186
- name = self._extract_name(ref)
187
- if name not in self._cache:
188
- self._cache[name] = ref
189
- return ref
190
-
191
- # Tool without ID (e.g., from Tool.from_native()) - needs platform lookup
192
- # Fall through to normal resolution
193
-
194
- return super().resolve(ref)
195
-
196
-
197
- class _ToolRegistrySingleton:
198
- """Singleton holder for ToolRegistry to avoid global statement."""
199
-
200
- _instance: ToolRegistry | None = None
201
-
202
- @classmethod
203
- def get_instance(cls) -> ToolRegistry:
204
- """Get or create the singleton instance.
205
-
206
- Returns:
207
- The global ToolRegistry instance.
208
- """
209
- if cls._instance is None:
210
- cls._instance = ToolRegistry()
211
- return cls._instance
212
-
213
- @classmethod
214
- def reset(cls) -> None:
215
- """Reset the singleton instance (for testing)."""
216
- cls._instance = None
217
-
218
-
219
- def get_tool_registry() -> ToolRegistry:
220
- """Get the singleton ToolRegistry instance.
221
-
222
- Returns a global ToolRegistry that caches tools across the session.
223
-
224
- Returns:
225
- The global ToolRegistry instance.
226
-
227
- Example:
228
- >>> from glaip_sdk.registry import get_tool_registry
229
- >>> registry = get_tool_registry()
230
- >>> tool = registry.resolve("web_search")
231
- """
232
- return _ToolRegistrySingleton.get_instance()
@@ -1,59 +0,0 @@
1
- """Local agent execution runners.
2
-
3
- This module provides runners for executing glaip-sdk agents locally
4
- without requiring the AIP backend server. The primary runner is
5
- LangGraphRunner which uses the aip-agents library.
6
-
7
- To use local execution, install with the [local] extra:
8
- pip install "glaip-sdk[local]"
9
-
10
- Authors:
11
- Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
12
-
13
- Example:
14
- >>> from glaip_sdk.runner import get_default_runner
15
- >>> from glaip_sdk.agents import Agent
16
- >>>
17
- >>> agent = Agent(name="my-agent", instruction="You are helpful.")
18
- >>> runner = get_default_runner()
19
- >>> result = runner.run(agent, "Hello!")
20
- """
21
-
22
- from glaip_sdk.runner.deps import (
23
- LOCAL_RUNTIME_AVAILABLE,
24
- check_local_runtime_available,
25
- get_local_runtime_missing_message,
26
- )
27
- from glaip_sdk.runner.langgraph import LangGraphRunner
28
-
29
- # Default runner instance
30
- _default_runner: LangGraphRunner | None = None
31
-
32
-
33
- def get_default_runner() -> LangGraphRunner:
34
- """Get the default runner instance for local agent execution.
35
-
36
- Returns:
37
- The default LangGraphRunner instance.
38
-
39
- Raises:
40
- RuntimeError: If local runtime dependencies are not available.
41
- """
42
- global _default_runner
43
-
44
- if not check_local_runtime_available():
45
- raise RuntimeError(get_local_runtime_missing_message())
46
-
47
- if _default_runner is None:
48
- _default_runner = LangGraphRunner()
49
-
50
- return _default_runner
51
-
52
-
53
- __all__ = [
54
- "LOCAL_RUNTIME_AVAILABLE",
55
- "LangGraphRunner",
56
- "check_local_runtime_available",
57
- "get_default_runner",
58
- "get_local_runtime_missing_message",
59
- ]