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.
Files changed (216) hide show
  1. glaip_sdk/__init__.py +44 -4
  2. glaip_sdk/_version.py +10 -3
  3. glaip_sdk/agents/__init__.py +27 -0
  4. glaip_sdk/agents/base.py +1250 -0
  5. glaip_sdk/branding.py +15 -6
  6. glaip_sdk/cli/account_store.py +540 -0
  7. glaip_sdk/cli/agent_config.py +2 -6
  8. glaip_sdk/cli/auth.py +271 -45
  9. glaip_sdk/cli/commands/__init__.py +2 -2
  10. glaip_sdk/cli/commands/accounts.py +746 -0
  11. glaip_sdk/cli/commands/agents/__init__.py +119 -0
  12. glaip_sdk/cli/commands/agents/_common.py +561 -0
  13. glaip_sdk/cli/commands/agents/create.py +151 -0
  14. glaip_sdk/cli/commands/agents/delete.py +64 -0
  15. glaip_sdk/cli/commands/agents/get.py +89 -0
  16. glaip_sdk/cli/commands/agents/list.py +129 -0
  17. glaip_sdk/cli/commands/agents/run.py +264 -0
  18. glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
  19. glaip_sdk/cli/commands/agents/update.py +112 -0
  20. glaip_sdk/cli/commands/common_config.py +104 -0
  21. glaip_sdk/cli/commands/configure.py +734 -143
  22. glaip_sdk/cli/commands/mcps/__init__.py +94 -0
  23. glaip_sdk/cli/commands/mcps/_common.py +459 -0
  24. glaip_sdk/cli/commands/mcps/connect.py +82 -0
  25. glaip_sdk/cli/commands/mcps/create.py +152 -0
  26. glaip_sdk/cli/commands/mcps/delete.py +73 -0
  27. glaip_sdk/cli/commands/mcps/get.py +212 -0
  28. glaip_sdk/cli/commands/mcps/list.py +69 -0
  29. glaip_sdk/cli/commands/mcps/tools.py +235 -0
  30. glaip_sdk/cli/commands/mcps/update.py +190 -0
  31. glaip_sdk/cli/commands/models.py +14 -12
  32. glaip_sdk/cli/commands/shared/__init__.py +21 -0
  33. glaip_sdk/cli/commands/shared/formatters.py +91 -0
  34. glaip_sdk/cli/commands/tools/__init__.py +69 -0
  35. glaip_sdk/cli/commands/tools/_common.py +80 -0
  36. glaip_sdk/cli/commands/tools/create.py +228 -0
  37. glaip_sdk/cli/commands/tools/delete.py +61 -0
  38. glaip_sdk/cli/commands/tools/get.py +103 -0
  39. glaip_sdk/cli/commands/tools/list.py +69 -0
  40. glaip_sdk/cli/commands/tools/script.py +49 -0
  41. glaip_sdk/cli/commands/tools/update.py +102 -0
  42. glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
  43. glaip_sdk/cli/commands/transcripts/_common.py +9 -0
  44. glaip_sdk/cli/commands/transcripts/clear.py +5 -0
  45. glaip_sdk/cli/commands/transcripts/detail.py +5 -0
  46. glaip_sdk/cli/commands/transcripts_original.py +756 -0
  47. glaip_sdk/cli/commands/update.py +164 -23
  48. glaip_sdk/cli/config.py +49 -7
  49. glaip_sdk/cli/constants.py +38 -0
  50. glaip_sdk/cli/context.py +8 -0
  51. glaip_sdk/cli/core/__init__.py +79 -0
  52. glaip_sdk/cli/core/context.py +124 -0
  53. glaip_sdk/cli/core/output.py +851 -0
  54. glaip_sdk/cli/core/prompting.py +649 -0
  55. glaip_sdk/cli/core/rendering.py +187 -0
  56. glaip_sdk/cli/display.py +45 -32
  57. glaip_sdk/cli/entrypoint.py +20 -0
  58. glaip_sdk/cli/hints.py +57 -0
  59. glaip_sdk/cli/io.py +14 -17
  60. glaip_sdk/cli/main.py +344 -167
  61. glaip_sdk/cli/masking.py +21 -33
  62. glaip_sdk/cli/mcp_validators.py +5 -15
  63. glaip_sdk/cli/pager.py +15 -22
  64. glaip_sdk/cli/parsers/__init__.py +1 -3
  65. glaip_sdk/cli/parsers/json_input.py +11 -22
  66. glaip_sdk/cli/resolution.py +5 -10
  67. glaip_sdk/cli/rich_helpers.py +1 -3
  68. glaip_sdk/cli/slash/__init__.py +0 -9
  69. glaip_sdk/cli/slash/accounts_controller.py +580 -0
  70. glaip_sdk/cli/slash/accounts_shared.py +75 -0
  71. glaip_sdk/cli/slash/agent_session.py +65 -29
  72. glaip_sdk/cli/slash/prompt.py +24 -10
  73. glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
  74. glaip_sdk/cli/slash/session.py +827 -232
  75. glaip_sdk/cli/slash/tui/__init__.py +34 -0
  76. glaip_sdk/cli/slash/tui/accounts.tcss +88 -0
  77. glaip_sdk/cli/slash/tui/accounts_app.py +933 -0
  78. glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
  79. glaip_sdk/cli/slash/tui/clipboard.py +147 -0
  80. glaip_sdk/cli/slash/tui/context.py +59 -0
  81. glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
  82. glaip_sdk/cli/slash/tui/loading.py +58 -0
  83. glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
  84. glaip_sdk/cli/slash/tui/terminal.py +402 -0
  85. glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
  86. glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
  87. glaip_sdk/cli/slash/tui/theme/manager.py +86 -0
  88. glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
  89. glaip_sdk/cli/slash/tui/toast.py +123 -0
  90. glaip_sdk/cli/transcript/__init__.py +12 -52
  91. glaip_sdk/cli/transcript/cache.py +258 -60
  92. glaip_sdk/cli/transcript/capture.py +72 -21
  93. glaip_sdk/cli/transcript/history.py +815 -0
  94. glaip_sdk/cli/transcript/launcher.py +1 -3
  95. glaip_sdk/cli/transcript/viewer.py +79 -329
  96. glaip_sdk/cli/update_notifier.py +385 -24
  97. glaip_sdk/cli/validators.py +16 -18
  98. glaip_sdk/client/__init__.py +3 -1
  99. glaip_sdk/client/_schedule_payloads.py +89 -0
  100. glaip_sdk/client/agent_runs.py +147 -0
  101. glaip_sdk/client/agents.py +370 -100
  102. glaip_sdk/client/base.py +78 -35
  103. glaip_sdk/client/hitl.py +136 -0
  104. glaip_sdk/client/main.py +25 -10
  105. glaip_sdk/client/mcps.py +166 -27
  106. glaip_sdk/client/payloads/agent/__init__.py +23 -0
  107. glaip_sdk/client/{_agent_payloads.py → payloads/agent/requests.py} +65 -74
  108. glaip_sdk/client/payloads/agent/responses.py +43 -0
  109. glaip_sdk/client/run_rendering.py +583 -79
  110. glaip_sdk/client/schedules.py +439 -0
  111. glaip_sdk/client/shared.py +21 -0
  112. glaip_sdk/client/tools.py +214 -56
  113. glaip_sdk/client/validators.py +20 -48
  114. glaip_sdk/config/constants.py +11 -0
  115. glaip_sdk/exceptions.py +1 -3
  116. glaip_sdk/hitl/__init__.py +48 -0
  117. glaip_sdk/hitl/base.py +64 -0
  118. glaip_sdk/hitl/callback.py +43 -0
  119. glaip_sdk/hitl/local.py +121 -0
  120. glaip_sdk/hitl/remote.py +523 -0
  121. glaip_sdk/icons.py +9 -3
  122. glaip_sdk/mcps/__init__.py +21 -0
  123. glaip_sdk/mcps/base.py +345 -0
  124. glaip_sdk/models/__init__.py +107 -0
  125. glaip_sdk/models/agent.py +47 -0
  126. glaip_sdk/models/agent_runs.py +117 -0
  127. glaip_sdk/models/common.py +42 -0
  128. glaip_sdk/models/mcp.py +33 -0
  129. glaip_sdk/models/schedule.py +224 -0
  130. glaip_sdk/models/tool.py +33 -0
  131. glaip_sdk/payload_schemas/__init__.py +1 -13
  132. glaip_sdk/payload_schemas/agent.py +1 -3
  133. glaip_sdk/registry/__init__.py +55 -0
  134. glaip_sdk/registry/agent.py +164 -0
  135. glaip_sdk/registry/base.py +139 -0
  136. glaip_sdk/registry/mcp.py +253 -0
  137. glaip_sdk/registry/tool.py +445 -0
  138. glaip_sdk/rich_components.py +58 -2
  139. glaip_sdk/runner/__init__.py +76 -0
  140. glaip_sdk/runner/base.py +84 -0
  141. glaip_sdk/runner/deps.py +112 -0
  142. glaip_sdk/runner/langgraph.py +872 -0
  143. glaip_sdk/runner/logging_config.py +77 -0
  144. glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
  145. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
  146. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
  147. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +95 -0
  148. glaip_sdk/runner/tool_adapter/__init__.py +18 -0
  149. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
  150. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +242 -0
  151. glaip_sdk/schedules/__init__.py +22 -0
  152. glaip_sdk/schedules/base.py +291 -0
  153. glaip_sdk/tools/__init__.py +22 -0
  154. glaip_sdk/tools/base.py +468 -0
  155. glaip_sdk/utils/__init__.py +59 -12
  156. glaip_sdk/utils/a2a/__init__.py +34 -0
  157. glaip_sdk/utils/a2a/event_processor.py +188 -0
  158. glaip_sdk/utils/agent_config.py +4 -14
  159. glaip_sdk/utils/bundler.py +403 -0
  160. glaip_sdk/utils/client.py +111 -0
  161. glaip_sdk/utils/client_utils.py +46 -28
  162. glaip_sdk/utils/datetime_helpers.py +58 -0
  163. glaip_sdk/utils/discovery.py +78 -0
  164. glaip_sdk/utils/display.py +25 -21
  165. glaip_sdk/utils/export.py +143 -0
  166. glaip_sdk/utils/general.py +1 -36
  167. glaip_sdk/utils/import_export.py +15 -16
  168. glaip_sdk/utils/import_resolver.py +524 -0
  169. glaip_sdk/utils/instructions.py +101 -0
  170. glaip_sdk/utils/rendering/__init__.py +115 -1
  171. glaip_sdk/utils/rendering/formatting.py +38 -23
  172. glaip_sdk/utils/rendering/layout/__init__.py +64 -0
  173. glaip_sdk/utils/rendering/{renderer → layout}/panels.py +10 -3
  174. glaip_sdk/utils/rendering/{renderer → layout}/progress.py +73 -12
  175. glaip_sdk/utils/rendering/layout/summary.py +74 -0
  176. glaip_sdk/utils/rendering/layout/transcript.py +606 -0
  177. glaip_sdk/utils/rendering/models.py +18 -8
  178. glaip_sdk/utils/rendering/renderer/__init__.py +9 -51
  179. glaip_sdk/utils/rendering/renderer/base.py +534 -882
  180. glaip_sdk/utils/rendering/renderer/config.py +4 -10
  181. glaip_sdk/utils/rendering/renderer/debug.py +30 -34
  182. glaip_sdk/utils/rendering/renderer/factory.py +138 -0
  183. glaip_sdk/utils/rendering/renderer/stream.py +13 -54
  184. glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
  185. glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
  186. glaip_sdk/utils/rendering/renderer/toggle.py +182 -0
  187. glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
  188. glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
  189. glaip_sdk/utils/rendering/state.py +204 -0
  190. glaip_sdk/utils/rendering/step_tree_state.py +100 -0
  191. glaip_sdk/utils/rendering/steps/__init__.py +34 -0
  192. glaip_sdk/utils/rendering/steps/event_processor.py +778 -0
  193. glaip_sdk/utils/rendering/steps/format.py +176 -0
  194. glaip_sdk/utils/rendering/{steps.py → steps/manager.py} +122 -26
  195. glaip_sdk/utils/rendering/timing.py +36 -0
  196. glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
  197. glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
  198. glaip_sdk/utils/resource_refs.py +29 -26
  199. glaip_sdk/utils/runtime_config.py +425 -0
  200. glaip_sdk/utils/serialization.py +32 -46
  201. glaip_sdk/utils/sync.py +162 -0
  202. glaip_sdk/utils/tool_detection.py +301 -0
  203. glaip_sdk/utils/tool_storage_provider.py +140 -0
  204. glaip_sdk/utils/validation.py +20 -28
  205. {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.7.7.dist-info}/METADATA +78 -23
  206. glaip_sdk-0.7.7.dist-info/RECORD +213 -0
  207. {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.7.7.dist-info}/WHEEL +2 -1
  208. glaip_sdk-0.7.7.dist-info/entry_points.txt +2 -0
  209. glaip_sdk-0.7.7.dist-info/top_level.txt +1 -0
  210. glaip_sdk/cli/commands/agents.py +0 -1412
  211. glaip_sdk/cli/commands/mcps.py +0 -1225
  212. glaip_sdk/cli/commands/tools.py +0 -597
  213. glaip_sdk/cli/utils.py +0 -1330
  214. glaip_sdk/models.py +0 -259
  215. glaip_sdk-0.0.20.dist-info/RECORD +0 -80
  216. 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)
@@ -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__()
@@ -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
- from glaip_sdk.payload_schemas.agent import (
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()