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
glaip_sdk/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""AIP SDK - Python SDK for AI Agent Platform.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .client import Client
|
|
8
|
+
from .exceptions import AIPError
|
|
9
|
+
from .models import MCP, Agent, Tool
|
|
10
|
+
|
|
11
|
+
__version__ = "0.1.0"
|
|
12
|
+
__all__ = ["Client", "Agent", "Tool", "MCP", "AIPError"]
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
"""Agent management commands.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.text import Text
|
|
13
|
+
|
|
14
|
+
from glaip_sdk.utils import is_uuid
|
|
15
|
+
|
|
16
|
+
from ..utils import (
|
|
17
|
+
get_client,
|
|
18
|
+
handle_ambiguous_resource,
|
|
19
|
+
output_flags,
|
|
20
|
+
output_list,
|
|
21
|
+
output_result,
|
|
22
|
+
safe_getattr,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
console = Console()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group(name="agents", no_args_is_help=True)
|
|
29
|
+
def agents_group():
|
|
30
|
+
"""Agent management operations."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _resolve_agent(ctx, client, ref, select=None):
|
|
35
|
+
"""Resolve agent reference (ID or name) with ambiguity handling."""
|
|
36
|
+
if is_uuid(ref):
|
|
37
|
+
return client.agents.get_agent_by_id(ref)
|
|
38
|
+
|
|
39
|
+
# Find agents by name
|
|
40
|
+
matches = client.agents.find_agents(name=ref)
|
|
41
|
+
if not matches:
|
|
42
|
+
raise click.ClickException(f"Agent '{ref}' not found")
|
|
43
|
+
|
|
44
|
+
if len(matches) == 1:
|
|
45
|
+
return matches[0]
|
|
46
|
+
|
|
47
|
+
# Multiple matches - handle ambiguity
|
|
48
|
+
if select:
|
|
49
|
+
idx = int(select) - 1
|
|
50
|
+
if not (0 <= idx < len(matches)):
|
|
51
|
+
raise click.ClickException(f"--select must be 1..{len(matches)}")
|
|
52
|
+
return matches[idx]
|
|
53
|
+
|
|
54
|
+
return handle_ambiguous_resource(ctx, "agent", ref, matches)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@agents_group.command(name="list")
|
|
58
|
+
@output_flags()
|
|
59
|
+
@click.pass_context
|
|
60
|
+
def list_agents(ctx):
|
|
61
|
+
"""List all agents."""
|
|
62
|
+
try:
|
|
63
|
+
client = get_client(ctx)
|
|
64
|
+
agents = client.agents.list_agents()
|
|
65
|
+
|
|
66
|
+
# Define table columns: (data_key, header, style, width)
|
|
67
|
+
columns = [
|
|
68
|
+
("id", "ID", "dim", 36),
|
|
69
|
+
("name", "Name", "cyan", None),
|
|
70
|
+
("type", "Type", "yellow", None),
|
|
71
|
+
("framework", "Framework", "blue", None),
|
|
72
|
+
("version", "Version", "green", None),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
# Transform function for safe attribute access
|
|
76
|
+
def transform_agent(agent):
|
|
77
|
+
return {
|
|
78
|
+
"id": str(agent.id),
|
|
79
|
+
"name": agent.name,
|
|
80
|
+
"type": safe_getattr(agent, "type") or "N/A",
|
|
81
|
+
"framework": safe_getattr(agent, "framework") or "N/A",
|
|
82
|
+
"version": safe_getattr(agent, "version") or "N/A",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
output_list(ctx, agents, "🤖 Available Agents", columns, transform_agent)
|
|
86
|
+
|
|
87
|
+
except Exception as e:
|
|
88
|
+
raise click.ClickException(str(e))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@agents_group.command()
|
|
92
|
+
@click.argument("agent_ref")
|
|
93
|
+
@click.option("--select", type=int, help="Choose among ambiguous matches (1-based)")
|
|
94
|
+
@output_flags()
|
|
95
|
+
@click.pass_context
|
|
96
|
+
def get(ctx, agent_ref, select):
|
|
97
|
+
"""Get agent details."""
|
|
98
|
+
try:
|
|
99
|
+
client = get_client(ctx)
|
|
100
|
+
|
|
101
|
+
# Resolve agent with ambiguity handling
|
|
102
|
+
agent = _resolve_agent(ctx, client, agent_ref, select)
|
|
103
|
+
|
|
104
|
+
# Create result data with all available fields from backend
|
|
105
|
+
result_data = {
|
|
106
|
+
"id": str(getattr(agent, "id", "N/A")),
|
|
107
|
+
"name": getattr(agent, "name", "N/A"),
|
|
108
|
+
"type": getattr(agent, "type", "N/A"),
|
|
109
|
+
"framework": getattr(agent, "framework", "N/A"),
|
|
110
|
+
"version": getattr(agent, "version", "N/A"),
|
|
111
|
+
"description": getattr(agent, "description", "N/A"),
|
|
112
|
+
"instruction": getattr(agent, "instruction", "") or "-",
|
|
113
|
+
"metadata": getattr(agent, "metadata", "N/A"),
|
|
114
|
+
"language_model_id": getattr(agent, "language_model_id", "N/A"),
|
|
115
|
+
"agent_config": getattr(agent, "agent_config", "N/A"),
|
|
116
|
+
"tools": getattr(agent, "tools", []),
|
|
117
|
+
"agents": getattr(agent, "agents", []),
|
|
118
|
+
"mcps": getattr(agent, "mcps", []),
|
|
119
|
+
"a2a_profile": getattr(agent, "a2a_profile", "N/A"),
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
output_result(
|
|
123
|
+
ctx, result_data, title="Agent Details", panel_title=f"🤖 {agent.name}"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
except Exception as e:
|
|
127
|
+
raise click.ClickException(str(e))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@agents_group.command()
|
|
131
|
+
@click.argument("agent_id")
|
|
132
|
+
@click.option("--input", "input_text", required=True, help="Input text for the agent")
|
|
133
|
+
@click.option("--chat-history", help="JSON string of chat history")
|
|
134
|
+
@click.option("--timeout", default=600, type=int, help="Request timeout in seconds")
|
|
135
|
+
@click.option(
|
|
136
|
+
"--view",
|
|
137
|
+
type=click.Choice(["rich", "plain", "json", "md"]),
|
|
138
|
+
default="rich",
|
|
139
|
+
help="Output view format",
|
|
140
|
+
)
|
|
141
|
+
@click.option(
|
|
142
|
+
"--compact/--verbose", default=True, help="Collapse tool steps (default: compact)"
|
|
143
|
+
)
|
|
144
|
+
@click.option(
|
|
145
|
+
"--save",
|
|
146
|
+
type=click.Path(dir_okay=False, writable=True),
|
|
147
|
+
help="Save transcript to file (md or json)",
|
|
148
|
+
)
|
|
149
|
+
@click.option(
|
|
150
|
+
"--theme", type=click.Choice(["dark", "light"]), default="dark", help="Color theme"
|
|
151
|
+
)
|
|
152
|
+
@click.option(
|
|
153
|
+
"--file",
|
|
154
|
+
"files",
|
|
155
|
+
multiple=True,
|
|
156
|
+
type=click.Path(exists=True),
|
|
157
|
+
help="Attach file(s)",
|
|
158
|
+
)
|
|
159
|
+
@click.pass_context
|
|
160
|
+
def run(
|
|
161
|
+
ctx,
|
|
162
|
+
agent_id,
|
|
163
|
+
input_text,
|
|
164
|
+
chat_history,
|
|
165
|
+
timeout,
|
|
166
|
+
view,
|
|
167
|
+
compact,
|
|
168
|
+
save,
|
|
169
|
+
theme,
|
|
170
|
+
files,
|
|
171
|
+
):
|
|
172
|
+
"""Run an agent with input text (ID required)."""
|
|
173
|
+
try:
|
|
174
|
+
client = get_client(ctx)
|
|
175
|
+
|
|
176
|
+
# Get agent by ID (no ambiguity handling needed)
|
|
177
|
+
try:
|
|
178
|
+
agent = client.agents.get_agent_by_id(agent_id)
|
|
179
|
+
except Exception as e:
|
|
180
|
+
raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}")
|
|
181
|
+
|
|
182
|
+
# Parse chat history if provided
|
|
183
|
+
parsed_chat_history = None
|
|
184
|
+
if chat_history:
|
|
185
|
+
try:
|
|
186
|
+
parsed_chat_history = json.loads(chat_history)
|
|
187
|
+
except json.JSONDecodeError:
|
|
188
|
+
raise click.ClickException("Invalid JSON in chat history")
|
|
189
|
+
|
|
190
|
+
# Always stream (no --no-stream option)
|
|
191
|
+
stream = ctx.obj.get("tty", True)
|
|
192
|
+
|
|
193
|
+
# Create appropriate renderer based on view
|
|
194
|
+
renderer = None
|
|
195
|
+
if stream:
|
|
196
|
+
from ...utils.run_renderer import RichStreamRenderer
|
|
197
|
+
|
|
198
|
+
# Use RichStreamRenderer for all streaming output
|
|
199
|
+
# Different view formats are handled in the output logic below
|
|
200
|
+
renderer = RichStreamRenderer(
|
|
201
|
+
console, verbose=not compact, theme=theme, use_emoji=True
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Run agent
|
|
205
|
+
result = client.agents.run_agent(
|
|
206
|
+
agent_id=agent.id,
|
|
207
|
+
message=input_text,
|
|
208
|
+
files=list(files),
|
|
209
|
+
stream=stream,
|
|
210
|
+
agent_name=agent.name, # Pass agent name for better display
|
|
211
|
+
**({"chat_history": parsed_chat_history} if parsed_chat_history else {}),
|
|
212
|
+
**({"timeout": timeout} if timeout else {}),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Check if renderer already printed output (for streaming renderers)
|
|
216
|
+
printed_by_renderer = bool(renderer and stream)
|
|
217
|
+
|
|
218
|
+
# Handle output format for non-streaming or fallback
|
|
219
|
+
# Only print here if nothing was printed by the renderer
|
|
220
|
+
if not printed_by_renderer:
|
|
221
|
+
if (ctx.obj.get("view") == "json") or (view == "json"):
|
|
222
|
+
click.echo(json.dumps({"output": result}, indent=2))
|
|
223
|
+
elif view == "md":
|
|
224
|
+
click.echo(f"# Assistant\n\n{result}")
|
|
225
|
+
elif view == "plain":
|
|
226
|
+
click.echo(result)
|
|
227
|
+
elif not stream:
|
|
228
|
+
# Rich output for non-streaming
|
|
229
|
+
panel = Panel(
|
|
230
|
+
Text(result, style="green"),
|
|
231
|
+
title="Agent Output",
|
|
232
|
+
border_style="green",
|
|
233
|
+
)
|
|
234
|
+
console.print(panel)
|
|
235
|
+
|
|
236
|
+
# Save transcript if requested
|
|
237
|
+
if save and result:
|
|
238
|
+
ext = (save.rsplit(".", 1)[-1] or "").lower()
|
|
239
|
+
if ext == "json":
|
|
240
|
+
content = json.dumps({"output": result}, indent=2)
|
|
241
|
+
with open(save, "w", encoding="utf-8") as f:
|
|
242
|
+
f.write(content)
|
|
243
|
+
else:
|
|
244
|
+
content = f"# Assistant\n\n{result}\n"
|
|
245
|
+
with open(save, "w", encoding="utf-8") as f:
|
|
246
|
+
f.write(content)
|
|
247
|
+
console.print(f"[green]Transcript saved to: {save}[/green]")
|
|
248
|
+
|
|
249
|
+
except Exception as e:
|
|
250
|
+
if ctx.obj.get("view") == "json":
|
|
251
|
+
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
252
|
+
else:
|
|
253
|
+
console.print(f"[red]Error running agent: {e}[/red]")
|
|
254
|
+
raise click.ClickException(str(e))
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
@agents_group.command()
|
|
258
|
+
@click.option("--name", required=True, help="Agent name")
|
|
259
|
+
@click.option("--instruction", required=True, help="Agent instruction (prompt)")
|
|
260
|
+
@click.option("--tools", multiple=True, help="Tool names or IDs to attach")
|
|
261
|
+
@click.option("--agents", multiple=True, help="Sub-agent names to attach")
|
|
262
|
+
@click.option("--timeout", default=300, type=int, help="Execution timeout in seconds")
|
|
263
|
+
@output_flags()
|
|
264
|
+
@click.pass_context
|
|
265
|
+
def create(
|
|
266
|
+
ctx,
|
|
267
|
+
name,
|
|
268
|
+
instruction,
|
|
269
|
+
tools,
|
|
270
|
+
agents,
|
|
271
|
+
timeout,
|
|
272
|
+
):
|
|
273
|
+
"""Create a new agent."""
|
|
274
|
+
try:
|
|
275
|
+
client = get_client(ctx)
|
|
276
|
+
# Create agent (uses backend default model)
|
|
277
|
+
agent = client.agents.create_agent(
|
|
278
|
+
name=name,
|
|
279
|
+
instruction=instruction,
|
|
280
|
+
tools=list(tools),
|
|
281
|
+
agents=list(agents),
|
|
282
|
+
timeout=timeout,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
if ctx.obj.get("view") == "json":
|
|
286
|
+
click.echo(json.dumps(agent.model_dump(), indent=2))
|
|
287
|
+
else:
|
|
288
|
+
# Rich output
|
|
289
|
+
lm = getattr(agent, "model", None)
|
|
290
|
+
if not lm:
|
|
291
|
+
cfg = getattr(agent, "agent_config", {}) or {}
|
|
292
|
+
lm = (
|
|
293
|
+
cfg.get("lm_name")
|
|
294
|
+
or cfg.get("model")
|
|
295
|
+
or "gpt-4.1 (backend default)"
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
panel = Panel(
|
|
299
|
+
f"[green]✅ Agent '{agent.name}' created successfully![/green]\n\n"
|
|
300
|
+
f"ID: {agent.id}\n"
|
|
301
|
+
f"Model: {lm}\n"
|
|
302
|
+
f"Type: {getattr(agent, 'type', 'config')}\n"
|
|
303
|
+
f"Framework: {getattr(agent, 'framework', 'langchain')}\n"
|
|
304
|
+
f"Version: {getattr(agent, 'version', '1.0')}",
|
|
305
|
+
title="🤖 Agent Created",
|
|
306
|
+
border_style="green",
|
|
307
|
+
)
|
|
308
|
+
console.print(panel)
|
|
309
|
+
|
|
310
|
+
except Exception as e:
|
|
311
|
+
if ctx.obj.get("view") == "json":
|
|
312
|
+
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
313
|
+
else:
|
|
314
|
+
console.print(f"[red]Error creating agent: {e}[/red]")
|
|
315
|
+
raise click.ClickException(str(e))
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@agents_group.command()
|
|
319
|
+
@click.argument("agent_id")
|
|
320
|
+
@click.option("--name", help="New agent name")
|
|
321
|
+
@click.option("--instruction", help="New instruction")
|
|
322
|
+
@click.option("--tools", multiple=True, help="New tool names or IDs")
|
|
323
|
+
@click.option("--agents", multiple=True, help="New sub-agent names")
|
|
324
|
+
@click.option("--timeout", type=int, help="New timeout value")
|
|
325
|
+
@output_flags()
|
|
326
|
+
@click.pass_context
|
|
327
|
+
def update(ctx, agent_id, name, instruction, tools, agents, timeout):
|
|
328
|
+
"""Update an existing agent."""
|
|
329
|
+
try:
|
|
330
|
+
client = get_client(ctx)
|
|
331
|
+
|
|
332
|
+
# Get agent by ID (no ambiguity handling needed)
|
|
333
|
+
try:
|
|
334
|
+
agent = client.agents.get_agent_by_id(agent_id)
|
|
335
|
+
except Exception as e:
|
|
336
|
+
raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}")
|
|
337
|
+
|
|
338
|
+
# Build update data
|
|
339
|
+
update_data = {}
|
|
340
|
+
if name is not None:
|
|
341
|
+
update_data["name"] = name
|
|
342
|
+
if instruction is not None:
|
|
343
|
+
update_data["instruction"] = instruction
|
|
344
|
+
if tools:
|
|
345
|
+
update_data["tools"] = list(tools)
|
|
346
|
+
if agents:
|
|
347
|
+
update_data["agents"] = list(agents)
|
|
348
|
+
if timeout is not None:
|
|
349
|
+
update_data["timeout"] = timeout
|
|
350
|
+
|
|
351
|
+
if not update_data:
|
|
352
|
+
raise click.ClickException("No update fields specified")
|
|
353
|
+
|
|
354
|
+
# Update agent
|
|
355
|
+
updated_agent = client.agents.update_agent(agent.id, update_data)
|
|
356
|
+
|
|
357
|
+
if ctx.obj.get("view") == "json":
|
|
358
|
+
click.echo(json.dumps(updated_agent.model_dump(), indent=2))
|
|
359
|
+
else:
|
|
360
|
+
console.print(
|
|
361
|
+
f"[green]✅ Agent '{updated_agent.name}' updated successfully[/green]"
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
except Exception as e:
|
|
365
|
+
if ctx.obj.get("view") == "json":
|
|
366
|
+
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
367
|
+
else:
|
|
368
|
+
console.print(f"[red]Error updating agent: {e}[/red]")
|
|
369
|
+
raise click.ClickException(str(e))
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
@agents_group.command()
|
|
373
|
+
@click.argument("agent_id")
|
|
374
|
+
@click.option("-y", "--yes", is_flag=True, help="Skip confirmation")
|
|
375
|
+
@output_flags()
|
|
376
|
+
@click.pass_context
|
|
377
|
+
def delete(ctx, agent_id, yes):
|
|
378
|
+
"""Delete an agent."""
|
|
379
|
+
try:
|
|
380
|
+
client = get_client(ctx)
|
|
381
|
+
|
|
382
|
+
# Get agent by ID (no ambiguity handling needed)
|
|
383
|
+
try:
|
|
384
|
+
agent = client.agents.get_agent_by_id(agent_id)
|
|
385
|
+
except Exception as e:
|
|
386
|
+
raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}")
|
|
387
|
+
|
|
388
|
+
# Confirm deletion
|
|
389
|
+
if not yes and not click.confirm(
|
|
390
|
+
f"Are you sure you want to delete agent '{agent.name}'?"
|
|
391
|
+
):
|
|
392
|
+
if ctx.obj.get("view") != "json":
|
|
393
|
+
console.print("Deletion cancelled.")
|
|
394
|
+
return
|
|
395
|
+
|
|
396
|
+
client.agents.delete_agent(agent.id)
|
|
397
|
+
|
|
398
|
+
if ctx.obj.get("view") == "json":
|
|
399
|
+
click.echo(
|
|
400
|
+
json.dumps(
|
|
401
|
+
{"success": True, "message": f"Agent '{agent.name}' deleted"},
|
|
402
|
+
indent=2,
|
|
403
|
+
)
|
|
404
|
+
)
|
|
405
|
+
else:
|
|
406
|
+
console.print(
|
|
407
|
+
f"[green]✅ Agent '{agent.name}' deleted successfully[/green]"
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
except Exception as e:
|
|
411
|
+
if ctx.obj.get("view") == "json":
|
|
412
|
+
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
413
|
+
else:
|
|
414
|
+
console.print(f"[red]Error deleting agent: {e}[/red]")
|
|
415
|
+
raise click.ClickException(str(e))
|