glaip-sdk 0.1.2__py3-none-any.whl → 0.7.17__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 (217) hide show
  1. glaip_sdk/__init__.py +44 -4
  2. glaip_sdk/_version.py +9 -0
  3. glaip_sdk/agents/__init__.py +27 -0
  4. glaip_sdk/agents/base.py +1413 -0
  5. glaip_sdk/branding.py +126 -2
  6. glaip_sdk/cli/account_store.py +555 -0
  7. glaip_sdk/cli/auth.py +260 -15
  8. glaip_sdk/cli/commands/__init__.py +2 -2
  9. glaip_sdk/cli/commands/accounts.py +746 -0
  10. glaip_sdk/cli/commands/agents/__init__.py +116 -0
  11. glaip_sdk/cli/commands/agents/_common.py +562 -0
  12. glaip_sdk/cli/commands/agents/create.py +155 -0
  13. glaip_sdk/cli/commands/agents/delete.py +64 -0
  14. glaip_sdk/cli/commands/agents/get.py +89 -0
  15. glaip_sdk/cli/commands/agents/list.py +129 -0
  16. glaip_sdk/cli/commands/agents/run.py +264 -0
  17. glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
  18. glaip_sdk/cli/commands/agents/update.py +112 -0
  19. glaip_sdk/cli/commands/common_config.py +104 -0
  20. glaip_sdk/cli/commands/configure.py +728 -113
  21. glaip_sdk/cli/commands/mcps/__init__.py +94 -0
  22. glaip_sdk/cli/commands/mcps/_common.py +459 -0
  23. glaip_sdk/cli/commands/mcps/connect.py +82 -0
  24. glaip_sdk/cli/commands/mcps/create.py +152 -0
  25. glaip_sdk/cli/commands/mcps/delete.py +73 -0
  26. glaip_sdk/cli/commands/mcps/get.py +212 -0
  27. glaip_sdk/cli/commands/mcps/list.py +69 -0
  28. glaip_sdk/cli/commands/mcps/tools.py +235 -0
  29. glaip_sdk/cli/commands/mcps/update.py +190 -0
  30. glaip_sdk/cli/commands/models.py +12 -8
  31. glaip_sdk/cli/commands/shared/__init__.py +21 -0
  32. glaip_sdk/cli/commands/shared/formatters.py +91 -0
  33. glaip_sdk/cli/commands/tools/__init__.py +69 -0
  34. glaip_sdk/cli/commands/tools/_common.py +80 -0
  35. glaip_sdk/cli/commands/tools/create.py +228 -0
  36. glaip_sdk/cli/commands/tools/delete.py +61 -0
  37. glaip_sdk/cli/commands/tools/get.py +103 -0
  38. glaip_sdk/cli/commands/tools/list.py +69 -0
  39. glaip_sdk/cli/commands/tools/script.py +49 -0
  40. glaip_sdk/cli/commands/tools/update.py +102 -0
  41. glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
  42. glaip_sdk/cli/commands/transcripts/_common.py +9 -0
  43. glaip_sdk/cli/commands/transcripts/clear.py +5 -0
  44. glaip_sdk/cli/commands/transcripts/detail.py +5 -0
  45. glaip_sdk/cli/commands/transcripts_original.py +756 -0
  46. glaip_sdk/cli/commands/update.py +163 -17
  47. glaip_sdk/cli/config.py +49 -4
  48. glaip_sdk/cli/constants.py +38 -0
  49. glaip_sdk/cli/context.py +8 -0
  50. glaip_sdk/cli/core/__init__.py +79 -0
  51. glaip_sdk/cli/core/context.py +124 -0
  52. glaip_sdk/cli/core/output.py +851 -0
  53. glaip_sdk/cli/core/prompting.py +649 -0
  54. glaip_sdk/cli/core/rendering.py +187 -0
  55. glaip_sdk/cli/display.py +41 -20
  56. glaip_sdk/cli/entrypoint.py +20 -0
  57. glaip_sdk/cli/hints.py +57 -0
  58. glaip_sdk/cli/io.py +6 -3
  59. glaip_sdk/cli/main.py +340 -143
  60. glaip_sdk/cli/masking.py +21 -33
  61. glaip_sdk/cli/pager.py +12 -13
  62. glaip_sdk/cli/parsers/__init__.py +1 -3
  63. glaip_sdk/cli/resolution.py +2 -1
  64. glaip_sdk/cli/slash/__init__.py +0 -9
  65. glaip_sdk/cli/slash/accounts_controller.py +580 -0
  66. glaip_sdk/cli/slash/accounts_shared.py +75 -0
  67. glaip_sdk/cli/slash/agent_session.py +62 -21
  68. glaip_sdk/cli/slash/prompt.py +21 -0
  69. glaip_sdk/cli/slash/remote_runs_controller.py +568 -0
  70. glaip_sdk/cli/slash/session.py +1105 -153
  71. glaip_sdk/cli/slash/tui/__init__.py +36 -0
  72. glaip_sdk/cli/slash/tui/accounts.tcss +177 -0
  73. glaip_sdk/cli/slash/tui/accounts_app.py +1853 -0
  74. glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
  75. glaip_sdk/cli/slash/tui/clipboard.py +195 -0
  76. glaip_sdk/cli/slash/tui/context.py +92 -0
  77. glaip_sdk/cli/slash/tui/indicators.py +341 -0
  78. glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
  79. glaip_sdk/cli/slash/tui/layouts/__init__.py +14 -0
  80. glaip_sdk/cli/slash/tui/layouts/harlequin.py +184 -0
  81. glaip_sdk/cli/slash/tui/loading.py +80 -0
  82. glaip_sdk/cli/slash/tui/remote_runs_app.py +760 -0
  83. glaip_sdk/cli/slash/tui/terminal.py +407 -0
  84. glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
  85. glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
  86. glaip_sdk/cli/slash/tui/theme/manager.py +112 -0
  87. glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
  88. glaip_sdk/cli/slash/tui/toast.py +388 -0
  89. glaip_sdk/cli/transcript/__init__.py +12 -52
  90. glaip_sdk/cli/transcript/cache.py +255 -44
  91. glaip_sdk/cli/transcript/capture.py +66 -1
  92. glaip_sdk/cli/transcript/history.py +815 -0
  93. glaip_sdk/cli/transcript/viewer.py +72 -463
  94. glaip_sdk/cli/tui_settings.py +125 -0
  95. glaip_sdk/cli/update_notifier.py +227 -10
  96. glaip_sdk/cli/validators.py +5 -6
  97. glaip_sdk/client/__init__.py +3 -1
  98. glaip_sdk/client/_schedule_payloads.py +89 -0
  99. glaip_sdk/client/agent_runs.py +147 -0
  100. glaip_sdk/client/agents.py +576 -44
  101. glaip_sdk/client/base.py +26 -0
  102. glaip_sdk/client/hitl.py +136 -0
  103. glaip_sdk/client/main.py +25 -14
  104. glaip_sdk/client/mcps.py +165 -24
  105. glaip_sdk/client/payloads/agent/__init__.py +23 -0
  106. glaip_sdk/client/{_agent_payloads.py → payloads/agent/requests.py} +63 -47
  107. glaip_sdk/client/payloads/agent/responses.py +43 -0
  108. glaip_sdk/client/run_rendering.py +546 -92
  109. glaip_sdk/client/schedules.py +439 -0
  110. glaip_sdk/client/shared.py +21 -0
  111. glaip_sdk/client/tools.py +206 -32
  112. glaip_sdk/config/constants.py +33 -2
  113. glaip_sdk/guardrails/__init__.py +80 -0
  114. glaip_sdk/guardrails/serializer.py +89 -0
  115. glaip_sdk/hitl/__init__.py +48 -0
  116. glaip_sdk/hitl/base.py +64 -0
  117. glaip_sdk/hitl/callback.py +43 -0
  118. glaip_sdk/hitl/local.py +121 -0
  119. glaip_sdk/hitl/remote.py +523 -0
  120. glaip_sdk/mcps/__init__.py +21 -0
  121. glaip_sdk/mcps/base.py +345 -0
  122. glaip_sdk/models/__init__.py +136 -0
  123. glaip_sdk/models/_provider_mappings.py +101 -0
  124. glaip_sdk/models/_validation.py +97 -0
  125. glaip_sdk/models/agent.py +48 -0
  126. glaip_sdk/models/agent_runs.py +117 -0
  127. glaip_sdk/models/common.py +42 -0
  128. glaip_sdk/models/constants.py +141 -0
  129. glaip_sdk/models/mcp.py +33 -0
  130. glaip_sdk/models/model.py +170 -0
  131. glaip_sdk/models/schedule.py +224 -0
  132. glaip_sdk/models/tool.py +33 -0
  133. glaip_sdk/payload_schemas/__init__.py +1 -13
  134. glaip_sdk/payload_schemas/agent.py +1 -0
  135. glaip_sdk/payload_schemas/guardrails.py +34 -0
  136. glaip_sdk/registry/__init__.py +55 -0
  137. glaip_sdk/registry/agent.py +164 -0
  138. glaip_sdk/registry/base.py +139 -0
  139. glaip_sdk/registry/mcp.py +253 -0
  140. glaip_sdk/registry/tool.py +445 -0
  141. glaip_sdk/rich_components.py +58 -2
  142. glaip_sdk/runner/__init__.py +76 -0
  143. glaip_sdk/runner/base.py +84 -0
  144. glaip_sdk/runner/deps.py +115 -0
  145. glaip_sdk/runner/langgraph.py +1055 -0
  146. glaip_sdk/runner/logging_config.py +77 -0
  147. glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
  148. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
  149. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
  150. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +116 -0
  151. glaip_sdk/runner/tool_adapter/__init__.py +18 -0
  152. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
  153. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +242 -0
  154. glaip_sdk/schedules/__init__.py +22 -0
  155. glaip_sdk/schedules/base.py +291 -0
  156. glaip_sdk/tools/__init__.py +22 -0
  157. glaip_sdk/tools/base.py +488 -0
  158. glaip_sdk/utils/__init__.py +59 -12
  159. glaip_sdk/utils/a2a/__init__.py +34 -0
  160. glaip_sdk/utils/a2a/event_processor.py +188 -0
  161. glaip_sdk/utils/agent_config.py +8 -2
  162. glaip_sdk/utils/bundler.py +403 -0
  163. glaip_sdk/utils/client.py +111 -0
  164. glaip_sdk/utils/client_utils.py +39 -7
  165. glaip_sdk/utils/datetime_helpers.py +58 -0
  166. glaip_sdk/utils/discovery.py +78 -0
  167. glaip_sdk/utils/display.py +23 -15
  168. glaip_sdk/utils/export.py +143 -0
  169. glaip_sdk/utils/general.py +0 -33
  170. glaip_sdk/utils/import_export.py +12 -7
  171. glaip_sdk/utils/import_resolver.py +524 -0
  172. glaip_sdk/utils/instructions.py +101 -0
  173. glaip_sdk/utils/rendering/__init__.py +115 -1
  174. glaip_sdk/utils/rendering/formatting.py +5 -30
  175. glaip_sdk/utils/rendering/layout/__init__.py +64 -0
  176. glaip_sdk/utils/rendering/{renderer → layout}/panels.py +9 -0
  177. glaip_sdk/utils/rendering/{renderer → layout}/progress.py +70 -1
  178. glaip_sdk/utils/rendering/layout/summary.py +74 -0
  179. glaip_sdk/utils/rendering/layout/transcript.py +606 -0
  180. glaip_sdk/utils/rendering/models.py +1 -0
  181. glaip_sdk/utils/rendering/renderer/__init__.py +9 -47
  182. glaip_sdk/utils/rendering/renderer/base.py +299 -1434
  183. glaip_sdk/utils/rendering/renderer/config.py +1 -5
  184. glaip_sdk/utils/rendering/renderer/debug.py +26 -20
  185. glaip_sdk/utils/rendering/renderer/factory.py +138 -0
  186. glaip_sdk/utils/rendering/renderer/stream.py +4 -33
  187. glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
  188. glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
  189. glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
  190. glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
  191. glaip_sdk/utils/rendering/state.py +204 -0
  192. glaip_sdk/utils/rendering/steps/__init__.py +34 -0
  193. glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +53 -440
  194. glaip_sdk/utils/rendering/steps/format.py +176 -0
  195. glaip_sdk/utils/rendering/steps/manager.py +387 -0
  196. glaip_sdk/utils/rendering/timing.py +36 -0
  197. glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
  198. glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
  199. glaip_sdk/utils/resource_refs.py +25 -13
  200. glaip_sdk/utils/runtime_config.py +426 -0
  201. glaip_sdk/utils/serialization.py +18 -0
  202. glaip_sdk/utils/sync.py +162 -0
  203. glaip_sdk/utils/tool_detection.py +301 -0
  204. glaip_sdk/utils/tool_storage_provider.py +140 -0
  205. glaip_sdk/utils/validation.py +16 -24
  206. {glaip_sdk-0.1.2.dist-info → glaip_sdk-0.7.17.dist-info}/METADATA +69 -23
  207. glaip_sdk-0.7.17.dist-info/RECORD +224 -0
  208. {glaip_sdk-0.1.2.dist-info → glaip_sdk-0.7.17.dist-info}/WHEEL +2 -1
  209. glaip_sdk-0.7.17.dist-info/entry_points.txt +2 -0
  210. glaip_sdk-0.7.17.dist-info/top_level.txt +1 -0
  211. glaip_sdk/cli/commands/agents.py +0 -1369
  212. glaip_sdk/cli/commands/mcps.py +0 -1187
  213. glaip_sdk/cli/commands/tools.py +0 -584
  214. glaip_sdk/cli/utils.py +0 -1278
  215. glaip_sdk/models.py +0 -240
  216. glaip_sdk-0.1.2.dist-info/RECORD +0 -82
  217. glaip_sdk-0.1.2.dist-info/entry_points.txt +0 -3
