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
@@ -1,11 +1,15 @@
1
- #!/usr/bin/env python3
2
- """Shared helpers for Agent client payload construction and query handling."""
1
+ """Agent request payload types and helpers.
3
2
 
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ # pylint: disable=duplicate-code
4
8
  from __future__ import annotations
5
9
 
6
10
  from collections.abc import Callable, Mapping, MutableMapping, Sequence
7
11
  from copy import deepcopy
8
- from dataclasses import dataclass, field
12
+ from dataclasses import dataclass
9
13
  from typing import Any
10
14
 
11
15
  from glaip_sdk.config.constants import (
@@ -13,12 +17,9 @@ from glaip_sdk.config.constants import (
13
17
  DEFAULT_AGENT_PROVIDER,
14
18
  DEFAULT_AGENT_TYPE,
15
19
  DEFAULT_AGENT_VERSION,
16
- DEFAULT_MODEL,
17
- )
18
- from glaip_sdk.payload_schemas.agent import (
19
- AgentImportOperation,
20
- get_import_field_plan,
21
20
  )
21
+ from glaip_sdk.models.constants import DEFAULT_MODEL
22
+ from glaip_sdk.payload_schemas.agent import AgentImportOperation, get_import_field_plan
22
23
  from glaip_sdk.utils.client_utils import extract_ids
23
24
 
24
25
  _LM_CONFLICT_KEYS = {
@@ -99,6 +100,11 @@ def resolve_language_model_fields(
99
100
  resolved_model = model_name or model or default_model
100
101
  resolved_provider = provider if provider is not None else default_provider
101
102
 
103
+ if resolved_model and isinstance(resolved_model, str) and "/" in resolved_model:
104
+ parts = resolved_model.split("/", 1)
105
+ resolved_provider = parts[0]
106
+ resolved_model = parts[1]
107
+
102
108
  result: dict[str, Any] = {}
103
109
  if resolved_model is not None:
104
110
  result["model_name"] = resolved_model
@@ -209,6 +215,11 @@ class AgentListParams:
209
215
  return params
210
216
 
211
217
  def _base_filter_params(self) -> dict[str, Any]:
218
+ """Build base filter parameters from non-None fields.
219
+
220
+ Returns:
221
+ Dictionary of filter parameters with non-None values.
222
+ """
212
223
  return {
213
224
  key: value
214
225
  for key, value in (
@@ -221,6 +232,11 @@ class AgentListParams:
221
232
  }
222
233
 
223
234
  def _apply_pagination_params(self, params: dict[str, Any]) -> None:
235
+ """Apply pagination parameters to the params dictionary.
236
+
237
+ Args:
238
+ params: Dictionary to update with pagination parameters.
239
+ """
224
240
  if self.limit is not None:
225
241
  if not 1 <= self.limit <= 100:
226
242
  raise ValueError("limit must be between 1 and 100 inclusive")
@@ -238,6 +254,11 @@ class AgentListParams:
238
254
  params["sync_langflow_agents"] = str(self.sync_langflow_agents).lower()
239
255
 
240
256
  def _apply_timestamp_filters(self, params: dict[str, Any]) -> None:
257
+ """Apply timestamp filter parameters to the params dictionary.
258
+
259
+ Args:
260
+ params: Dictionary to update with timestamp filter parameters.
261
+ """
241
262
  timestamp_filters = {
242
263
  "created_at_start": self.created_at_start,
243
264
  "created_at_end": self.created_at_end,
@@ -249,6 +270,11 @@ class AgentListParams:
249
270
  params[key] = value
250
271
 
251
272
  def _apply_metadata_filters(self, params: dict[str, Any]) -> None:
273
+ """Apply metadata filter parameters to the params dictionary.
274
+
275
+ Args:
276
+ params: Dictionary to update with metadata filter parameters.
277
+ """
252
278
  if not self.metadata:
253
279
  return
254
280
  for key, value in self.metadata.items():
@@ -256,28 +282,6 @@ class AgentListParams:
256
282
  params[f"metadata.{key}"] = value
257
283
 
258
284
 
259
- @dataclass(slots=True)
260
- class AgentListResult:
261
- """Structured response for list_agents that retains pagination metadata."""
262
-
263
- items: list[Any] = field(default_factory=list)
264
- total: int | None = None
265
- page: int | None = None
266
- limit: int | None = None
267
- has_next: bool | None = None
268
- has_prev: bool | None = None
269
- message: str | None = None
270
-
271
- def __len__(self) -> int: # pragma: no cover - simple delegation
272
- return len(self.items)
273
-
274
- def __iter__(self): # pragma: no cover - simple delegation
275
- return iter(self.items)
276
-
277
- def __getitem__(self, index: int) -> Any: # pragma: no cover - simple delegation
278
- return self.items[index]
279
-
280
-
281
285
  @dataclass(slots=True)
282
286
  class AgentCreateRequest:
283
287
  """Declarative representation of an agent creation payload."""
@@ -395,41 +399,51 @@ class AgentUpdateRequest:
395
399
  return payload
396
400
 
397
401
 
398
- __all__ = [
399
- "AgentCreateRequest",
400
- "AgentListParams",
401
- "AgentListResult",
402
- "AgentUpdateRequest",
403
- "merge_payload_fields",
404
- "resolve_language_model_fields",
405
- ]
406
-
407
-
408
402
  def _build_base_update_payload(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
403
+ """Populate immutable agent update fields using request data or existing agent defaults."""
404
+ # Support both "agent_type" (runtime class) and "type" (API response) attributes
405
+ current_type = getattr(current_agent, "agent_type", None) or getattr(current_agent, "type", None)
409
406
  return {
410
- "name": request.name.strip() if request.name is not None else getattr(current_agent, "name", None),
411
- "instruction": request.instruction.strip()
412
- if request.instruction is not None
413
- else getattr(current_agent, "instruction", None),
414
- "type": request.agent_type or getattr(current_agent, "type", None) or DEFAULT_AGENT_TYPE,
407
+ "name": (request.name.strip() if request.name is not None else getattr(current_agent, "name", None)),
408
+ "instruction": (
409
+ request.instruction.strip()
410
+ if request.instruction is not None
411
+ else getattr(current_agent, "instruction", None)
412
+ ),
413
+ "type": request.agent_type or current_type or DEFAULT_AGENT_TYPE,
415
414
  "framework": request.framework or getattr(current_agent, "framework", None) or DEFAULT_AGENT_FRAMEWORK,
416
415
  "version": request.version or getattr(current_agent, "version", None) or DEFAULT_AGENT_VERSION,
417
416
  }
418
417
 
419
418
 
420
419
  def _resolve_update_language_model_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
420
+ """Resolve the language-model portion of an update request with sensible fallbacks."""
421
+ # Check if any LM inputs were provided
422
+ has_lm_inputs = any(
423
+ [
424
+ request.model is not None,
425
+ request.language_model_id is not None,
426
+ request.provider is not None,
427
+ request.model_name is not None,
428
+ ]
429
+ )
430
+
431
+ if not has_lm_inputs:
432
+ # No LM inputs provided - preserve existing fields
433
+ return _existing_language_model_fields(current_agent)
434
+
435
+ # LM inputs provided - resolve them (may return defaults if only partial info)
421
436
  fields = resolve_language_model_fields(
422
437
  model=request.model,
423
438
  language_model_id=request.language_model_id,
424
439
  provider=request.provider,
425
440
  model_name=request.model_name,
426
441
  )
427
- if not fields:
428
- fields = _existing_language_model_fields(current_agent)
429
442
  return fields
430
443
 
431
444
 
432
445
  def _collect_optional_update_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
446
+ """Collect optional agent fields, preserving current values when updates are absent."""
433
447
  result: dict[str, Any] = {}
434
448
 
435
449
  for field_name, value in (
@@ -468,6 +482,7 @@ def _collect_optional_update_fields(request: AgentUpdateRequest, current_agent:
468
482
 
469
483
 
470
484
  def _collect_relationship_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
485
+ """Return relationship identifiers (tools/agents/mcps) for an update request."""
471
486
  return {
472
487
  "tools": _resolve_relation_ids(request.tools, current_agent, "tools"),
473
488
  "agents": _resolve_relation_ids(request.agents, current_agent, "agents"),
@@ -476,6 +491,7 @@ def _collect_relationship_fields(request: AgentUpdateRequest, current_agent: Any
476
491
 
477
492
 
478
493
  def _resolve_agent_config_update(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any] | None:
494
+ """Determine the agent_config payload to send, if any."""
479
495
  effective_agent_config = _sanitize_agent_config(request.agent_config)
480
496
  if effective_agent_config is not None:
481
497
  return effective_agent_config
@@ -0,0 +1,43 @@
1
+ """Agent response payload types.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ # pylint: disable=duplicate-code
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+ from typing import Any
12
+
13
+
14
+ @dataclass(slots=True)
15
+ class AgentListResult:
16
+ """Structured response for list_agents that retains pagination metadata."""
17
+
18
+ items: list[Any] = field(default_factory=list)
19
+ total: int | None = None
20
+ page: int | None = None
21
+ limit: int | None = None
22
+ has_next: bool | None = None
23
+ has_prev: bool | None = None
24
+ message: str | None = None
25
+
26
+ def __len__(self) -> int: # pragma: no cover - simple delegation
27
+ """Return the number of items in the result list."""
28
+ return len(self.items)
29
+
30
+ def __iter__(self): # pragma: no cover - simple delegation
31
+ """Return an iterator over the items in the result list."""
32
+ return iter(self.items)
33
+
34
+ def __getitem__(self, index: int) -> Any: # pragma: no cover - simple delegation
35
+ """Get an item from the result list by index.
36
+
37
+ Args:
38
+ index: Index of the item to retrieve.
39
+
40
+ Returns:
41
+ The item at the specified index.
42
+ """
43
+ return self.items[index]