glaip-sdk 0.0.20__py3-none-any.whl → 0.7.7__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 +10 -3
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1250 -0
- glaip_sdk/branding.py +15 -6
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/agent_config.py +2 -6
- glaip_sdk/cli/auth.py +271 -45
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents/__init__.py +119 -0
- glaip_sdk/cli/commands/agents/_common.py +561 -0
- glaip_sdk/cli/commands/agents/create.py +151 -0
- glaip_sdk/cli/commands/agents/delete.py +64 -0
- glaip_sdk/cli/commands/agents/get.py +89 -0
- glaip_sdk/cli/commands/agents/list.py +129 -0
- glaip_sdk/cli/commands/agents/run.py +264 -0
- glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
- glaip_sdk/cli/commands/agents/update.py +112 -0
- glaip_sdk/cli/commands/common_config.py +104 -0
- glaip_sdk/cli/commands/configure.py +734 -143
- glaip_sdk/cli/commands/mcps/__init__.py +94 -0
- glaip_sdk/cli/commands/mcps/_common.py +459 -0
- glaip_sdk/cli/commands/mcps/connect.py +82 -0
- glaip_sdk/cli/commands/mcps/create.py +152 -0
- glaip_sdk/cli/commands/mcps/delete.py +73 -0
- glaip_sdk/cli/commands/mcps/get.py +212 -0
- glaip_sdk/cli/commands/mcps/list.py +69 -0
- glaip_sdk/cli/commands/mcps/tools.py +235 -0
- glaip_sdk/cli/commands/mcps/update.py +190 -0
- glaip_sdk/cli/commands/models.py +14 -12
- glaip_sdk/cli/commands/shared/__init__.py +21 -0
- glaip_sdk/cli/commands/shared/formatters.py +91 -0
- glaip_sdk/cli/commands/tools/__init__.py +69 -0
- glaip_sdk/cli/commands/tools/_common.py +80 -0
- glaip_sdk/cli/commands/tools/create.py +228 -0
- glaip_sdk/cli/commands/tools/delete.py +61 -0
- glaip_sdk/cli/commands/tools/get.py +103 -0
- glaip_sdk/cli/commands/tools/list.py +69 -0
- glaip_sdk/cli/commands/tools/script.py +49 -0
- glaip_sdk/cli/commands/tools/update.py +102 -0
- glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
- glaip_sdk/cli/commands/transcripts/_common.py +9 -0
- glaip_sdk/cli/commands/transcripts/clear.py +5 -0
- glaip_sdk/cli/commands/transcripts/detail.py +5 -0
- glaip_sdk/cli/commands/transcripts_original.py +756 -0
- glaip_sdk/cli/commands/update.py +164 -23
- glaip_sdk/cli/config.py +49 -7
- 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 +45 -32
- glaip_sdk/cli/entrypoint.py +20 -0
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +14 -17
- glaip_sdk/cli/main.py +344 -167
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/mcp_validators.py +5 -15
- glaip_sdk/cli/pager.py +15 -22
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/parsers/json_input.py +11 -22
- glaip_sdk/cli/resolution.py +5 -10
- glaip_sdk/cli/rich_helpers.py +1 -3
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/accounts_controller.py +580 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +65 -29
- glaip_sdk/cli/slash/prompt.py +24 -10
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +827 -232
- glaip_sdk/cli/slash/tui/__init__.py +34 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +88 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +933 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/clipboard.py +147 -0
- glaip_sdk/cli/slash/tui/context.py +59 -0
- glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/slash/tui/terminal.py +402 -0
- glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
- glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
- glaip_sdk/cli/slash/tui/theme/manager.py +86 -0
- glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
- glaip_sdk/cli/slash/tui/toast.py +123 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +258 -60
- glaip_sdk/cli/transcript/capture.py +72 -21
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/launcher.py +1 -3
- glaip_sdk/cli/transcript/viewer.py +79 -329
- glaip_sdk/cli/update_notifier.py +385 -24
- glaip_sdk/cli/validators.py +16 -18
- glaip_sdk/client/__init__.py +3 -1
- glaip_sdk/client/_schedule_payloads.py +89 -0
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +370 -100
- glaip_sdk/client/base.py +78 -35
- glaip_sdk/client/hitl.py +136 -0
- glaip_sdk/client/main.py +25 -10
- glaip_sdk/client/mcps.py +166 -27
- glaip_sdk/client/payloads/agent/__init__.py +23 -0
- glaip_sdk/client/{_agent_payloads.py → payloads/agent/requests.py} +65 -74
- glaip_sdk/client/payloads/agent/responses.py +43 -0
- glaip_sdk/client/run_rendering.py +583 -79
- glaip_sdk/client/schedules.py +439 -0
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +214 -56
- glaip_sdk/client/validators.py +20 -48
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/exceptions.py +1 -3
- glaip_sdk/hitl/__init__.py +48 -0
- glaip_sdk/hitl/base.py +64 -0
- glaip_sdk/hitl/callback.py +43 -0
- glaip_sdk/hitl/local.py +121 -0
- glaip_sdk/hitl/remote.py +523 -0
- glaip_sdk/icons.py +9 -3
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +107 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +117 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/schedule.py +224 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/payload_schemas/agent.py +1 -3
- 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 +445 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/runner/__init__.py +76 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +112 -0
- glaip_sdk/runner/langgraph.py +872 -0
- glaip_sdk/runner/logging_config.py +77 -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 +242 -0
- glaip_sdk/schedules/__init__.py +22 -0
- glaip_sdk/schedules/base.py +291 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +468 -0
- glaip_sdk/utils/__init__.py +59 -12
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/agent_config.py +4 -14
- glaip_sdk/utils/bundler.py +403 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +46 -28
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +25 -21
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +1 -36
- glaip_sdk/utils/import_export.py +15 -16
- glaip_sdk/utils/import_resolver.py +524 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -1
- glaip_sdk/utils/rendering/formatting.py +38 -23
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer → layout}/panels.py +10 -3
- glaip_sdk/utils/rendering/{renderer → layout}/progress.py +73 -12
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +18 -8
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -51
- glaip_sdk/utils/rendering/renderer/base.py +534 -882
- glaip_sdk/utils/rendering/renderer/config.py +4 -10
- glaip_sdk/utils/rendering/renderer/debug.py +30 -34
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +13 -54
- glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/toggle.py +182 -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/step_tree_state.py +100 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/steps/event_processor.py +778 -0
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/{steps.py → steps/manager.py} +122 -26
- 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 +29 -26
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +32 -46
- glaip_sdk/utils/sync.py +162 -0
- glaip_sdk/utils/tool_detection.py +301 -0
- glaip_sdk/utils/tool_storage_provider.py +140 -0
- glaip_sdk/utils/validation.py +20 -28
- {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.7.7.dist-info}/METADATA +78 -23
- glaip_sdk-0.7.7.dist-info/RECORD +213 -0
- {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.7.7.dist-info}/WHEEL +2 -1
- glaip_sdk-0.7.7.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.7.7.dist-info/top_level.txt +1 -0
- glaip_sdk/cli/commands/agents.py +0 -1412
- glaip_sdk/cli/commands/mcps.py +0 -1225
- glaip_sdk/cli/commands/tools.py +0 -597
- glaip_sdk/cli/utils.py +0 -1330
- glaip_sdk/models.py +0 -259
- glaip_sdk-0.0.20.dist-info/RECORD +0 -80
- glaip_sdk-0.0.20.dist-info/entry_points.txt +0 -3
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Common models for AIP SDK.
|
|
2
|
+
|
|
3
|
+
This module contains common models that don't fit into specific categories.
|
|
4
|
+
|
|
5
|
+
Authors:
|
|
6
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
7
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LanguageModelResponse(BaseModel):
|
|
14
|
+
"""Language model response model."""
|
|
15
|
+
|
|
16
|
+
name: str
|
|
17
|
+
provider: str
|
|
18
|
+
description: str | None = None
|
|
19
|
+
capabilities: list[str] | None = None
|
|
20
|
+
max_tokens: int | None = None
|
|
21
|
+
supports_streaming: bool = False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TTYRenderer:
|
|
25
|
+
"""Simple TTY renderer for non-Rich environments."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, use_color: bool = True):
|
|
28
|
+
"""Initialize the TTY renderer.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
use_color: Whether to use color output
|
|
32
|
+
"""
|
|
33
|
+
self.use_color = use_color
|
|
34
|
+
|
|
35
|
+
def render_message(self, message: str, event_type: str = "message") -> None:
|
|
36
|
+
"""Render a message with optional color."""
|
|
37
|
+
if event_type == "error":
|
|
38
|
+
print(f"ERROR: {message}", flush=True)
|
|
39
|
+
elif event_type == "done":
|
|
40
|
+
print(f"\n✅ {message}", flush=True)
|
|
41
|
+
else:
|
|
42
|
+
print(message, flush=True)
|
glaip_sdk/models/mcp.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""MCP response model for AIP SDK.
|
|
2
|
+
|
|
3
|
+
This module contains the Pydantic model for MCP API responses.
|
|
4
|
+
This is a pure data model with no runtime behavior.
|
|
5
|
+
|
|
6
|
+
For the runtime MCP class with update/delete methods, use glaip_sdk.mcps.MCP.
|
|
7
|
+
|
|
8
|
+
Authors:
|
|
9
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
10
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MCPResponse(BaseModel):
|
|
19
|
+
"""Pydantic model for MCP API responses.
|
|
20
|
+
|
|
21
|
+
This is a pure data model for deserializing API responses.
|
|
22
|
+
It does NOT have runtime methods (update, delete, get_tools).
|
|
23
|
+
|
|
24
|
+
For the runtime MCP class, use glaip_sdk.mcps.MCP.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
id: str
|
|
28
|
+
name: str
|
|
29
|
+
description: str | None = None
|
|
30
|
+
config: dict[str, Any] | None = None
|
|
31
|
+
transport: str | None = None # "sse" or "http"
|
|
32
|
+
authentication: dict[str, Any] | None = None
|
|
33
|
+
metadata: dict[str, Any] | None = None
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Schedule DTO models for AIP SDK.
|
|
3
|
+
|
|
4
|
+
These models represent API payloads and responses. They are intentionally DTO-only
|
|
5
|
+
and do not contain runtime behavior.
|
|
6
|
+
|
|
7
|
+
Authors:
|
|
8
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
9
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict
|
|
16
|
+
|
|
17
|
+
from glaip_sdk.models.agent_runs import RunStatus
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ScheduleConfig(BaseModel):
|
|
21
|
+
"""Cron-like schedule configuration matching backend ScheduleConfig.
|
|
22
|
+
|
|
23
|
+
All fields accept cron-style values:
|
|
24
|
+
- Specific values: "0", "9", "1"
|
|
25
|
+
- Wildcards: "*"
|
|
26
|
+
- Intervals: "*/5", "*/2"
|
|
27
|
+
- Ranges: "1-5", "9-17"
|
|
28
|
+
- Lists: "1,3,5"
|
|
29
|
+
|
|
30
|
+
Note: day_of_week uses 0-6 where 0=Monday.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
minute: str = "*"
|
|
34
|
+
hour: str = "*"
|
|
35
|
+
day_of_month: str = "*"
|
|
36
|
+
month: str = "*"
|
|
37
|
+
day_of_week: str = "*"
|
|
38
|
+
|
|
39
|
+
model_config = ConfigDict(from_attributes=True)
|
|
40
|
+
|
|
41
|
+
def to_cron_string(self) -> str:
|
|
42
|
+
"""Convert to standard cron string format.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Cron string in format "minute hour day_of_month month day_of_week"
|
|
46
|
+
"""
|
|
47
|
+
return f"{self.minute} {self.hour} {self.day_of_month} {self.month} {self.day_of_week}"
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_cron_string(cls, cron: str) -> "ScheduleConfig":
|
|
51
|
+
"""Parse a cron string into ScheduleConfig.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
cron: Cron string in format "minute hour day_of_month month day_of_week"
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
ScheduleConfig instance
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
ValueError: If cron string doesn't have exactly 5 fields
|
|
61
|
+
"""
|
|
62
|
+
parts = cron.split()
|
|
63
|
+
if len(parts) != 5:
|
|
64
|
+
raise ValueError(f"Invalid cron string: expected 5 fields, got {len(parts)}")
|
|
65
|
+
return cls(
|
|
66
|
+
minute=parts[0],
|
|
67
|
+
hour=parts[1],
|
|
68
|
+
day_of_month=parts[2],
|
|
69
|
+
month=parts[3],
|
|
70
|
+
day_of_week=parts[4],
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ScheduleMetadata(BaseModel):
|
|
75
|
+
"""Metadata embedded in schedule responses.
|
|
76
|
+
|
|
77
|
+
Contains the agent association, input text, and cron configuration.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
agent_id: str
|
|
81
|
+
input: str
|
|
82
|
+
schedule: ScheduleConfig
|
|
83
|
+
|
|
84
|
+
model_config = ConfigDict(from_attributes=True)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ScheduleResponse(BaseModel):
|
|
88
|
+
"""Schedule response DTO.
|
|
89
|
+
|
|
90
|
+
Attributes:
|
|
91
|
+
id: Schedule ID.
|
|
92
|
+
next_run_time: Next run time as returned by the API.
|
|
93
|
+
time_until_next_run: Human-readable duration until next run.
|
|
94
|
+
metadata: Schedule metadata.
|
|
95
|
+
created_at: Creation timestamp.
|
|
96
|
+
updated_at: Update timestamp.
|
|
97
|
+
agent_id: Agent ID derived from metadata.
|
|
98
|
+
input: Input text derived from metadata.
|
|
99
|
+
schedule_config: ScheduleConfig derived from metadata.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
id: str
|
|
103
|
+
next_run_time: str | None = None
|
|
104
|
+
time_until_next_run: str | None = None
|
|
105
|
+
metadata: ScheduleMetadata | None = None
|
|
106
|
+
created_at: datetime | None = None
|
|
107
|
+
updated_at: datetime | None = None
|
|
108
|
+
|
|
109
|
+
model_config = ConfigDict(from_attributes=True)
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def agent_id(self) -> str | None:
|
|
113
|
+
"""Get the agent ID from metadata."""
|
|
114
|
+
return self.metadata.agent_id if self.metadata else None
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def input(self) -> str | None:
|
|
118
|
+
"""Get the scheduled input text from metadata."""
|
|
119
|
+
return self.metadata.input if self.metadata else None
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def schedule_config(self) -> ScheduleConfig | None:
|
|
123
|
+
"""Get the schedule configuration from metadata."""
|
|
124
|
+
return self.metadata.schedule if self.metadata else None
|
|
125
|
+
|
|
126
|
+
def __repr__(self) -> str:
|
|
127
|
+
"""Return a readable representation of the schedule."""
|
|
128
|
+
parts = [f"ScheduleResponse(id={self.id!r}"]
|
|
129
|
+
if self.next_run_time:
|
|
130
|
+
parts.append(f"next_run_time={self.next_run_time!r}")
|
|
131
|
+
if self.time_until_next_run:
|
|
132
|
+
parts.append(f"time_until_next_run={self.time_until_next_run!r}")
|
|
133
|
+
if self.agent_id:
|
|
134
|
+
parts.append(f"agent_id={self.agent_id!r}")
|
|
135
|
+
if self.created_at:
|
|
136
|
+
parts.append(f"created_at={self.created_at!r}")
|
|
137
|
+
return ", ".join(parts) + ")"
|
|
138
|
+
|
|
139
|
+
def __str__(self) -> str:
|
|
140
|
+
"""Return a readable string representation."""
|
|
141
|
+
return self.__repr__()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# Type alias for SSE event dictionaries
|
|
145
|
+
ScheduleRunOutputChunk = dict[str, Any]
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class ScheduleRunResponse(BaseModel):
|
|
149
|
+
"""Schedule run response DTO."""
|
|
150
|
+
|
|
151
|
+
id: str
|
|
152
|
+
agent_id: str
|
|
153
|
+
schedule_id: str | None = None # May be None for non-scheduled runs
|
|
154
|
+
status: RunStatus # Backend uses lowercase.
|
|
155
|
+
run_type: str | None = None # "schedule" for scheduled runs
|
|
156
|
+
started_at: datetime | None = None
|
|
157
|
+
completed_at: datetime | None = None
|
|
158
|
+
input: str | None = None # Input used for the execution.
|
|
159
|
+
config: ScheduleConfig | dict[str, str] | None = None # Schedule config used.
|
|
160
|
+
created_at: datetime | None = None
|
|
161
|
+
updated_at: datetime | None = None
|
|
162
|
+
|
|
163
|
+
model_config = ConfigDict(from_attributes=True, extra="ignore")
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def duration(self) -> str | None:
|
|
167
|
+
"""Calculate the duration of the run.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Formatted duration string (HH:MM:SS) or None if incomplete
|
|
171
|
+
"""
|
|
172
|
+
if self.started_at and self.completed_at:
|
|
173
|
+
delta = self.completed_at - self.started_at
|
|
174
|
+
total_seconds = int(delta.total_seconds())
|
|
175
|
+
hours, remainder = divmod(total_seconds, 3600)
|
|
176
|
+
minutes, seconds = divmod(remainder, 60)
|
|
177
|
+
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
def __repr__(self) -> str:
|
|
181
|
+
"""Return a readable representation of the run."""
|
|
182
|
+
parts = [f"ScheduleRunResponse(id={self.id!r}"]
|
|
183
|
+
parts.append(f"status={self.status!r}")
|
|
184
|
+
if self.started_at:
|
|
185
|
+
parts.append(f"started_at={self.started_at.isoformat()!r}")
|
|
186
|
+
if self.duration:
|
|
187
|
+
parts.append(f"duration={self.duration!r}")
|
|
188
|
+
return ", ".join(parts) + ")"
|
|
189
|
+
|
|
190
|
+
def __str__(self) -> str:
|
|
191
|
+
"""Return a readable string representation."""
|
|
192
|
+
return self.__repr__()
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ScheduleRunResult(BaseModel):
|
|
196
|
+
"""Full output payload for a schedule run.
|
|
197
|
+
|
|
198
|
+
Maps to the backend's AgentRunWithOutputResponse which includes
|
|
199
|
+
run metadata plus the output stream.
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
id: str
|
|
203
|
+
agent_id: str
|
|
204
|
+
schedule_id: str | None = None
|
|
205
|
+
status: RunStatus
|
|
206
|
+
run_type: str | None = None
|
|
207
|
+
started_at: datetime | None = None
|
|
208
|
+
completed_at: datetime | None = None
|
|
209
|
+
input: str | None = None # Input used for the execution.
|
|
210
|
+
config: ScheduleConfig | dict[str, str] | None = None # Schedule config used.
|
|
211
|
+
output: list[ScheduleRunOutputChunk] | None = None
|
|
212
|
+
created_at: datetime | None = None
|
|
213
|
+
updated_at: datetime | None = None
|
|
214
|
+
|
|
215
|
+
model_config = ConfigDict(from_attributes=True, extra="ignore")
|
|
216
|
+
|
|
217
|
+
def __repr__(self) -> str:
|
|
218
|
+
"""Return a readable representation of the result."""
|
|
219
|
+
output_count = len(self.output) if self.output else 0
|
|
220
|
+
return f"ScheduleRunResult(id={self.id!r}, status={self.status!r}, output_chunks={output_count})"
|
|
221
|
+
|
|
222
|
+
def __str__(self) -> str:
|
|
223
|
+
"""Return a readable string representation."""
|
|
224
|
+
return self.__repr__()
|
glaip_sdk/models/tool.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Tool response model for AIP SDK.
|
|
2
|
+
|
|
3
|
+
This module contains the Pydantic model for Tool API responses.
|
|
4
|
+
This is a pure data model with no runtime behavior.
|
|
5
|
+
|
|
6
|
+
For the runtime Tool class with update/delete methods, use glaip_sdk.tools.Tool.
|
|
7
|
+
|
|
8
|
+
Authors:
|
|
9
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
10
|
+
Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ToolResponse(BaseModel):
|
|
17
|
+
"""Pydantic model for Tool API responses.
|
|
18
|
+
|
|
19
|
+
This is a pure data model for deserializing API responses.
|
|
20
|
+
It does NOT have runtime methods (update, delete, get_script).
|
|
21
|
+
|
|
22
|
+
For the runtime Tool class, use glaip_sdk.tools.Tool.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
id: str
|
|
26
|
+
name: str
|
|
27
|
+
tool_type: str | None = None
|
|
28
|
+
description: str | None = None
|
|
29
|
+
framework: str | None = None
|
|
30
|
+
version: str | None = None
|
|
31
|
+
tool_script: str | None = None
|
|
32
|
+
tool_file: str | None = None
|
|
33
|
+
tags: str | list[str] | None = None
|
|
@@ -4,16 +4,4 @@ Authors:
|
|
|
4
4
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
AgentImportOperation,
|
|
9
|
-
ImportFieldPlan,
|
|
10
|
-
get_import_field_plan,
|
|
11
|
-
list_server_only_fields,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
__all__ = [
|
|
15
|
-
"AgentImportOperation",
|
|
16
|
-
"ImportFieldPlan",
|
|
17
|
-
"get_import_field_plan",
|
|
18
|
-
"list_server_only_fields",
|
|
19
|
-
]
|
|
7
|
+
__all__: list[str] = []
|
|
@@ -60,9 +60,7 @@ AGENT_FIELD_RULES: Mapping[str, FieldRule] = {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
def get_import_field_plan(
|
|
64
|
-
field_name: str, operation: AgentImportOperation
|
|
65
|
-
) -> ImportFieldPlan:
|
|
63
|
+
def get_import_field_plan(field_name: str, operation: AgentImportOperation) -> ImportFieldPlan:
|
|
66
64
|
"""Return the import handling plan for ``field_name`` under ``operation``.
|
|
67
65
|
|
|
68
66
|
Unknown fields default to being copied as-is so new API fields propagate
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Registry package for GL AIP platform.
|
|
2
|
+
|
|
3
|
+
This package provides registries that cache platform objects to avoid
|
|
4
|
+
redundant API calls when deploying multi-agent systems.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
>>> from glaip_sdk.registry import get_agent_registry, get_tool_registry
|
|
8
|
+
>>> agent_registry = get_agent_registry()
|
|
9
|
+
>>> tool_registry = get_tool_registry()
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import importlib
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from glaip_sdk.registry.base import BaseRegistry
|
|
18
|
+
|
|
19
|
+
# Lazy imports to avoid circular dependencies
|
|
20
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
21
|
+
from glaip_sdk.registry.agent import AgentRegistry, get_agent_registry
|
|
22
|
+
from glaip_sdk.registry.mcp import MCPRegistry, get_mcp_registry
|
|
23
|
+
from glaip_sdk.registry.tool import ToolRegistry, get_tool_registry
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"BaseRegistry",
|
|
27
|
+
"AgentRegistry",
|
|
28
|
+
"get_agent_registry",
|
|
29
|
+
"ToolRegistry",
|
|
30
|
+
"get_tool_registry",
|
|
31
|
+
"MCPRegistry",
|
|
32
|
+
"get_mcp_registry",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def __getattr__(name: str) -> type:
|
|
37
|
+
"""Lazy import to avoid circular dependencies."""
|
|
38
|
+
_agent_module = "glaip_sdk.registry.agent"
|
|
39
|
+
_tool_module = "glaip_sdk.registry.tool"
|
|
40
|
+
_mcp_module = "glaip_sdk.registry.mcp"
|
|
41
|
+
|
|
42
|
+
lazy_imports = {
|
|
43
|
+
"AgentRegistry": _agent_module,
|
|
44
|
+
"get_agent_registry": _agent_module,
|
|
45
|
+
"ToolRegistry": _tool_module,
|
|
46
|
+
"get_tool_registry": _tool_module,
|
|
47
|
+
"MCPRegistry": _mcp_module,
|
|
48
|
+
"get_mcp_registry": _mcp_module,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if name in lazy_imports:
|
|
52
|
+
module = importlib.import_module(lazy_imports[name])
|
|
53
|
+
return getattr(module, name)
|
|
54
|
+
|
|
55
|
+
raise AttributeError(f"module 'glaip_sdk.registry' has no attribute '{name}'")
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Agent registry for glaip_sdk.
|
|
2
|
+
|
|
3
|
+
This module provides the AgentRegistry that caches deployed agents
|
|
4
|
+
to avoid redundant API calls when deploying multi-agent systems.
|
|
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.agents import Agent
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AgentRegistry(BaseRegistry["Agent"]):
|
|
24
|
+
"""Registry for agents.
|
|
25
|
+
|
|
26
|
+
Resolves agent references to glaip_sdk.models.Agent objects.
|
|
27
|
+
Caches results to avoid redundant API calls and duplicate deployments.
|
|
28
|
+
|
|
29
|
+
Handles:
|
|
30
|
+
- glaip_sdk.agents.Agent classes → deploy, cache, return Agent
|
|
31
|
+
- glaip_sdk.agents.Agent instances → deploy, cache, return Agent
|
|
32
|
+
- glaip_sdk.models.Agent → return as-is (uses agent.id)
|
|
33
|
+
- String names → lookup on platform, cache, return Agent
|
|
34
|
+
|
|
35
|
+
Attributes:
|
|
36
|
+
_cache: Internal cache mapping names to Agent objects.
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> registry = get_agent_registry()
|
|
40
|
+
>>> agent = registry.resolve(GreeterAgent) # Returns deployed Agent
|
|
41
|
+
>>> print(agent.id) # "uuid-123"
|
|
42
|
+
>>> print(agent.name) # "greeter_agent"
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def _extract_name(self, ref: Any) -> str:
|
|
46
|
+
"""Extract agent name from a reference.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
ref: An agent class, instance, or string name.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
The extracted agent name.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If name cannot be extracted from the reference.
|
|
56
|
+
"""
|
|
57
|
+
# Lazy import to avoid circular dependency
|
|
58
|
+
from glaip_sdk.agents.base import Agent # noqa: PLC0415
|
|
59
|
+
|
|
60
|
+
# Agent class
|
|
61
|
+
if isinstance(ref, type) and issubclass(ref, Agent):
|
|
62
|
+
return ref().name
|
|
63
|
+
|
|
64
|
+
# Agent instance
|
|
65
|
+
if isinstance(ref, Agent):
|
|
66
|
+
return ref.name
|
|
67
|
+
|
|
68
|
+
# Already deployed agent (glaip_sdk.models.Agent)
|
|
69
|
+
if hasattr(ref, "id") and hasattr(ref, "name") and not isinstance(ref, type):
|
|
70
|
+
return ref.name
|
|
71
|
+
|
|
72
|
+
# String name
|
|
73
|
+
if isinstance(ref, str):
|
|
74
|
+
return ref
|
|
75
|
+
|
|
76
|
+
raise ValueError(f"Cannot extract name from: {ref}")
|
|
77
|
+
|
|
78
|
+
def _resolve_and_cache(self, ref: Any, name: str) -> Agent:
|
|
79
|
+
"""Resolve agent reference - deploy if class/instance, find if string.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
ref: The agent reference to resolve.
|
|
83
|
+
name: The extracted agent name.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
The resolved glaip_sdk.models.Agent object.
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
ValueError: If the agent cannot be resolved.
|
|
90
|
+
"""
|
|
91
|
+
# Lazy imports to avoid circular dependency
|
|
92
|
+
from glaip_sdk.agents.base import Agent # noqa: PLC0415
|
|
93
|
+
from glaip_sdk.utils.discovery import find_agent # noqa: PLC0415
|
|
94
|
+
|
|
95
|
+
# Agent class
|
|
96
|
+
if isinstance(ref, type) and issubclass(ref, Agent):
|
|
97
|
+
logger.info("Deploying Agent class: %s", name)
|
|
98
|
+
deployed = ref().deploy()
|
|
99
|
+
self._cache[name] = deployed
|
|
100
|
+
return deployed
|
|
101
|
+
|
|
102
|
+
# Agent instance
|
|
103
|
+
if isinstance(ref, Agent):
|
|
104
|
+
logger.info("Deploying Agent instance: %s", name)
|
|
105
|
+
deployed = ref.deploy()
|
|
106
|
+
self._cache[name] = deployed
|
|
107
|
+
return deployed
|
|
108
|
+
|
|
109
|
+
# Already deployed agent (glaip_sdk.models.Agent) - just cache and return
|
|
110
|
+
if hasattr(ref, "id") and hasattr(ref, "name") and not isinstance(ref, type):
|
|
111
|
+
logger.debug("Caching already deployed agent: %s", name)
|
|
112
|
+
self._cache[name] = ref
|
|
113
|
+
return ref
|
|
114
|
+
|
|
115
|
+
# String name - look up on platform
|
|
116
|
+
if isinstance(ref, str):
|
|
117
|
+
logger.info("Looking up agent by name: %s", name)
|
|
118
|
+
agent = find_agent(name)
|
|
119
|
+
if agent:
|
|
120
|
+
self._cache[name] = agent
|
|
121
|
+
return agent
|
|
122
|
+
raise ValueError(f"Agent not found on platform: {name}")
|
|
123
|
+
|
|
124
|
+
raise ValueError(f"Could not resolve agent reference: {ref}")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class _AgentRegistrySingleton:
|
|
128
|
+
"""Singleton holder for AgentRegistry to avoid global statement."""
|
|
129
|
+
|
|
130
|
+
_instance: AgentRegistry | None = None
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def get_instance(cls) -> AgentRegistry:
|
|
134
|
+
"""Get or create the singleton instance.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
The global AgentRegistry instance.
|
|
138
|
+
"""
|
|
139
|
+
if cls._instance is None:
|
|
140
|
+
cls._instance = AgentRegistry()
|
|
141
|
+
return cls._instance
|
|
142
|
+
|
|
143
|
+
@classmethod
|
|
144
|
+
def reset(cls) -> None:
|
|
145
|
+
"""Reset the singleton instance (for testing)."""
|
|
146
|
+
cls._instance = None
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_agent_registry() -> AgentRegistry:
|
|
150
|
+
"""Get the singleton AgentRegistry instance.
|
|
151
|
+
|
|
152
|
+
Returns a global AgentRegistry that caches agents across the session.
|
|
153
|
+
Use this function to get the registry instead of creating instances directly.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
The global AgentRegistry instance.
|
|
157
|
+
|
|
158
|
+
Example:
|
|
159
|
+
>>> from glaip_sdk.registry import get_agent_registry
|
|
160
|
+
>>> registry = get_agent_registry()
|
|
161
|
+
>>> agent = registry.resolve("weather_agent")
|
|
162
|
+
>>> print(agent.name)
|
|
163
|
+
"""
|
|
164
|
+
return _AgentRegistrySingleton.get_instance()
|