@@ -0,0 +1,439 @@
1
+ """Schedule client for AIP SDK.
2
+
3
+ Authors:
4
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
5
+ Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
6
+ """
7
+
8
+ from typing import TYPE_CHECKING, Any
9
+
10
+ from glaip_sdk.client._schedule_payloads import ScheduleListParams, normalize_schedule
11
+ from glaip_sdk.client.base import BaseClient
12
+ from glaip_sdk.exceptions import APIError, NotFoundError
13
+ from glaip_sdk.models.agent_runs import RunStatus
14
+ from glaip_sdk.models.schedule import (
15
+ ScheduleConfig,
16
+ ScheduleResponse,
17
+ ScheduleRunResponse,
18
+ ScheduleRunResult,
19
+ )
20
+ from glaip_sdk.schedules import (
21
+ Schedule,
22
+ ScheduleListResult,
23
+ ScheduleRun,
24
+ ScheduleRunListResult,
25
+ )
26
+
27
+ if TYPE_CHECKING:
28
+ from glaip_sdk.models import Agent
29
+
30
+
31
+ class ScheduleClient(BaseClient):
32
+ """Client for managing agent schedules.
33
+
34
+ Provides CRUD operations for scheduled agent executions.
35
+ Schedules allow agents to run automatically at specified times
36
+ using cron-like configurations.
37
+
38
+ Example:
39
+ >>> from glaip_sdk import Client
40
+ >>> from glaip_sdk.models.schedule import ScheduleConfig
41
+ >>>
42
+ >>> client = Client()
43
+ >>> # List all schedules
44
+ >>> result = client.schedules.list()
45
+ >>> for schedule in result:
46
+ ... print(f"{schedule.id}: {schedule.next_run_time}")
47
+ >>>
48
+ >>> # Get a specific schedule
49
+ >>> schedule = client.schedules.get("schedule-id")
50
+ >>>
51
+ >>> # Create a schedule for an agent
52
+ >>> schedule = client.schedules.create(
53
+ ... agent_id="agent-id",
54
+ ... input="Generate daily report",
55
+ ... schedule=ScheduleConfig(minute="0", hour="9", day_of_week="1-5")
56
+ ... )
57
+ >>>
58
+ >>> # Update a schedule
59
+ >>> schedule = client.schedules.update(
60
+ ... schedule_id="schedule-id",
61
+ ... input="Updated report input"
62
+ ... )
63
+ >>>
64
+ >>> # Delete a schedule
65
+ >>> client.schedules.delete("schedule-id")
66
+ """
67
+
68
+ def list(
69
+ self,
70
+ *,
71
+ limit: int | None = None,
72
+ page: int | None = None,
73
+ agent_id: str | None = None,
74
+ ) -> ScheduleListResult:
75
+ """List schedules with optional filtering and pagination.
76
+
77
+ Args:
78
+ limit: Maximum number of schedules to return (1-100)
79
+ page: Page number for pagination
80
+ agent_id: Filter schedules by agent ID
81
+
82
+ Returns:
83
+ ScheduleListResult containing schedules and pagination metadata
84
+ """
85
+ params = ScheduleListParams(limit=limit, page=page, agent_id=agent_id)
86
+
87
+ response = self._request_with_envelope(
88
+ "GET",
89
+ "/agents/schedules",
90
+ params=params.to_query_params(),
91
+ )
92
+
93
+ # Parse schedules from response data
94
+ schedules = [
95
+ Schedule.from_response(ScheduleResponse.model_validate(item), client=self)
96
+ for item in (response.get("data") or [])
97
+ ]
98
+
99
+ return ScheduleListResult(
100
+ items=schedules,
101
+ total=response.get("total"),
102
+ page=response.get("page"),
103
+ limit=response.get("limit"),
104
+ has_next=response.get("has_next"),
105
+ has_prev=response.get("has_prev"),
106
+ )
107
+
108
+ def get(self, schedule_id: str) -> Schedule:
109
+ """Get a schedule by ID.
110
+
111
+ Args:
112
+ schedule_id: The schedule ID to retrieve
113
+
114
+ Returns:
115
+ Schedule instance
116
+
117
+ Raises:
118
+ NotFoundError: If schedule is not found
119
+ AuthenticationError: If API key is invalid
120
+ APIError: If the API request fails
121
+ """
122
+ data = self._request("GET", f"/agents/schedules/{schedule_id}")
123
+
124
+ if data is None:
125
+ raise NotFoundError(f"Schedule not found: {schedule_id}")
126
+ return Schedule.from_response(ScheduleResponse.model_validate(data), client=self)
127
+
128
+ def create(
129
+ self,
130
+ *,
131
+ agent_id: str,
132
+ input: str,
133
+ schedule: ScheduleConfig | dict[str, str] | str,
134
+ ) -> Schedule:
135
+ """Create a new schedule for an agent.
136
+
137
+ Args:
138
+ agent_id: The agent ID to schedule
139
+ input: Input text for scheduled execution
140
+ schedule: Schedule configuration (ScheduleConfig, dict, or cron string)
141
+
142
+ Returns:
143
+ Created Schedule instance
144
+
145
+ Raises:
146
+ ValueError: If schedule format is invalid
147
+ NotFoundError: If agent is not found
148
+ ValidationError: If schedule configuration is invalid
149
+ AuthenticationError: If API key is invalid
150
+ APIError: If the API request fails
151
+ """
152
+ schedule_dict = normalize_schedule(schedule)
153
+ if schedule_dict is None:
154
+ raise ValueError("schedule is required")
155
+
156
+ payload = {
157
+ "input": input,
158
+ "schedule": schedule_dict,
159
+ }
160
+
161
+ response = self._request("POST", f"/agents/{agent_id}/schedule", json=payload)
162
+
163
+ # Response contains schedule_id, fetch the full schedule
164
+ schedule_id = response.get("schedule_id")
165
+ if not schedule_id:
166
+ raise APIError("Missing schedule_id in create response")
167
+
168
+ return self.get(schedule_id)
169
+
170
+ def update(
171
+ self,
172
+ schedule_id: str,
173
+ *,
174
+ input: str | None = None,
175
+ schedule: ScheduleConfig | dict[str, str] | str | None = None,
176
+ ) -> Schedule:
177
+ """Update an existing schedule.
178
+
179
+ Args:
180
+ schedule_id: The schedule ID to update
181
+ input: New input text for scheduled execution
182
+ schedule: New schedule configuration (ScheduleConfig, dict, or cron string)
183
+
184
+ Returns:
185
+ Updated Schedule instance
186
+
187
+ Raises:
188
+ NotFoundError: If schedule is not found
189
+ ValueError: If schedule config is required but not provided
190
+ ValidationError: If schedule configuration is invalid
191
+ AuthenticationError: If API key is invalid
192
+ APIError: If the API request fails
193
+
194
+ Note:
195
+ Updates use explicit replacement (not merge). The SDK normalizes partial
196
+ schedule dicts by filling missing cron fields with "*". This is intentional
197
+ for predictability - what you provide is what you get (plus wildcard defaults).
198
+ If the current schedule metadata is missing and no schedule parameter is
199
+ provided, a ValueError is raised.
200
+ """
201
+ # Get current schedule to merge with updates
202
+ current = self.get(schedule_id)
203
+
204
+ # Handle input - ensure we have valid input data
205
+ if current.input is None and input is None:
206
+ raise ValueError(
207
+ f"Schedule {schedule_id} has missing input metadata and no input parameter provided. "
208
+ "Please provide an input value to update this schedule."
209
+ )
210
+
211
+ # Handle schedule config - ensure we have complete schedule data
212
+ if current.schedule_config is None and schedule is None:
213
+ raise ValueError(
214
+ f"Schedule {schedule_id} has missing metadata and no schedule parameter provided. "
215
+ "Please provide a full schedule configuration to update this schedule."
216
+ )
217
+
218
+ current_input = current.input or ""
219
+ current_schedule = current.schedule_config.model_dump() if current.schedule_config else {}
220
+
221
+ payload: dict[str, Any] = {
222
+ "input": input if input is not None else current_input,
223
+ "schedule": normalize_schedule(schedule) or current_schedule,
224
+ }
225
+
226
+ data = self._request("PUT", f"/agents/schedules/{schedule_id}", json=payload)
227
+ return Schedule.from_response(ScheduleResponse.model_validate(data), client=self)
228
+
229
+ def delete(self, schedule_id: str) -> None:
230
+ """Delete a schedule.
231
+
232
+ Args:
233
+ schedule_id: The schedule ID to delete
234
+
235
+ Raises:
236
+ NotFoundError: If schedule is not found
237
+ AuthenticationError: If API key is invalid
238
+ APIError: If the API request fails
239
+ """
240
+ self._request("DELETE", f"/agents/schedules/{schedule_id}")
241
+
242
+ def list_runs(
243
+ self,
244
+ agent_id: str,
245
+ *,
246
+ schedule_id: str | None = None,
247
+ status: RunStatus | None = None,
248
+ limit: int | None = None,
249
+ page: int | None = None,
250
+ ) -> ScheduleRunListResult:
251
+ """List runs for an agent, optionally filtered by schedule ID.
252
+
253
+ Args:
254
+ agent_id: The agent ID to list runs for
255
+ schedule_id: Optional schedule ID to filter by
256
+ status: Optional status filter
257
+ limit: Maximum number of runs to return (1-100)
258
+ page: Page number for pagination
259
+
260
+ Returns:
261
+ ScheduleRunListResult containing runs and pagination metadata
262
+ """
263
+ params: dict[str, Any] = {"run_type": "schedule"}
264
+ if schedule_id is not None:
265
+ params["schedule_id"] = schedule_id
266
+ if status is not None:
267
+ params["status"] = status
268
+ if limit is not None:
269
+ params["limit"] = limit
270
+ if page is not None:
271
+ params["page"] = page
272
+
273
+ response = self._request_with_envelope(
274
+ "GET",
275
+ f"/agents/{agent_id}/runs",
276
+ params=params,
277
+ )
278
+
279
+ # Parse runs from response data
280
+ runs = [
281
+ ScheduleRun.from_response(ScheduleRunResponse.model_validate(item), client=self)
282
+ for item in (response.get("data") or [])
283
+ ]
284
+
285
+ return ScheduleRunListResult(
286
+ items=runs,
287
+ total=response.get("total"),
288
+ page=response.get("page"),
289
+ limit=response.get("limit"),
290
+ has_next=response.get("has_next"),
291
+ has_prev=response.get("has_prev"),
292
+ )
293
+
294
+ def get_run_result(self, agent_id: str, run_id: str) -> ScheduleRunResult:
295
+ """Get the full output payload for an agent run.
296
+
297
+ Args:
298
+ agent_id: The agent ID the run belongs to
299
+ run_id: The run ID to retrieve
300
+
301
+ Returns:
302
+ ScheduleRunResult containing run details and optional output
303
+ """
304
+ data = self._request("GET", f"/agents/{agent_id}/runs/{run_id}")
305
+ return ScheduleRunResult.model_validate(data)
306
+
307
+
308
+ class AgentScheduleManager:
309
+ """Facade for agent-scoped schedule operations.
310
+
311
+ Provides a convenient interface for managing schedules through
312
+ an Agent instance, automatically scoping operations to that agent.
313
+
314
+ Example:
315
+ >>> agent = client.get_agent_by_id("agent-id")
316
+ >>> # List schedules for this agent
317
+ >>> schedules = agent.schedule.list()
318
+ >>> # Create a schedule for this agent
319
+ >>> schedule = agent.schedule.create(
320
+ ... input="Daily task",
321
+ ... schedule="0 9 * * 1-5"
322
+ ... )
323
+ """
324
+
325
+ def __init__(self, agent: "Agent", client: ScheduleClient) -> None:
326
+ """Initialize the schedule manager.
327
+
328
+ Args:
329
+ agent: The agent to manage schedules for
330
+ client: The ScheduleClient for API operations
331
+ """
332
+ self._agent = agent
333
+ self._client = client
334
+
335
+ def list(
336
+ self,
337
+ *,
338
+ limit: int | None = None,
339
+ page: int | None = None,
340
+ ) -> ScheduleListResult:
341
+ """List schedules for this agent.
342
+
343
+ Args:
344
+ limit: Maximum number of schedules to return (1-100)
345
+ page: Page number for pagination
346
+
347
+ Returns:
348
+ ScheduleListResult containing schedules for this agent
349
+ """
350
+ return self._client.list(limit=limit, page=page, agent_id=self._agent.id)
351
+
352
+ def create(
353
+ self,
354
+ *,
355
+ input: str,
356
+ schedule: ScheduleConfig | dict[str, str] | str,
357
+ ) -> Schedule:
358
+ """Create a schedule for this agent.
359
+
360
+ Args:
361
+ input: Input text for scheduled execution
362
+ schedule: Schedule configuration (ScheduleConfig, dict, or cron string)
363
+
364
+ Returns:
365
+ Created Schedule instance
366
+ """
367
+ return self._client.create(
368
+ agent_id=self._agent.id,
369
+ input=input,
370
+ schedule=schedule,
371
+ )
372
+
373
+ def get(self, schedule_id: str) -> Schedule:
374
+ """Get a schedule by ID.
375
+
376
+ Args:
377
+ schedule_id: The schedule ID to retrieve
378
+
379
+ Returns:
380
+ Schedule instance
381
+
382
+ Raises:
383
+ NotFoundError: If schedule is not found
384
+ """
385
+ return self._client.get(schedule_id)
386
+
387
+ def update(
388
+ self,
389
+ schedule_id: str,
390
+ *,
391
+ input: str | None = None,
392
+ schedule: ScheduleConfig | dict[str, str] | str | None = None,
393
+ ) -> Schedule:
394
+ """Update a schedule.
395
+
396
+ Args:
397
+ schedule_id: The schedule ID to update
398
+ input: New input text for scheduled execution
399
+ schedule: New schedule configuration
400
+
401
+ Returns:
402
+ Updated Schedule instance
403
+ """
404
+ return self._client.update(schedule_id, input=input, schedule=schedule)
405
+
406
+ def delete(self, schedule_id: str) -> None:
407
+ """Delete a schedule.
408
+
409
+ Args:
410
+ schedule_id: The schedule ID to delete
411
+ """
412
+ self._client.delete(schedule_id)
413
+
414
+ def list_runs(
415
+ self,
416
+ schedule_id: str | None = None,
417
+ *,
418
+ status: RunStatus | None = None,
419
+ limit: int | None = None,
420
+ page: int | None = None,
421
+ ) -> ScheduleRunListResult:
422
+ """List runs for this agent.
423
+
424
+ Args:
425
+ schedule_id: Optional schedule ID to filter by
426
+ status: Optional status filter
427
+ limit: Maximum number of runs to return (1-100)
428
+ page: Page number for pagination
429
+
430
+ Returns:
431
+ ScheduleRunListResult containing runs for this agent
432
+ """
433
+ return self._client.list_runs(
434
+ self._agent.id,
435
+ schedule_id=schedule_id,
436
+ status=status,
437
+ limit=limit,
438
+ page=page,
439
+ )
@@ -0,0 +1,21 @@
1
+ """Shared helpers for client configuration wiring.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ from glaip_sdk.client.base import BaseClient
12
+
13
+
14
+ def build_shared_config(client: BaseClient) -> dict[str, Any]:
15
+ """Return the keyword arguments used to initialize sub-clients."""
16
+ return {
17
+ "parent_client": client,
18
+ "api_url": client.api_url,
19
+ "api_key": client.api_key,
20
+ "timeout": client._timeout,
21
+ }