glaip-sdk 0.1.3__py3-none-any.whl → 0.6.19__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 +44 -4
- glaip_sdk/_version.py +9 -0
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1196 -0
- glaip_sdk/branding.py +13 -0
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/auth.py +254 -15
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents.py +213 -73
- glaip_sdk/cli/commands/common_config.py +104 -0
- glaip_sdk/cli/commands/configure.py +729 -113
- glaip_sdk/cli/commands/mcps.py +241 -72
- glaip_sdk/cli/commands/models.py +11 -5
- glaip_sdk/cli/commands/tools.py +49 -57
- glaip_sdk/cli/commands/transcripts.py +755 -0
- glaip_sdk/cli/config.py +48 -4
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +8 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +851 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +35 -19
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +6 -3
- glaip_sdk/cli/main.py +241 -121
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/pager.py +9 -10
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/accounts_controller.py +578 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +62 -21
- glaip_sdk/cli/slash/prompt.py +21 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +771 -140
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +86 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +876 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +255 -44
- glaip_sdk/cli/transcript/capture.py +27 -1
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/viewer.py +72 -499
- glaip_sdk/cli/update_notifier.py +14 -5
- glaip_sdk/cli/utils.py +243 -1252
- glaip_sdk/cli/validators.py +5 -6
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_agent_payloads.py +45 -9
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +291 -35
- glaip_sdk/client/base.py +1 -0
- glaip_sdk/client/main.py +19 -10
- glaip_sdk/client/mcps.py +122 -12
- glaip_sdk/client/run_rendering.py +466 -89
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +155 -10
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/hitl/__init__.py +15 -0
- glaip_sdk/hitl/local.py +151 -0
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +90 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +116 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/registry/__init__.py +55 -0
- glaip_sdk/registry/agent.py +164 -0
- glaip_sdk/registry/base.py +139 -0
- glaip_sdk/registry/mcp.py +253 -0
- glaip_sdk/registry/tool.py +232 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/runner/__init__.py +59 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +112 -0
- glaip_sdk/runner/langgraph.py +870 -0
- glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +95 -0
- glaip_sdk/runner/tool_adapter/__init__.py +18 -0
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +219 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +435 -0
- glaip_sdk/utils/__init__.py +58 -12
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +39 -7
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +23 -15
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +0 -33
- glaip_sdk/utils/import_export.py +12 -7
- glaip_sdk/utils/import_resolver.py +492 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -1
- glaip_sdk/utils/rendering/formatting.py +5 -30
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer → layout}/panels.py +9 -0
- glaip_sdk/utils/rendering/{renderer → layout}/progress.py +70 -1
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +1 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -47
- glaip_sdk/utils/rendering/renderer/base.py +275 -1476
- glaip_sdk/utils/rendering/renderer/debug.py +26 -20
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +4 -12
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
- glaip_sdk/utils/rendering/state.py +204 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +53 -440
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/steps/manager.py +387 -0
- glaip_sdk/utils/rendering/timing.py +36 -0
- glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
- glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
- glaip_sdk/utils/resource_refs.py +25 -13
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +18 -0
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/tool_detection.py +33 -0
- glaip_sdk/utils/tool_storage_provider.py +140 -0
- glaip_sdk/utils/validation.py +16 -24
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.6.19.dist-info}/METADATA +56 -21
- glaip_sdk-0.6.19.dist-info/RECORD +163 -0
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.6.19.dist-info}/WHEEL +2 -1
- glaip_sdk-0.6.19.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.6.19.dist-info/top_level.txt +1 -0
- glaip_sdk/models.py +0 -240
- glaip_sdk-0.1.3.dist-info/RECORD +0 -83
- glaip_sdk-0.1.3.dist-info/entry_points.txt +0 -3
glaip_sdk/client/mcps.py
CHANGED
|
@@ -3,18 +3,22 @@
|
|
|
3
3
|
|
|
4
4
|
Authors:
|
|
5
5
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
6
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
import logging
|
|
9
10
|
from typing import Any
|
|
10
11
|
|
|
11
12
|
from glaip_sdk.client.base import BaseClient
|
|
12
|
-
from glaip_sdk.config.constants import
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
from glaip_sdk.config.constants import DEFAULT_MCP_TRANSPORT, DEFAULT_MCP_TYPE
|
|
14
|
+
from glaip_sdk.mcps import MCP
|
|
15
|
+
from glaip_sdk.models import MCPResponse
|
|
16
|
+
from glaip_sdk.utils.client_utils import (
|
|
17
|
+
add_kwargs_to_payload,
|
|
18
|
+
create_model_instances,
|
|
19
|
+
find_by_name,
|
|
15
20
|
)
|
|
16
|
-
from glaip_sdk.
|
|
17
|
-
from glaip_sdk.utils.client_utils import create_model_instances, find_by_name
|
|
21
|
+
from glaip_sdk.utils.resource_refs import is_uuid
|
|
18
22
|
|
|
19
23
|
# API endpoints
|
|
20
24
|
MCPS_ENDPOINT = "/mcps/"
|
|
@@ -45,7 +49,8 @@ class MCPClient(BaseClient):
|
|
|
45
49
|
def get_mcp_by_id(self, mcp_id: str) -> MCP:
|
|
46
50
|
"""Get MCP by ID."""
|
|
47
51
|
data = self._request("GET", f"{MCPS_ENDPOINT}{mcp_id}")
|
|
48
|
-
|
|
52
|
+
response = MCPResponse(**data)
|
|
53
|
+
return MCP.from_response(response, client=self)
|
|
49
54
|
|
|
50
55
|
def find_mcps(self, name: str | None = None) -> list[MCP]:
|
|
51
56
|
"""Find MCPs by name."""
|
|
@@ -77,7 +82,8 @@ class MCPClient(BaseClient):
|
|
|
77
82
|
get_endpoint_fmt=f"{MCPS_ENDPOINT}{{id}}",
|
|
78
83
|
json=payload,
|
|
79
84
|
)
|
|
80
|
-
|
|
85
|
+
response = MCPResponse(**full_mcp_data)
|
|
86
|
+
return MCP.from_response(response, client=self)
|
|
81
87
|
|
|
82
88
|
def update_mcp(self, mcp_id: str, **kwargs) -> MCP:
|
|
83
89
|
"""Update an existing MCP.
|
|
@@ -99,12 +105,102 @@ class MCPClient(BaseClient):
|
|
|
99
105
|
method = "PATCH"
|
|
100
106
|
|
|
101
107
|
data = self._request(method, f"{MCPS_ENDPOINT}{mcp_id}", json=kwargs)
|
|
102
|
-
|
|
108
|
+
response = MCPResponse(**data)
|
|
109
|
+
return MCP.from_response(response, client=self)
|
|
103
110
|
|
|
104
111
|
def delete_mcp(self, mcp_id: str) -> None:
|
|
105
112
|
"""Delete an MCP."""
|
|
106
113
|
self._request("DELETE", f"{MCPS_ENDPOINT}{mcp_id}")
|
|
107
114
|
|
|
115
|
+
def upsert_mcp(
|
|
116
|
+
self,
|
|
117
|
+
identifier: str | MCP,
|
|
118
|
+
description: str | None = None,
|
|
119
|
+
config: dict[str, Any] | None = None,
|
|
120
|
+
**kwargs,
|
|
121
|
+
) -> MCP:
|
|
122
|
+
"""Create or update an MCP by instance, ID, or name.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
identifier: MCP instance, ID (UUID string), or name
|
|
126
|
+
description: MCP description
|
|
127
|
+
config: MCP configuration dictionary
|
|
128
|
+
**kwargs: Additional parameters (transport, metadata, etc.)
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
The created or updated MCP.
|
|
132
|
+
|
|
133
|
+
Example:
|
|
134
|
+
>>> # By name (creates if not exists)
|
|
135
|
+
>>> mcp = client.mcps.upsert_mcp(
|
|
136
|
+
... "deepwiki",
|
|
137
|
+
... transport="sse",
|
|
138
|
+
... config={"url": "https://mcp.deepwiki.com/sse"},
|
|
139
|
+
... )
|
|
140
|
+
>>> # By instance
|
|
141
|
+
>>> mcp = client.mcps.upsert_mcp(existing_mcp, description="Updated")
|
|
142
|
+
>>> # By ID
|
|
143
|
+
>>> mcp = client.mcps.upsert_mcp("uuid-here", description="Updated")
|
|
144
|
+
"""
|
|
145
|
+
# Handle MCP instance
|
|
146
|
+
if isinstance(identifier, MCP):
|
|
147
|
+
if identifier.id:
|
|
148
|
+
logger.info("Updating MCP by instance: %s", identifier.name)
|
|
149
|
+
return self._do_upsert_update(identifier.id, identifier.name, description, config, **kwargs)
|
|
150
|
+
# MCP without ID - treat name as identifier
|
|
151
|
+
identifier = identifier.name
|
|
152
|
+
|
|
153
|
+
# Handle string (ID or name)
|
|
154
|
+
if isinstance(identifier, str):
|
|
155
|
+
if is_uuid(identifier):
|
|
156
|
+
logger.info("Updating MCP by ID: %s", identifier)
|
|
157
|
+
existing = self.get_mcp_by_id(identifier)
|
|
158
|
+
return self._do_upsert_update(identifier, existing.name, description, config, **kwargs)
|
|
159
|
+
|
|
160
|
+
# It's a name - find or create
|
|
161
|
+
return self._upsert_by_name(identifier, description, config, **kwargs)
|
|
162
|
+
|
|
163
|
+
raise ValueError(f"Invalid identifier type: {type(identifier)}")
|
|
164
|
+
|
|
165
|
+
def _do_upsert_update(
|
|
166
|
+
self,
|
|
167
|
+
mcp_id: str,
|
|
168
|
+
name: str | None,
|
|
169
|
+
description: str | None,
|
|
170
|
+
config: dict[str, Any] | None,
|
|
171
|
+
**kwargs,
|
|
172
|
+
) -> MCP:
|
|
173
|
+
"""Perform the update part of upsert."""
|
|
174
|
+
update_kwargs = {**kwargs}
|
|
175
|
+
if name is not None:
|
|
176
|
+
update_kwargs["name"] = name
|
|
177
|
+
if description is not None:
|
|
178
|
+
update_kwargs["description"] = description
|
|
179
|
+
if config is not None:
|
|
180
|
+
update_kwargs["config"] = config
|
|
181
|
+
return self.update_mcp(mcp_id, **update_kwargs)
|
|
182
|
+
|
|
183
|
+
def _upsert_by_name(
|
|
184
|
+
self,
|
|
185
|
+
name: str,
|
|
186
|
+
description: str | None,
|
|
187
|
+
config: dict[str, Any] | None,
|
|
188
|
+
**kwargs,
|
|
189
|
+
) -> MCP:
|
|
190
|
+
"""Find by name and update, or create if not found."""
|
|
191
|
+
existing = self.find_mcps(name)
|
|
192
|
+
|
|
193
|
+
if len(existing) == 1:
|
|
194
|
+
logger.info("Updating existing MCP: %s", name)
|
|
195
|
+
return self._do_upsert_update(existing[0].id, name, description, config, **kwargs)
|
|
196
|
+
|
|
197
|
+
if len(existing) > 1:
|
|
198
|
+
raise ValueError(f"Multiple MCPs found with name '{name}'")
|
|
199
|
+
|
|
200
|
+
# Create new MCP
|
|
201
|
+
logger.info("Creating new MCP: %s", name)
|
|
202
|
+
return self.create_mcp(name=name, description=description, config=config, **kwargs)
|
|
203
|
+
|
|
108
204
|
def _build_create_payload(
|
|
109
205
|
self,
|
|
110
206
|
name: str,
|
|
@@ -147,9 +243,7 @@ class MCPClient(BaseClient):
|
|
|
147
243
|
|
|
148
244
|
# Add any other kwargs (excluding already handled ones)
|
|
149
245
|
excluded_keys = {"type"} # type is handled above
|
|
150
|
-
|
|
151
|
-
if key not in excluded_keys:
|
|
152
|
-
payload[key] = value
|
|
246
|
+
add_kwargs_to_payload(payload, kwargs, excluded_keys)
|
|
153
247
|
|
|
154
248
|
return payload
|
|
155
249
|
|
|
@@ -206,7 +300,23 @@ class MCPClient(BaseClient):
|
|
|
206
300
|
def get_mcp_tools(self, mcp_id: str) -> list[dict[str, Any]]:
|
|
207
301
|
"""Get tools available from an MCP."""
|
|
208
302
|
data = self._request("GET", f"{MCPS_ENDPOINT}{mcp_id}/tools")
|
|
209
|
-
|
|
303
|
+
if data is None:
|
|
304
|
+
return []
|
|
305
|
+
if isinstance(data, list):
|
|
306
|
+
return data
|
|
307
|
+
if isinstance(data, dict):
|
|
308
|
+
if "tools" in data:
|
|
309
|
+
return data.get("tools", []) or []
|
|
310
|
+
logger.warning(
|
|
311
|
+
"Unexpected MCP tools response keys %s; returning empty list",
|
|
312
|
+
list(data.keys()),
|
|
313
|
+
)
|
|
314
|
+
return []
|
|
315
|
+
logger.warning(
|
|
316
|
+
"Unexpected MCP tools response type %s; returning empty list",
|
|
317
|
+
type(data).__name__,
|
|
318
|
+
)
|
|
319
|
+
return []
|
|
210
320
|
|
|
211
321
|
def test_mcp_connection(self, config: dict[str, Any]) -> dict[str, Any]:
|
|
212
322
|
"""Test MCP connection using configuration.
|