glaip-sdk 0.0.1b5__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 +12 -0
- glaip_sdk/cli/__init__.py +9 -0
- glaip_sdk/cli/commands/__init__.py +5 -0
- glaip_sdk/cli/commands/agents.py +415 -0
- glaip_sdk/cli/commands/configure.py +316 -0
- glaip_sdk/cli/commands/init.py +168 -0
- glaip_sdk/cli/commands/mcps.py +473 -0
- glaip_sdk/cli/commands/models.py +52 -0
- glaip_sdk/cli/commands/tools.py +309 -0
- glaip_sdk/cli/config.py +592 -0
- glaip_sdk/cli/main.py +298 -0
- glaip_sdk/cli/utils.py +733 -0
- glaip_sdk/client/__init__.py +179 -0
- glaip_sdk/client/agents.py +441 -0
- glaip_sdk/client/base.py +223 -0
- glaip_sdk/client/mcps.py +94 -0
- glaip_sdk/client/tools.py +193 -0
- glaip_sdk/client/validators.py +166 -0
- glaip_sdk/config/constants.py +28 -0
- glaip_sdk/exceptions.py +93 -0
- glaip_sdk/models.py +190 -0
- glaip_sdk/utils/__init__.py +95 -0
- glaip_sdk/utils/run_renderer.py +1009 -0
- glaip_sdk/utils.py +167 -0
- glaip_sdk-0.0.1b5.dist-info/METADATA +633 -0
- glaip_sdk-0.0.1b5.dist-info/RECORD +28 -0
- glaip_sdk-0.0.1b5.dist-info/WHEEL +4 -0
- glaip_sdk-0.0.1b5.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Configuration constants for the AIP SDK.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Default language model configuration
|
|
8
|
+
DEFAULT_MODEL = "gpt-4.1"
|
|
9
|
+
DEFAULT_MODEL_PROVIDER = "openai"
|
|
10
|
+
|
|
11
|
+
# Default timeout values
|
|
12
|
+
DEFAULT_TIMEOUT = 30.0
|
|
13
|
+
DEFAULT_AGENT_TIMEOUT = 300.0
|
|
14
|
+
|
|
15
|
+
# User agent
|
|
16
|
+
SDK_NAME = "glaip-sdk"
|
|
17
|
+
SDK_VERSION = "0.1.0"
|
|
18
|
+
|
|
19
|
+
# Reserved names that cannot be used for agents/tools
|
|
20
|
+
RESERVED_NAMES = {
|
|
21
|
+
"system",
|
|
22
|
+
"admin",
|
|
23
|
+
"root",
|
|
24
|
+
"test",
|
|
25
|
+
"example",
|
|
26
|
+
"demo",
|
|
27
|
+
"sample",
|
|
28
|
+
}
|
glaip_sdk/exceptions.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Custom exceptions for AIP SDK.
|
|
3
|
+
|
|
4
|
+
Authors:
|
|
5
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AIPError(Exception):
|
|
12
|
+
"""Base exception for AIP SDK."""
|
|
13
|
+
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class APIError(AIPError):
|
|
18
|
+
"""Base API exception with rich context."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
message: str,
|
|
23
|
+
*,
|
|
24
|
+
status_code: int | None = None,
|
|
25
|
+
error_type: str | None = None,
|
|
26
|
+
payload: Any = None,
|
|
27
|
+
request_id: str | None = None,
|
|
28
|
+
):
|
|
29
|
+
super().__init__(message)
|
|
30
|
+
self.status_code = status_code
|
|
31
|
+
self.error_type = error_type
|
|
32
|
+
self.payload = payload
|
|
33
|
+
self.request_id = request_id
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class AuthenticationError(APIError):
|
|
37
|
+
"""Authentication failed."""
|
|
38
|
+
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ValidationError(APIError):
|
|
43
|
+
"""Validation failed."""
|
|
44
|
+
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ForbiddenError(APIError):
|
|
49
|
+
"""Access forbidden."""
|
|
50
|
+
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class NotFoundError(APIError):
|
|
55
|
+
"""Resource not found."""
|
|
56
|
+
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ConflictError(APIError):
|
|
61
|
+
"""Resource conflict."""
|
|
62
|
+
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class AmbiguousResourceError(APIError):
|
|
67
|
+
"""Multiple resources match the query."""
|
|
68
|
+
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ServerError(APIError):
|
|
73
|
+
"""Server error."""
|
|
74
|
+
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class RateLimitError(APIError):
|
|
79
|
+
"""Rate limit exceeded."""
|
|
80
|
+
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class TimeoutError(APIError):
|
|
85
|
+
"""Request timeout."""
|
|
86
|
+
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ClientError(APIError):
|
|
91
|
+
"""Client-side error (e.g., invalid request format, missing parameters)."""
|
|
92
|
+
|
|
93
|
+
pass
|
glaip_sdk/models.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Data models for AIP SDK.
|
|
3
|
+
|
|
4
|
+
Authors:
|
|
5
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Agent(BaseModel):
|
|
14
|
+
"""Agent model for API responses."""
|
|
15
|
+
|
|
16
|
+
id: str
|
|
17
|
+
name: str
|
|
18
|
+
instruction: str | None = None
|
|
19
|
+
description: str | None = None # Add missing description field
|
|
20
|
+
type: str | None = None
|
|
21
|
+
framework: str | None = None
|
|
22
|
+
version: str | None = None
|
|
23
|
+
tools: list[dict[str, Any]] | None = None # Backend returns ToolReference objects
|
|
24
|
+
agents: list[dict[str, Any]] | None = None # Backend returns AgentReference objects
|
|
25
|
+
agent_config: dict[str, Any] | None = None
|
|
26
|
+
timeout: int = 300
|
|
27
|
+
_client: Any = None # Will hold client reference
|
|
28
|
+
|
|
29
|
+
def _set_client(self, client):
|
|
30
|
+
"""Set the client reference for this resource."""
|
|
31
|
+
self._client = client
|
|
32
|
+
return self
|
|
33
|
+
|
|
34
|
+
def run(self, message: str, **kwargs) -> str:
|
|
35
|
+
"""Run the agent with a message."""
|
|
36
|
+
if not self._client:
|
|
37
|
+
raise RuntimeError(
|
|
38
|
+
"No client available. Use client.get_agent_by_id() to get a client-connected agent."
|
|
39
|
+
)
|
|
40
|
+
# Automatically pass the agent name for better renderer display
|
|
41
|
+
kwargs.setdefault("agent_name", self.name)
|
|
42
|
+
return self._client.run_agent(self.id, message, **kwargs)
|
|
43
|
+
|
|
44
|
+
def update(self, **kwargs) -> "Agent":
|
|
45
|
+
"""Update agent attributes."""
|
|
46
|
+
if not self._client:
|
|
47
|
+
raise RuntimeError(
|
|
48
|
+
"No client available. Use client.get_agent_by_id() to get a client-connected agent."
|
|
49
|
+
)
|
|
50
|
+
updated_agent = self._client.update_agent(self.id, **kwargs)
|
|
51
|
+
# Update current instance with new data
|
|
52
|
+
for key, value in updated_agent.model_dump().items():
|
|
53
|
+
if hasattr(self, key):
|
|
54
|
+
setattr(self, key, value)
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def delete(self) -> None:
|
|
58
|
+
"""Delete the agent."""
|
|
59
|
+
if not self._client:
|
|
60
|
+
raise RuntimeError(
|
|
61
|
+
"No client available. Use client.get_agent_by_id() to get a client-connected agent."
|
|
62
|
+
)
|
|
63
|
+
self._client.delete_agent(self.id)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Tool(BaseModel):
|
|
67
|
+
"""Tool model for API responses."""
|
|
68
|
+
|
|
69
|
+
id: str
|
|
70
|
+
name: str
|
|
71
|
+
tool_type: str | None = None
|
|
72
|
+
description: str | None = None
|
|
73
|
+
framework: str | None = None
|
|
74
|
+
version: str | None = None
|
|
75
|
+
tool_script: str | None = None
|
|
76
|
+
tool_file: str | None = None
|
|
77
|
+
_client: Any = None # Will hold client reference
|
|
78
|
+
|
|
79
|
+
def _set_client(self, client):
|
|
80
|
+
"""Set the client reference for this resource."""
|
|
81
|
+
self._client = client
|
|
82
|
+
return self
|
|
83
|
+
|
|
84
|
+
def get_script(self) -> str:
|
|
85
|
+
"""Get the tool script content."""
|
|
86
|
+
if self.tool_script:
|
|
87
|
+
return self.tool_script
|
|
88
|
+
elif self.tool_file:
|
|
89
|
+
return f"Script content from file: {self.tool_file}"
|
|
90
|
+
else:
|
|
91
|
+
return "No script content available"
|
|
92
|
+
|
|
93
|
+
def update(self, **kwargs) -> "Tool":
|
|
94
|
+
"""Update tool attributes."""
|
|
95
|
+
if not self._client:
|
|
96
|
+
raise RuntimeError(
|
|
97
|
+
"No client available. Use client.get_tool_by_id() to get a client-connected tool."
|
|
98
|
+
)
|
|
99
|
+
updated_tool = self._client.tools.update_tool(self.id, **kwargs)
|
|
100
|
+
# Update current instance with new data
|
|
101
|
+
for key, value in updated_tool.model_dump().items():
|
|
102
|
+
if hasattr(self, key):
|
|
103
|
+
setattr(self, key, value)
|
|
104
|
+
return self
|
|
105
|
+
|
|
106
|
+
def delete(self) -> None:
|
|
107
|
+
"""Delete the tool."""
|
|
108
|
+
if not self._client:
|
|
109
|
+
raise RuntimeError(
|
|
110
|
+
"No client available. Use client.get_tool_by_id() to get a client-connected tool."
|
|
111
|
+
)
|
|
112
|
+
self._client.tools.delete_tool(self.id)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class MCP(BaseModel):
|
|
116
|
+
"""MCP model for API responses."""
|
|
117
|
+
|
|
118
|
+
id: str
|
|
119
|
+
name: str
|
|
120
|
+
description: str | None = None
|
|
121
|
+
config: dict[str, Any] | None = None
|
|
122
|
+
framework: str | None = None
|
|
123
|
+
version: str | None = None
|
|
124
|
+
transport: str | None = None # "sse" or "http"
|
|
125
|
+
authentication: dict[str, Any] | None = None
|
|
126
|
+
metadata: dict[str, Any] | None = None
|
|
127
|
+
_client: Any = None # Will hold client reference
|
|
128
|
+
|
|
129
|
+
def _set_client(self, client):
|
|
130
|
+
"""Set the client reference for this resource."""
|
|
131
|
+
self._client = client
|
|
132
|
+
return self
|
|
133
|
+
|
|
134
|
+
def get_tools(self) -> list[dict[str, Any]]:
|
|
135
|
+
"""Get tools available from this MCP."""
|
|
136
|
+
if not self._client:
|
|
137
|
+
raise RuntimeError(
|
|
138
|
+
"No client available. Use client.get_mcp_by_id() to get a client-connected MCP."
|
|
139
|
+
)
|
|
140
|
+
# This would delegate to the client's MCP tools endpoint
|
|
141
|
+
# For now, return empty list as placeholder
|
|
142
|
+
return []
|
|
143
|
+
|
|
144
|
+
def update(self, **kwargs) -> "MCP":
|
|
145
|
+
"""Update MCP attributes."""
|
|
146
|
+
if not self._client:
|
|
147
|
+
raise RuntimeError(
|
|
148
|
+
"No client available. Use client.get_mcp_by_id() to get a client-connected MCP."
|
|
149
|
+
)
|
|
150
|
+
updated_mcp = self._client.update_mcp(self.id, **kwargs)
|
|
151
|
+
# Update current instance with new data
|
|
152
|
+
for key, value in updated_mcp.model_dump().items():
|
|
153
|
+
if hasattr(self, key):
|
|
154
|
+
setattr(self, key, value)
|
|
155
|
+
return self
|
|
156
|
+
|
|
157
|
+
def delete(self) -> None:
|
|
158
|
+
"""Delete the MCP."""
|
|
159
|
+
if not self._client:
|
|
160
|
+
raise RuntimeError(
|
|
161
|
+
"No client available. Use client.get_mcp_by_id() to get a client-connected MCP."
|
|
162
|
+
)
|
|
163
|
+
self._client.delete_mcp(self.id)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class LanguageModelResponse(BaseModel):
|
|
167
|
+
"""Language model response model."""
|
|
168
|
+
|
|
169
|
+
name: str
|
|
170
|
+
provider: str
|
|
171
|
+
description: str | None = None
|
|
172
|
+
capabilities: list[str] | None = None
|
|
173
|
+
max_tokens: int | None = None
|
|
174
|
+
supports_streaming: bool = False
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class TTYRenderer:
|
|
178
|
+
"""Simple TTY renderer for non-Rich environments."""
|
|
179
|
+
|
|
180
|
+
def __init__(self, use_color: bool = True):
|
|
181
|
+
self.use_color = use_color
|
|
182
|
+
|
|
183
|
+
def render_message(self, message: str, event_type: str = "message"):
|
|
184
|
+
"""Render a message with optional color."""
|
|
185
|
+
if event_type == "error":
|
|
186
|
+
print(f"ERROR: {message}", flush=True)
|
|
187
|
+
elif event_type == "done":
|
|
188
|
+
print(f"\n✅ {message}", flush=True)
|
|
189
|
+
else:
|
|
190
|
+
print(message, flush=True)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Utility modules for AIP SDK.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
from uuid import UUID
|
|
9
|
+
|
|
10
|
+
from .run_renderer import (
|
|
11
|
+
RichStreamRenderer,
|
|
12
|
+
RunStats,
|
|
13
|
+
Step,
|
|
14
|
+
StepManager,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"RichStreamRenderer",
|
|
19
|
+
"RunStats",
|
|
20
|
+
"Step",
|
|
21
|
+
"StepManager",
|
|
22
|
+
"is_uuid",
|
|
23
|
+
"sanitize_name",
|
|
24
|
+
"format_file_size",
|
|
25
|
+
"progress_bar",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def is_uuid(value: str) -> bool:
|
|
30
|
+
"""Check if a string is a valid UUID.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
value: String to check
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
True if value is a valid UUID, False otherwise
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
UUID(value)
|
|
40
|
+
return True
|
|
41
|
+
except (ValueError, TypeError):
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def sanitize_name(name: str) -> str:
|
|
46
|
+
"""Sanitize a name for resource creation.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
name: Raw name input
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Sanitized name suitable for resource creation
|
|
53
|
+
"""
|
|
54
|
+
# Remove special characters and normalize
|
|
55
|
+
sanitized = re.sub(r"[^a-zA-Z0-9\-_]", "-", name.strip())
|
|
56
|
+
sanitized = re.sub(r"-+", "-", sanitized) # Collapse multiple dashes
|
|
57
|
+
return sanitized.lower().strip("-")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def format_file_size(size_bytes: int) -> str:
|
|
61
|
+
"""Format file size in human readable format.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
size_bytes: Size in bytes
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Human readable size string (e.g., "1.5 MB")
|
|
68
|
+
"""
|
|
69
|
+
for unit in ["B", "KB", "MB", "GB"]:
|
|
70
|
+
if size_bytes < 1024.0:
|
|
71
|
+
return f"{size_bytes:.1f} {unit}"
|
|
72
|
+
size_bytes /= 1024.0
|
|
73
|
+
return f"{size_bytes:.1f} TB"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def progress_bar(iterable, description: str = "Processing"):
|
|
77
|
+
"""Simple progress bar using click.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
iterable: Iterable to process
|
|
81
|
+
description: Progress description
|
|
82
|
+
|
|
83
|
+
Yields:
|
|
84
|
+
Items from iterable with progress display
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
import click
|
|
88
|
+
|
|
89
|
+
with click.progressbar(iterable, label=description) as bar:
|
|
90
|
+
for item in bar:
|
|
91
|
+
yield item
|
|
92
|
+
except ImportError:
|
|
93
|
+
# Fallback if click not available
|
|
94
|
+
for item in iterable:
|
|
95
|
+
yield item
|