glaip-sdk 0.6.22__py3-none-any.whl → 0.6.24__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/agents/base.py CHANGED
@@ -55,6 +55,7 @@ from glaip_sdk.registry import get_agent_registry, get_mcp_registry, get_tool_re
55
55
  from glaip_sdk.utils.resource_refs import is_uuid
56
56
 
57
57
  if TYPE_CHECKING:
58
+ from glaip_sdk.client.schedules import AgentScheduleManager
58
59
  from glaip_sdk.models import AgentResponse
59
60
  from glaip_sdk.registry import AgentRegistry, MCPRegistry, ToolRegistry
60
61
 
@@ -844,6 +845,36 @@ class Agent:
844
845
  self._client = client
845
846
  return self
846
847
 
848
+ @property
849
+ def schedule(self) -> AgentScheduleManager:
850
+ """Get the schedule manager for this agent.
851
+
852
+ Provides a convenient interface for managing schedules scoped to this agent.
853
+
854
+ Returns:
855
+ AgentScheduleManager for schedule operations
856
+
857
+ Raises:
858
+ ValueError: If agent is not deployed
859
+ RuntimeError: If agent is not bound to a client
860
+
861
+ Example:
862
+ >>> agent = client.get_agent_by_id("agent-id")
863
+ >>> schedules = agent.schedule.list()
864
+ >>> new_schedule = agent.schedule.create(
865
+ ... input="Daily task",
866
+ ... schedule="0 9 * * 1-5"
867
+ ... )
868
+ """
869
+ if not self.id:
870
+ raise ValueError(_AGENT_NOT_DEPLOYED_MSG)
871
+ if not self._client:
872
+ raise RuntimeError(_CLIENT_NOT_AVAILABLE_MSG)
873
+
874
+ from glaip_sdk.client.schedules import AgentScheduleManager # noqa: PLC0415
875
+
876
+ return AgentScheduleManager(self, self._client.schedules)
877
+
847
878
  def _prepare_run_kwargs(
848
879
  self,
849
880
  message: str,
@@ -7,5 +7,6 @@ Authors:
7
7
 
8
8
  from glaip_sdk.client.agent_runs import AgentRunsClient
9
9
  from glaip_sdk.client.main import Client
10
+ from glaip_sdk.client.schedules import AgentScheduleManager, ScheduleClient
10
11
 
11
- __all__ = ["AgentRunsClient", "Client"]
12
+ __all__ = ["AgentRunsClient", "AgentScheduleManager", "Client", "ScheduleClient"]
@@ -0,0 +1,89 @@
1
+ """Schedule request payload builders for AIP SDK.
2
+
3
+ Authors:
4
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+ from typing import Any
9
+
10
+ from glaip_sdk.models.schedule import ScheduleConfig
11
+
12
+
13
+ @dataclass
14
+ class ScheduleListParams:
15
+ """Parameters for listing schedules.
16
+
17
+ Args:
18
+ limit: Maximum number of schedules to return (1-100, default 50)
19
+ page: Page number for pagination (default 1)
20
+ agent_id: Filter schedules by agent ID
21
+ """
22
+
23
+ limit: int | None = None
24
+ page: int | None = None
25
+ agent_id: str | None = None
26
+
27
+ def to_query_params(self) -> dict[str, Any]:
28
+ """Convert to query parameters dictionary.
29
+
30
+ Returns:
31
+ Dictionary of non-None parameters for the API request
32
+ """
33
+ params: dict[str, Any] = {}
34
+ if self.limit is not None:
35
+ params["limit"] = self.limit
36
+ if self.page is not None:
37
+ params["page"] = self.page
38
+ if self.agent_id is not None:
39
+ params["agent_id"] = self.agent_id
40
+ return params
41
+
42
+
43
+ def normalize_schedule(
44
+ schedule: ScheduleConfig | dict[str, str] | str | None,
45
+ ) -> dict[str, str] | None:
46
+ """Normalize schedule input to a dictionary for API requests.
47
+
48
+ Accepts multiple input formats for user convenience:
49
+ - ScheduleConfig: Pydantic model with cron fields
50
+ - dict: Dictionary with cron fields (minute, hour, etc.)
51
+ - str: Cron string like "0 9 * * 1-5"
52
+ - None: Returns None
53
+
54
+ Args:
55
+ schedule: Schedule in various formats
56
+
57
+ Returns:
58
+ Dictionary suitable for API request or None
59
+
60
+ Raises:
61
+ ValueError: If cron string format is invalid
62
+ TypeError: If schedule is an unsupported type
63
+
64
+ Examples:
65
+ >>> normalize_schedule(ScheduleConfig(minute="0", hour="9"))
66
+ {'minute': '0', 'hour': '9', 'day_of_month': '*', 'month': '*', 'day_of_week': '*'}
67
+
68
+ >>> normalize_schedule({"minute": "0", "hour": "9"})
69
+ {'minute': '0', 'hour': '9', 'day_of_month': '*', 'month': '*', 'day_of_week': '*'}
70
+
71
+ >>> normalize_schedule("0 9 * * 1-5")
72
+ {'minute': '0', 'hour': '9', 'day_of_month': '*', 'month': '*', 'day_of_week': '1-5'}
73
+ """
74
+ if schedule is None:
75
+ return None
76
+
77
+ if isinstance(schedule, ScheduleConfig):
78
+ return schedule.model_dump()
79
+
80
+ if isinstance(schedule, dict):
81
+ # Validate and merge with defaults
82
+ return ScheduleConfig(**schedule).model_dump()
83
+
84
+ if isinstance(schedule, str):
85
+ # Parse cron string
86
+ config = ScheduleConfig.from_cron_string(schedule)
87
+ return config.model_dump()
88
+
89
+ raise TypeError(f"schedule must be ScheduleConfig, dict, or str, got {type(schedule).__name__}")
@@ -13,7 +13,10 @@ from collections.abc import AsyncGenerator, Callable, Iterator, Mapping
13
13
  from contextlib import asynccontextmanager
14
14
  from os import PathLike
15
15
  from pathlib import Path
16
- from typing import Any, BinaryIO
16
+ from typing import TYPE_CHECKING, Any, BinaryIO
17
+
18
+ if TYPE_CHECKING:
19
+ from glaip_sdk.client.schedules import ScheduleClient
17
20
 
18
21
  import httpx
19
22
  from glaip_sdk.agents import Agent
@@ -264,6 +267,7 @@ class AgentClient(BaseClient):
264
267
  self._tool_client: ToolClient | None = None
265
268
  self._mcp_client: MCPClient | None = None
266
269
  self._runs_client: AgentRunsClient | None = None
270
+ self._schedule_client: ScheduleClient | None = None
267
271
 
268
272
  def list_agents(
269
273
  self,
@@ -480,6 +484,20 @@ class AgentClient(BaseClient):
480
484
  self._mcp_client = MCPClient(parent_client=self)
481
485
  return self._mcp_client
482
486
 
487
+ @property
488
+ def schedules(self) -> "ScheduleClient":
489
+ """Get or create the schedule client instance.
490
+
491
+ Returns:
492
+ ScheduleClient instance.
493
+ """
494
+ if self._schedule_client is None:
495
+ # Import here to avoid circular import
496
+ from glaip_sdk.client.schedules import ScheduleClient # noqa: PLC0415
497
+
498
+ self._schedule_client = ScheduleClient(parent_client=self)
499
+ return self._schedule_client
500
+
483
501
  def _normalise_reference_entry(
484
502
  self,
485
503
  entry: Any,
glaip_sdk/client/main.py CHANGED
@@ -13,6 +13,7 @@ from typing import TYPE_CHECKING, Any
13
13
  from glaip_sdk.client.agents import AgentClient
14
14
  from glaip_sdk.client.base import BaseClient
15
15
  from glaip_sdk.client.mcps import MCPClient
16
+ from glaip_sdk.client.schedules import ScheduleClient
16
17
  from glaip_sdk.client.shared import build_shared_config
17
18
  from glaip_sdk.client.tools import ToolClient
18
19
 
@@ -38,6 +39,7 @@ class Client(BaseClient):
38
39
  self.agents = AgentClient(**shared_config)
39
40
  self.tools = ToolClient(**shared_config)
40
41
  self.mcps = MCPClient(**shared_config)
42
+ self.schedules = ScheduleClient(**shared_config)
41
43
 
42
44
  # ---- Core API Methods (Public Interface) ----
43
45
 
@@ -236,6 +238,8 @@ class Client(BaseClient):
236
238
  self.tools.http_client = self.http_client
237
239
  if hasattr(self, "mcps"):
238
240
  self.mcps.http_client = self.http_client
241
+ if hasattr(self, "schedules"):
242
+ self.schedules.http_client = self.http_client
239
243
  except Exception:
240
244
  pass
241
245
 
@@ -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
+ )
@@ -27,6 +27,16 @@ from glaip_sdk.models.agent_runs import (
27
27
  )
28
28
  from glaip_sdk.models.common import LanguageModelResponse, TTYRenderer
29
29
  from glaip_sdk.models.mcp import MCPResponse
30
+
31
+ # Export schedule models
32
+ from glaip_sdk.models.schedule import ( # noqa: F401
33
+ ScheduleConfig,
34
+ ScheduleMetadata,
35
+ ScheduleResponse,
36
+ ScheduleRunOutputChunk,
37
+ ScheduleRunResponse,
38
+ ScheduleRunResult,
39
+ )
30
40
  from glaip_sdk.models.tool import ToolResponse
31
41
 
32
42
 
@@ -87,4 +97,11 @@ __all__ = [
87
97
  "RunsPage",
88
98
  "RunWithOutput",
89
99
  "RunOutputChunk",
100
+ # Schedule models
101
+ "ScheduleConfig",
102
+ "ScheduleMetadata",
103
+ "ScheduleResponse",
104
+ "ScheduleRunResponse",
105
+ "ScheduleRunOutputChunk",
106
+ "ScheduleRunResult",
90
107
  ]
@@ -13,6 +13,7 @@ from pydantic import BaseModel, Field, field_validator, model_validator
13
13
 
14
14
  # Type alias for SSE event dictionaries
15
15
  RunOutputChunk = dict[str, Any]
16
+ RunStatus = Literal["started", "success", "failed", "cancelled", "aborted", "unavailable"]
16
17
 
17
18
 
18
19
  class RunSummary(BaseModel):
@@ -22,7 +23,7 @@ class RunSummary(BaseModel):
22
23
  agent_id: UUID
23
24
  run_type: Literal["manual", "schedule"]
24
25
  schedule_id: UUID | None = None
25
- status: Literal["started", "success", "failed", "cancelled", "aborted", "unavailable"]
26
+ status: RunStatus
26
27
  started_at: datetime
27
28
  completed_at: datetime | None = None
28
29
  input: str | 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,22 @@
1
+ """Schedules runtime package.
2
+
3
+ This package contains runtime schedule resource objects (class-based) that
4
+ encapsulate behavior and API interactions via attached clients.
5
+
6
+ Authors:
7
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
8
+ """
9
+
10
+ from glaip_sdk.schedules.base import (
11
+ Schedule,
12
+ ScheduleListResult,
13
+ ScheduleRun,
14
+ ScheduleRunListResult,
15
+ )
16
+
17
+ __all__ = [
18
+ "Schedule",
19
+ "ScheduleListResult",
20
+ "ScheduleRun",
21
+ "ScheduleRunListResult",
22
+ ]
@@ -0,0 +1,291 @@
1
+ """Schedule runtime resources.
2
+
3
+ This module contains class-based runtime resources for schedules.
4
+
5
+ The runtime resources:
6
+ - Are not Pydantic models.
7
+ - Are returned from public client APIs.
8
+ - Delegate API operations to a bound ScheduleClient.
9
+
10
+ Authors:
11
+ Christian Trisno Sen Long Chen (christian.t.s.l.chen@gdplabs.id)
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass, field
17
+ from datetime import datetime
18
+ from typing import TYPE_CHECKING
19
+
20
+ from glaip_sdk.models.agent_runs import RunStatus
21
+ from glaip_sdk.models.schedule import (
22
+ ScheduleConfig,
23
+ ScheduleMetadata,
24
+ ScheduleResponse,
25
+ ScheduleRunResponse,
26
+ ScheduleRunResult,
27
+ )
28
+
29
+ if TYPE_CHECKING: # pragma: no cover
30
+ from glaip_sdk.client.schedules import ScheduleClient
31
+
32
+ _SCHEDULE_CLIENT_REQUIRED_MSG = "No client available. Use client.schedules.get() to get a client-connected schedule."
33
+ _SCHEDULE_RUN_CLIENT_REQUIRED_MSG = (
34
+ "No client available. Use client.schedules.list_runs() to get a client-connected schedule run."
35
+ )
36
+
37
+
38
+ class Schedule:
39
+ """Runtime schedule resource.
40
+
41
+ Attributes:
42
+ id (str): The schedule ID.
43
+ next_run_time (str | None): Next run time as returned by the API.
44
+ time_until_next_run (str | None): Human readable duration until next run.
45
+ metadata (ScheduleMetadata | None): Schedule metadata.
46
+ created_at (datetime | None): Creation timestamp.
47
+ updated_at (datetime | None): Update timestamp.
48
+ """
49
+
50
+ def __init__(
51
+ self,
52
+ *,
53
+ id: str,
54
+ next_run_time: str | None = None,
55
+ time_until_next_run: str | None = None,
56
+ metadata: ScheduleMetadata | None = None,
57
+ created_at: datetime | None = None,
58
+ updated_at: datetime | None = None,
59
+ _client: ScheduleClient | None = None,
60
+ ) -> None:
61
+ """Initialize a runtime Schedule."""
62
+ self.id = id
63
+ self.next_run_time = next_run_time
64
+ self.time_until_next_run = time_until_next_run
65
+ self.metadata = metadata
66
+ self.created_at = created_at
67
+ self.updated_at = updated_at
68
+ self._client = _client
69
+
70
+ @classmethod
71
+ def from_response(cls, response: ScheduleResponse, *, client: ScheduleClient) -> Schedule:
72
+ """Build a runtime Schedule from a DTO response.
73
+
74
+ Args:
75
+ response: Parsed schedule response DTO.
76
+ client: ScheduleClient to bind.
77
+
78
+ Returns:
79
+ Runtime Schedule.
80
+ """
81
+ return cls(
82
+ id=response.id,
83
+ next_run_time=response.next_run_time,
84
+ time_until_next_run=response.time_until_next_run,
85
+ metadata=response.metadata,
86
+ created_at=response.created_at,
87
+ updated_at=response.updated_at,
88
+ _client=client,
89
+ )
90
+
91
+ @property
92
+ def agent_id(self) -> str | None:
93
+ """Agent ID derived from metadata."""
94
+ return self.metadata.agent_id if self.metadata else None
95
+
96
+ @property
97
+ def input(self) -> str | None:
98
+ """Input text derived from metadata."""
99
+ return self.metadata.input if self.metadata else None
100
+
101
+ @property
102
+ def schedule_config(self) -> ScheduleConfig | None:
103
+ """Schedule configuration derived from metadata."""
104
+ return self.metadata.schedule if self.metadata else None
105
+
106
+ def update(
107
+ self,
108
+ *,
109
+ input: str | None = None,
110
+ schedule: ScheduleConfig | dict[str, str] | str | None = None,
111
+ ) -> Schedule:
112
+ """Update this schedule."""
113
+ if self._client is None:
114
+ raise RuntimeError(_SCHEDULE_CLIENT_REQUIRED_MSG)
115
+ return self._client.update(self.id, input=input, schedule=schedule)
116
+
117
+ def delete(self) -> None:
118
+ """Delete this schedule."""
119
+ if self._client is None:
120
+ raise RuntimeError(_SCHEDULE_CLIENT_REQUIRED_MSG)
121
+ self._client.delete(self.id)
122
+
123
+ def list_runs(
124
+ self,
125
+ *,
126
+ status: RunStatus | None = None,
127
+ limit: int | None = None,
128
+ page: int | None = None,
129
+ ) -> ScheduleRunListResult:
130
+ """List runs for this schedule."""
131
+ if self._client is None:
132
+ raise RuntimeError(_SCHEDULE_CLIENT_REQUIRED_MSG)
133
+ if self.agent_id is None:
134
+ raise ValueError("Schedule has no agent_id")
135
+ return self._client.list_runs(
136
+ self.agent_id,
137
+ schedule_id=self.id,
138
+ status=status,
139
+ limit=limit,
140
+ page=page,
141
+ )
142
+
143
+ def __repr__(self) -> str:
144
+ """Return a developer-friendly representation."""
145
+ parts: list[str] = [f"id={self.id!r}"]
146
+ if self.agent_id is not None:
147
+ parts.append(f"agent_id={self.agent_id!r}")
148
+ if self.next_run_time is not None:
149
+ parts.append(f"next_run_time={self.next_run_time!r}")
150
+ if self.time_until_next_run is not None:
151
+ parts.append(f"time_until_next_run={self.time_until_next_run!r}")
152
+ if self.created_at is not None:
153
+ parts.append(f"created_at={self.created_at!r}")
154
+ return f"Schedule({', '.join(parts)})"
155
+
156
+ def __str__(self) -> str:
157
+ """Return a readable string representation."""
158
+ return self.__repr__()
159
+
160
+
161
+ class ScheduleRun:
162
+ """Runtime schedule run resource."""
163
+
164
+ def __init__(
165
+ self,
166
+ *,
167
+ id: str,
168
+ agent_id: str,
169
+ schedule_id: str | None = None,
170
+ status: RunStatus,
171
+ run_type: str | None = None,
172
+ started_at: datetime | None = None,
173
+ completed_at: datetime | None = None,
174
+ input: str | None = None,
175
+ config: ScheduleConfig | dict[str, str] | None = None,
176
+ created_at: datetime | None = None,
177
+ updated_at: datetime | None = None,
178
+ _client: ScheduleClient | None = None,
179
+ ) -> None:
180
+ """Initialize a runtime ScheduleRun."""
181
+ self.id = id
182
+ self.agent_id = agent_id
183
+ self.schedule_id = schedule_id
184
+ self.status = status
185
+ self.run_type = run_type
186
+ self.started_at = started_at
187
+ self.completed_at = completed_at
188
+ self.input = input
189
+ self.config = config
190
+ self.created_at = created_at
191
+ self.updated_at = updated_at
192
+ self._client = _client
193
+
194
+ @classmethod
195
+ def from_response(cls, response: ScheduleRunResponse, *, client: ScheduleClient) -> ScheduleRun:
196
+ """Build a runtime ScheduleRun from a DTO response."""
197
+ return cls(
198
+ id=response.id,
199
+ agent_id=response.agent_id,
200
+ schedule_id=response.schedule_id,
201
+ status=response.status,
202
+ run_type=response.run_type,
203
+ started_at=response.started_at,
204
+ completed_at=response.completed_at,
205
+ input=response.input,
206
+ config=response.config,
207
+ created_at=response.created_at,
208
+ updated_at=response.updated_at,
209
+ _client=client,
210
+ )
211
+
212
+ def get_result(self) -> ScheduleRunResult:
213
+ """Retrieve the full output payload for this run."""
214
+ if self._client is None:
215
+ raise RuntimeError(_SCHEDULE_RUN_CLIENT_REQUIRED_MSG)
216
+ if self.agent_id is None:
217
+ raise ValueError("Schedule run has no agent_id")
218
+ return self._client.get_run_result(self.agent_id, self.id)
219
+
220
+ @property
221
+ def duration(self) -> str | None:
222
+ """Formatted duration (HH:MM:SS) when both timestamps are available."""
223
+ if not self.started_at or not self.completed_at:
224
+ return None
225
+
226
+ total_seconds = int((self.completed_at - self.started_at).total_seconds())
227
+ minutes, seconds = divmod(total_seconds, 60)
228
+ hours, minutes = divmod(minutes, 60)
229
+ return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
230
+
231
+ def __repr__(self) -> str:
232
+ """Return a developer-friendly representation."""
233
+ parts: list[str] = [f"id={self.id!r}", f"status={self.status!r}"]
234
+ if self.started_at is not None:
235
+ parts.append(f"started_at={self.started_at.isoformat()!r}")
236
+ duration = self.duration
237
+ if duration is not None:
238
+ parts.append(f"duration={duration!r}")
239
+ return f"ScheduleRun({', '.join(parts)})"
240
+
241
+ def __str__(self) -> str:
242
+ """Return a readable string representation."""
243
+ return self.__repr__()
244
+
245
+
246
+ @dataclass
247
+ class ScheduleListResult:
248
+ """Paginated list wrapper for runtime schedules."""
249
+
250
+ items: list[Schedule]
251
+ total: int | None = field(default=None)
252
+ page: int | None = field(default=None)
253
+ limit: int | None = field(default=None)
254
+ has_next: bool | None = field(default=None)
255
+ has_prev: bool | None = field(default=None)
256
+
257
+ def __iter__(self):
258
+ """Iterate over schedules."""
259
+ yield from self.items
260
+
261
+ def __len__(self) -> int:
262
+ """Return the number of schedules in this page."""
263
+ return self.items.__len__()
264
+
265
+ def __getitem__(self, index: int) -> Schedule:
266
+ """Return the schedule at the given index."""
267
+ return self.items[index]
268
+
269
+
270
+ @dataclass
271
+ class ScheduleRunListResult:
272
+ """Paginated list wrapper for runtime schedule runs."""
273
+
274
+ items: list[ScheduleRun]
275
+ total: int | None = field(default=None)
276
+ page: int | None = field(default=None)
277
+ limit: int | None = field(default=None)
278
+ has_next: bool | None = field(default=None)
279
+ has_prev: bool | None = field(default=None)
280
+
281
+ def __iter__(self):
282
+ """Iterate over schedule runs."""
283
+ yield from self.items
284
+
285
+ def __len__(self) -> int:
286
+ """Return the number of runs in this page."""
287
+ return self.items.__len__()
288
+
289
+ def __getitem__(self, index: int) -> ScheduleRun:
290
+ """Return the run at the given index."""
291
+ return self.items[index]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: glaip-sdk
3
- Version: 0.6.22
3
+ Version: 0.6.24
4
4
  Summary: Python SDK and CLI for GL AIP (GDP Labs AI Agent Package) - Build, run, and manage AI agents
5
5
  Author-email: Raymond Christopher <raymond.christopher@gdplabs.id>
6
6
  License: MIT
@@ -20,12 +20,11 @@ Requires-Dist: gllm-core-binary>=0.1.0
20
20
  Requires-Dist: langchain-core>=0.3.0
21
21
  Requires-Dist: gllm-tools-binary>=0.1.3
22
22
  Provides-Extra: local
23
- Requires-Dist: aip-agents-binary[local]>=0.5.17; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
24
- Requires-Dist: gllm-docproc[docx,pdf,xlsx]<0.8.0,>=0.7.20; extra == "local"
23
+ Requires-Dist: aip-agents-binary[local]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
25
24
  Provides-Extra: memory
26
- Requires-Dist: aip-agents-binary[memory]>=0.5.17; (python_version >= "3.11" and python_version < "3.13") and extra == "memory"
25
+ Requires-Dist: aip-agents-binary[memory]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "memory"
27
26
  Provides-Extra: privacy
28
- Requires-Dist: aip-agents-binary[privacy]>=0.5.17; (python_version >= "3.11" and python_version < "3.13") and extra == "privacy"
27
+ Requires-Dist: aip-agents-binary[privacy]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "privacy"
29
28
  Provides-Extra: dev
30
29
  Requires-Dist: pytest>=7.0.0; extra == "dev"
31
30
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
@@ -5,7 +5,7 @@ glaip_sdk/exceptions.py,sha256=iAChFClkytXRBLP0vZq1_YjoZxA9i4m4bW1gDLiGR1g,2321
5
5
  glaip_sdk/icons.py,sha256=J5THz0ReAmDwIiIooh1_G3Le-mwTJyEjhJDdJ13KRxM,524
6
6
  glaip_sdk/rich_components.py,sha256=44Z0V1ZQleVh9gUDGwRR5mriiYFnVGOhm7fFxZYbP8c,4052
7
7
  glaip_sdk/agents/__init__.py,sha256=VfYov56edbWuySXFEbWJ_jLXgwnFzPk1KB-9-mfsUCc,776
8
- glaip_sdk/agents/base.py,sha256=_KfxI11vM3GaABN5o7hxD2f1Wv7nalCivC11J3wh0VM,42502
8
+ glaip_sdk/agents/base.py,sha256=D3Ll2l_uxv2kIwPCuDhfy_bbSxHrHPaxp6op2c7TBl0,43580
9
9
  glaip_sdk/cli/__init__.py,sha256=xCCfuF1Yc7mpCDcfhHZTX0vizvtrDSLeT8MJ3V7m5A0,156
10
10
  glaip_sdk/cli/account_store.py,sha256=TK4iTV93Q1uD9mCY_2ZMT6EazHKU2jX0qhgWfEM4V-4,18459
11
11
  glaip_sdk/cli/agent_config.py,sha256=YAbFKrTNTRqNA6b0i0Q3pH-01rhHDRi5v8dxSFwGSwM,2401
@@ -61,14 +61,16 @@ glaip_sdk/cli/transcript/export.py,sha256=reCvrZVzli8_LzYe5ZNdaa-MwZ1ov2RjnDzKZW
61
61
  glaip_sdk/cli/transcript/history.py,sha256=IAUaY41QCr9jKgQ1t8spDJiO3Me5r1vAoTX47QQu5z0,26217
62
62
  glaip_sdk/cli/transcript/launcher.py,sha256=z5ivkPXDQJpATIqtRLUK8jH3p3WIZ72PvOPqYRDMJvw,2327
63
63
  glaip_sdk/cli/transcript/viewer.py,sha256=Y4G40WR6v1g4TfxRbGSZqdrqhLcqBxoWkQgToQoGGxM,13198
64
- glaip_sdk/client/__init__.py,sha256=F-eE_dRSzA0cc1it06oi0tZetZBHmSUjWSHGhJMLCls,263
64
+ glaip_sdk/client/__init__.py,sha256=s2REOumgE8Z8lA9dWJpwXqpgMdzSELSuCQkZ7sYngX0,381
65
65
  glaip_sdk/client/_agent_payloads.py,sha256=cH7CvNRn0JvudwKLr072E7W2QGWO9r-4xDxWMvXoPKE,17865
66
+ glaip_sdk/client/_schedule_payloads.py,sha256=9BXa75CCx3clsKgwmG9AWyvhPY6kVwzQtoLvTTw40CQ,2759
66
67
  glaip_sdk/client/agent_runs.py,sha256=tZSFEZZ3Yx0uYRgnwkLe-X0TlmgKJQ-ivzb6SrVnxY8,4862
67
- glaip_sdk/client/agents.py,sha256=75uDLN85Smf67rw-jFhlVKyiToicAfcFyJHSvWJkAww,47631
68
+ glaip_sdk/client/agents.py,sha256=s1qhn48mTP-lqx5HXbxznE5v5ZtibytrJ2qeR0qJcP0,48250
68
69
  glaip_sdk/client/base.py,sha256=BhNaC2TJJ2jVWRTYmfxD3WjYgAyIuWNz9YURdNXXjJo,18245
69
- glaip_sdk/client/main.py,sha256=RTREAOgGouYm4lFKkpNBQ9dmxalnBsIpSSaQLWVFSmU,9054
70
+ glaip_sdk/client/main.py,sha256=wFJzPRagudeOBDWbANIuRKzZi4RsPcQaaggPfj6NL80,9270
70
71
  glaip_sdk/client/mcps.py,sha256=gFRuLOGeh6ieIhR4PeD6yNVT6NhvUMTqPq9iuu1vkAY,13019
71
72
  glaip_sdk/client/run_rendering.py,sha256=kERp78v50jojsNWHrjNEkbC8sgOpMacaqUdw5YZuK6A,26074
73
+ glaip_sdk/client/schedules.py,sha256=ZfPzCYzk4YRuPkjkTTgLe5Rqa07mi-h2WmP4H91mMZ0,14113
72
74
  glaip_sdk/client/shared.py,sha256=esHlsR0LEfL-pFDaWebQjKKOLl09jsRY-2pllBUn4nU,522
73
75
  glaip_sdk/client/tools.py,sha256=kK0rBwX1e_5AlGQRjlO6rNz6gDlohhXWdlxN9AwotdE,22585
74
76
  glaip_sdk/client/validators.py,sha256=ioF9VCs-LG2yLkaRDd7Hff74lojDZZ0_Q3CiLbdm1RY,8381
@@ -77,11 +79,12 @@ glaip_sdk/hitl/__init__.py,sha256=sg92Rpu8_vJIGi1ZEhx0-qWa1nGdvfrKyJAxtoDSKzo,49
77
79
  glaip_sdk/hitl/local.py,sha256=rzmaRK15BxgRX7cmklUcGQUotMYg8x2Gd9BWf39k6hw,5661
78
80
  glaip_sdk/mcps/__init__.py,sha256=4jYrt8K__oxrxexHRcmnRBXt-W_tbJN61H9Kf2lVh4Q,551
79
81
  glaip_sdk/mcps/base.py,sha256=jWwHjDF67_mtDGRp9p5SolANjVeB8jt1PSwPBtX876M,11654
80
- glaip_sdk/models/__init__.py,sha256=-qO4Yr1-fkyaYC9RcT3nYhplDjoXATrIFZr4JrqflHI,2577
82
+ glaip_sdk/models/__init__.py,sha256=Yfy5CKe9xt3MkyoRIiZ4PYy19LbEfv3GXi2PgqXW7iU,2973
81
83
  glaip_sdk/models/agent.py,sha256=vtmUSDrrib1hvm0xnofIuOebqlrs-gIaLsny8hzg1iE,1523
82
- glaip_sdk/models/agent_runs.py,sha256=MYgab07k8MfExjvI5_o6HxsksJZ3tl2TDZefVxzGc1g,3807
84
+ glaip_sdk/models/agent_runs.py,sha256=rK0fTpivukyiqIxrS86evgNtfEwV8Xecq_NeUakFUFw,3829
83
85
  glaip_sdk/models/common.py,sha256=O30MEGO2nKcGhKbnPNkoGzwNvDVUBjM-uU-Tpigaz5Y,1180
84
86
  glaip_sdk/models/mcp.py,sha256=ti_8MUf4k7qbR1gPs9JhqhybMcLUhZxEELtHQrTv2-U,944
87
+ glaip_sdk/models/schedule.py,sha256=gfL_b9abaWToMtnCD_iXOsmonQ1sq2dZoLcInvCzZ2o,7248
85
88
  glaip_sdk/models/tool.py,sha256=w3nL2DqyCtGgDPCd40Asi9obRGghQjLlC9Vt_p32Mpc,951
86
89
  glaip_sdk/payload_schemas/__init__.py,sha256=nTJmzwn2BbEpzZdq-8U24eVHQHxqYO3_-SABMV9lS_Q,142
87
90
  glaip_sdk/payload_schemas/agent.py,sha256=Nap68mI2Ba8eNGOhk79mGrYUoYUahcUJLof3DLWtVO4,3198
@@ -101,6 +104,8 @@ glaip_sdk/runner/mcp_adapter/mcp_config_builder.py,sha256=fQcRaueDuyUzXUSVn9N8Qx
101
104
  glaip_sdk/runner/tool_adapter/__init__.py,sha256=scv8sSPxSWjlSNEace03R230YbmWgphLgqINKvDjWmM,480
102
105
  glaip_sdk/runner/tool_adapter/base_tool_adapter.py,sha256=nL--eicV0St5_0PZZSEhRurHDZHNwhGN2cKOUh0C5IY,1400
103
106
  glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py,sha256=goSSDOpubuplsKpfemlbesf_bZBdpDKSTqLILvApcjA,7438
107
+ glaip_sdk/schedules/__init__.py,sha256=Ty__lE8ta3a6O7EiEsSXliVOwA3EBLKxKRsjAJt2WUg,482
108
+ glaip_sdk/schedules/base.py,sha256=ZRKWknoxQOYMhX8mjQ7S7oqpy6Wr0xdbzcgIrycsEQ8,9727
104
109
  glaip_sdk/tools/__init__.py,sha256=rhGzEqQFCzeMrxmikBuNrMz4PyYczwic28boDKVmoHs,585
105
110
  glaip_sdk/tools/base.py,sha256=bvumLJ-DiQTmuYKgq2yCnlwrTZ9nYXpOwWU0e1vWR5g,15185
106
111
  glaip_sdk/utils/__init__.py,sha256=ntohV7cxlY2Yksi2nFuFm_Mg2XVJbBbSJVRej7Mi9YE,2770
@@ -155,8 +160,8 @@ glaip_sdk/utils/rendering/steps/format.py,sha256=Chnq7OBaj8XMeBntSBxrX5zSmrYeGcO
155
160
  glaip_sdk/utils/rendering/steps/manager.py,sha256=BiBmTeQMQhjRMykgICXsXNYh1hGsss-fH9BIGVMWFi0,13194
156
161
  glaip_sdk/utils/rendering/viewer/__init__.py,sha256=XrxmE2cMAozqrzo1jtDFm8HqNtvDcYi2mAhXLXn5CjI,457
157
162
  glaip_sdk/utils/rendering/viewer/presenter.py,sha256=mlLMTjnyeyPVtsyrAbz1BJu9lFGQSlS-voZ-_Cuugv0,5725
158
- glaip_sdk-0.6.22.dist-info/METADATA,sha256=f0VCtMfGVoaWe3bA4KVUN3AmPZk0AFZtyw3GsOLA4ug,8375
159
- glaip_sdk-0.6.22.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
160
- glaip_sdk-0.6.22.dist-info/entry_points.txt,sha256=65vNPUggyYnVGhuw7RhNJ8Fp2jygTcX0yxJBcBY3iLU,48
161
- glaip_sdk-0.6.22.dist-info/top_level.txt,sha256=td7yXttiYX2s94-4wFhv-5KdT0rSZ-pnJRSire341hw,10
162
- glaip_sdk-0.6.22.dist-info/RECORD,,
163
+ glaip_sdk-0.6.24.dist-info/METADATA,sha256=mZ9OCm5VvtAtoEpJ7ATbyggUegM709JmEHVL1QjQAPc,8299
164
+ glaip_sdk-0.6.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
165
+ glaip_sdk-0.6.24.dist-info/entry_points.txt,sha256=65vNPUggyYnVGhuw7RhNJ8Fp2jygTcX0yxJBcBY3iLU,48
166
+ glaip_sdk-0.6.24.dist-info/top_level.txt,sha256=td7yXttiYX2s94-4wFhv-5KdT0rSZ-pnJRSire341hw,10
167
+ glaip_sdk-0.6.24.dist-info/RECORD,,