pygeai 0.1.6__py3-none-any.whl → 0.6.0b15__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.

Potentially problematic release.


This version of pygeai might be problematic. Click here for more details.

Files changed (788) hide show
  1. pygeai/__init__.py +11 -2
  2. pygeai/_docs/Makefile +20 -0
  3. pygeai/_docs/make.bat +35 -0
  4. pygeai/_docs/source/conf.py +117 -0
  5. pygeai/_docs/source/content/ai_lab/cli.rst +747 -0
  6. pygeai/_docs/source/content/ai_lab/models.rst +1734 -0
  7. pygeai/_docs/source/content/ai_lab/runner.rst +253 -0
  8. pygeai/_docs/source/content/ai_lab/spec.rst +431 -0
  9. pygeai/_docs/source/content/ai_lab/usage.rst +1011 -0
  10. pygeai/_docs/source/content/ai_lab.rst +102 -0
  11. pygeai/_docs/source/content/analytics.rst +598 -0
  12. pygeai/_docs/source/content/api_reference/admin.rst +161 -0
  13. pygeai/_docs/source/content/api_reference/assistant.rst +326 -0
  14. pygeai/_docs/source/content/api_reference/auth.rst +379 -0
  15. pygeai/_docs/source/content/api_reference/chat.rst +754 -0
  16. pygeai/_docs/source/content/api_reference/embeddings.rst +154 -0
  17. pygeai/_docs/source/content/api_reference/evaluation.rst +590 -0
  18. pygeai/_docs/source/content/api_reference/feedback.rst +237 -0
  19. pygeai/_docs/source/content/api_reference/files.rst +592 -0
  20. pygeai/_docs/source/content/api_reference/gam.rst +401 -0
  21. pygeai/_docs/source/content/api_reference/health.rst +58 -0
  22. pygeai/_docs/source/content/api_reference/project.rst +738 -0
  23. pygeai/_docs/source/content/api_reference/proxy.rst +318 -0
  24. pygeai/_docs/source/content/api_reference/rag.rst +710 -0
  25. pygeai/_docs/source/content/api_reference/rerank.rst +94 -0
  26. pygeai/_docs/source/content/api_reference/secrets.rst +495 -0
  27. pygeai/_docs/source/content/api_reference/usage_limits.rst +390 -0
  28. pygeai/_docs/source/content/api_reference.rst +58 -0
  29. pygeai/_docs/source/content/authentication.rst +295 -0
  30. pygeai/_docs/source/content/chat_gui.rst +121 -0
  31. pygeai/_docs/source/content/cli.rst +203 -0
  32. pygeai/_docs/source/content/debugger.rst +651 -0
  33. pygeai/_docs/source/content/intro.rst +67 -0
  34. pygeai/_docs/source/content/migration.rst +929 -0
  35. pygeai/_docs/source/content/modules.rst +7 -0
  36. pygeai/_docs/source/content/quickstart.rst +143 -0
  37. pygeai/_docs/source/content/samples.rst +394 -0
  38. pygeai/_docs/source/index.rst +75 -0
  39. pygeai/_docs/source/modules.rst +7 -0
  40. pygeai/_docs/source/pygeai.admin.rst +29 -0
  41. pygeai/_docs/source/pygeai.analytics.rst +53 -0
  42. pygeai/_docs/source/pygeai.assistant.data.rst +21 -0
  43. pygeai/_docs/source/pygeai.assistant.data_analyst.rst +29 -0
  44. pygeai/_docs/source/pygeai.assistant.rag.rst +53 -0
  45. pygeai/_docs/source/pygeai.assistant.rst +55 -0
  46. pygeai/_docs/source/pygeai.auth.rst +29 -0
  47. pygeai/_docs/source/pygeai.chat.rst +69 -0
  48. pygeai/_docs/source/pygeai.cli.commands.flows.rst +10 -0
  49. pygeai/_docs/source/pygeai.cli.commands.lab.rst +53 -0
  50. pygeai/_docs/source/pygeai.cli.commands.rst +222 -0
  51. pygeai/_docs/source/pygeai.cli.rst +62 -0
  52. pygeai/_docs/source/pygeai.cli.texts.rst +21 -0
  53. pygeai/_docs/source/pygeai.core.base.rst +53 -0
  54. pygeai/_docs/source/pygeai.core.common.rst +37 -0
  55. pygeai/_docs/source/pygeai.core.embeddings.rst +61 -0
  56. pygeai/_docs/source/pygeai.core.feedback.rst +37 -0
  57. pygeai/_docs/source/pygeai.core.files.rst +61 -0
  58. pygeai/_docs/source/pygeai.core.llm.rst +29 -0
  59. pygeai/_docs/source/pygeai.core.plugins.rst +37 -0
  60. pygeai/_docs/source/pygeai.core.rerank.rst +53 -0
  61. pygeai/_docs/source/pygeai.core.rst +63 -0
  62. pygeai/_docs/source/pygeai.core.secrets.rst +29 -0
  63. pygeai/_docs/source/pygeai.core.services.llm.rst +29 -0
  64. pygeai/_docs/source/pygeai.core.services.rst +37 -0
  65. pygeai/_docs/source/pygeai.core.utils.rst +37 -0
  66. pygeai/_docs/source/pygeai.dbg.rst +21 -0
  67. pygeai/_docs/source/pygeai.evaluation.dataset.rst +29 -0
  68. pygeai/_docs/source/pygeai.evaluation.plan.rst +29 -0
  69. pygeai/_docs/source/pygeai.evaluation.result.rst +29 -0
  70. pygeai/_docs/source/pygeai.evaluation.rst +31 -0
  71. pygeai/_docs/source/pygeai.flows.rst +29 -0
  72. pygeai/_docs/source/pygeai.gam.rst +29 -0
  73. pygeai/_docs/source/pygeai.health.rst +29 -0
  74. pygeai/_docs/source/pygeai.lab.agents.rst +37 -0
  75. pygeai/_docs/source/pygeai.lab.processes.rst +37 -0
  76. pygeai/_docs/source/pygeai.lab.rst +65 -0
  77. pygeai/_docs/source/pygeai.lab.spec.rst +29 -0
  78. pygeai/_docs/source/pygeai.lab.strategies.rst +37 -0
  79. pygeai/_docs/source/pygeai.lab.tools.rst +37 -0
  80. pygeai/_docs/source/pygeai.man.man1.rst +10 -0
  81. pygeai/_docs/source/pygeai.man.rst +18 -0
  82. pygeai/_docs/source/pygeai.migration.rst +29 -0
  83. pygeai/_docs/source/pygeai.organization.limits.rst +45 -0
  84. pygeai/_docs/source/pygeai.organization.rst +61 -0
  85. pygeai/_docs/source/pygeai.proxy.rst +53 -0
  86. pygeai/_docs/source/pygeai.rst +35 -0
  87. pygeai/_docs/source/pygeai.tests.admin.rst +21 -0
  88. pygeai/_docs/source/pygeai.tests.analytics.rst +45 -0
  89. pygeai/_docs/source/pygeai.tests.assistants.rag.rst +37 -0
  90. pygeai/_docs/source/pygeai.tests.assistants.rst +45 -0
  91. pygeai/_docs/source/pygeai.tests.auth.rst +29 -0
  92. pygeai/_docs/source/pygeai.tests.chat.rst +45 -0
  93. pygeai/_docs/source/pygeai.tests.cli.commands.lab.rst +37 -0
  94. pygeai/_docs/source/pygeai.tests.cli.commands.rst +165 -0
  95. pygeai/_docs/source/pygeai.tests.cli.docker.rst +10 -0
  96. pygeai/_docs/source/pygeai.tests.cli.rst +46 -0
  97. pygeai/_docs/source/pygeai.tests.core.base.data.rst +29 -0
  98. pygeai/_docs/source/pygeai.tests.core.base.rst +45 -0
  99. pygeai/_docs/source/pygeai.tests.core.common.data.rst +10 -0
  100. pygeai/_docs/source/pygeai.tests.core.common.rst +37 -0
  101. pygeai/_docs/source/pygeai.tests.core.embeddings.rst +37 -0
  102. pygeai/_docs/source/pygeai.tests.core.feedback.rst +21 -0
  103. pygeai/_docs/source/pygeai.tests.core.files.rst +53 -0
  104. pygeai/_docs/source/pygeai.tests.core.llm.rst +21 -0
  105. pygeai/_docs/source/pygeai.tests.core.plugins.rst +21 -0
  106. pygeai/_docs/source/pygeai.tests.core.rerank.rst +37 -0
  107. pygeai/_docs/source/pygeai.tests.core.rst +39 -0
  108. pygeai/_docs/source/pygeai.tests.core.secrets.rst +21 -0
  109. pygeai/_docs/source/pygeai.tests.core.services.rst +21 -0
  110. pygeai/_docs/source/pygeai.tests.core.utils.rst +21 -0
  111. pygeai/_docs/source/pygeai.tests.dbg.rst +21 -0
  112. pygeai/_docs/source/pygeai.tests.evaluation.dataset.rst +21 -0
  113. pygeai/_docs/source/pygeai.tests.evaluation.plan.rst +21 -0
  114. pygeai/_docs/source/pygeai.tests.evaluation.result.rst +21 -0
  115. pygeai/_docs/source/pygeai.tests.evaluation.rst +20 -0
  116. pygeai/_docs/source/pygeai.tests.gam.rst +21 -0
  117. pygeai/_docs/source/pygeai.tests.health.rst +21 -0
  118. pygeai/_docs/source/pygeai.tests.integration.assistants.rag.rst +21 -0
  119. pygeai/_docs/source/pygeai.tests.integration.assistants.rst +18 -0
  120. pygeai/_docs/source/pygeai.tests.integration.chat.rst +21 -0
  121. pygeai/_docs/source/pygeai.tests.integration.lab.agents.rst +69 -0
  122. pygeai/_docs/source/pygeai.tests.integration.lab.processes.rst +77 -0
  123. pygeai/_docs/source/pygeai.tests.integration.lab.reasoning_strategies.rst +37 -0
  124. pygeai/_docs/source/pygeai.tests.integration.lab.rst +21 -0
  125. pygeai/_docs/source/pygeai.tests.integration.lab.tools.rst +77 -0
  126. pygeai/_docs/source/pygeai.tests.integration.rst +20 -0
  127. pygeai/_docs/source/pygeai.tests.lab.agents.rst +29 -0
  128. pygeai/_docs/source/pygeai.tests.lab.processes.rst +29 -0
  129. pygeai/_docs/source/pygeai.tests.lab.rst +49 -0
  130. pygeai/_docs/source/pygeai.tests.lab.spec.rst +29 -0
  131. pygeai/_docs/source/pygeai.tests.lab.strategies.rst +29 -0
  132. pygeai/_docs/source/pygeai.tests.lab.tools.rst +29 -0
  133. pygeai/_docs/source/pygeai.tests.migration.rst +29 -0
  134. pygeai/_docs/source/pygeai.tests.organization.limits.rst +29 -0
  135. pygeai/_docs/source/pygeai.tests.organization.rst +53 -0
  136. pygeai/_docs/source/pygeai.tests.proxy.rst +61 -0
  137. pygeai/_docs/source/pygeai.tests.rst +33 -0
  138. pygeai/admin/clients.py +14 -11
  139. pygeai/admin/endpoints.py +2 -2
  140. pygeai/analytics/clients.py +505 -0
  141. pygeai/analytics/endpoints.py +35 -0
  142. pygeai/analytics/managers.py +606 -0
  143. pygeai/analytics/mappers.py +207 -0
  144. pygeai/analytics/responses.py +240 -0
  145. pygeai/assistant/clients.py +48 -57
  146. pygeai/assistant/data/__init__.py +0 -0
  147. pygeai/assistant/data/clients.py +15 -0
  148. pygeai/assistant/data_analyst/__init__.py +0 -0
  149. pygeai/assistant/data_analyst/clients.py +75 -0
  150. pygeai/assistant/data_analyst/endpoints.py +2 -0
  151. pygeai/assistant/endpoints.py +0 -2
  152. pygeai/assistant/managers.py +738 -0
  153. pygeai/assistant/mappers.py +153 -0
  154. pygeai/assistant/rag/clients.py +132 -21
  155. pygeai/assistant/rag/mappers.py +228 -0
  156. pygeai/assistant/rag/models.py +396 -0
  157. pygeai/assistant/rag/responses.py +10 -0
  158. pygeai/auth/__init__.py +0 -0
  159. pygeai/auth/clients.py +129 -0
  160. pygeai/auth/endpoints.py +6 -0
  161. pygeai/chat/clients.py +406 -31
  162. pygeai/chat/endpoints.py +3 -0
  163. pygeai/chat/iris.py +17 -0
  164. pygeai/chat/managers.py +64 -0
  165. pygeai/chat/session.py +38 -0
  166. pygeai/chat/settings.py +6 -0
  167. pygeai/chat/ui.py +678 -0
  168. pygeai/cli/__init__.py +0 -1
  169. pygeai/cli/commands/admin.py +9 -12
  170. pygeai/cli/commands/analytics.py +533 -0
  171. pygeai/cli/commands/assistant.py +11 -11
  172. pygeai/cli/commands/auth.py +299 -0
  173. pygeai/cli/commands/base.py +201 -7
  174. pygeai/cli/commands/chat.py +875 -14
  175. pygeai/cli/commands/common.py +30 -26
  176. pygeai/cli/commands/configuration.py +84 -9
  177. pygeai/cli/commands/docs.py +105 -0
  178. pygeai/cli/commands/embeddings.py +187 -0
  179. pygeai/cli/commands/evaluation.py +2069 -0
  180. pygeai/cli/commands/feedback.py +93 -0
  181. pygeai/cli/commands/files.py +312 -0
  182. pygeai/cli/commands/flows/__init__.py +0 -0
  183. pygeai/cli/commands/gam.py +349 -0
  184. pygeai/cli/commands/lab/__init__.py +0 -0
  185. pygeai/cli/commands/lab/ai_lab.py +4110 -0
  186. pygeai/cli/commands/lab/common.py +135 -0
  187. pygeai/cli/commands/lab/options.py +8 -0
  188. pygeai/cli/commands/lab/spec.py +273 -0
  189. pygeai/cli/commands/lab/utils.py +13 -0
  190. pygeai/cli/commands/llm.py +164 -0
  191. pygeai/cli/commands/migrate.py +1198 -0
  192. pygeai/cli/commands/options.py +86 -0
  193. pygeai/cli/commands/organization.py +560 -98
  194. pygeai/cli/commands/rag.py +306 -10
  195. pygeai/cli/commands/rerank.py +108 -0
  196. pygeai/cli/commands/secrets.py +357 -0
  197. pygeai/cli/commands/usage_limits.py +583 -0
  198. pygeai/cli/commands/validators.py +209 -0
  199. pygeai/cli/commands/version.py +44 -0
  200. pygeai/cli/error_handler.py +151 -0
  201. pygeai/cli/geai.py +171 -30
  202. pygeai/cli/geai_proxy.py +318 -0
  203. pygeai/cli/install_man.py +107 -0
  204. pygeai/cli/parsers.py +78 -25
  205. pygeai/cli/texts/help.py +712 -55
  206. pygeai/core/__init__.py +9 -1
  207. pygeai/core/base/clients.py +61 -10
  208. pygeai/core/base/mappers.py +208 -30
  209. pygeai/core/base/models.py +8 -308
  210. pygeai/core/base/responses.py +18 -1
  211. pygeai/core/base/session.py +110 -17
  212. pygeai/core/common/config.py +98 -16
  213. pygeai/core/common/decorators.py +44 -0
  214. pygeai/core/common/exceptions.py +104 -4
  215. pygeai/core/embeddings/__init__.py +19 -0
  216. pygeai/core/embeddings/clients.py +93 -0
  217. pygeai/core/embeddings/endpoints.py +1 -0
  218. pygeai/core/embeddings/managers.py +62 -0
  219. pygeai/core/embeddings/mappers.py +52 -0
  220. pygeai/core/embeddings/models.py +14 -0
  221. pygeai/core/embeddings/responses.py +31 -0
  222. pygeai/core/feedback/__init__.py +0 -0
  223. pygeai/core/feedback/clients.py +50 -0
  224. pygeai/core/feedback/endpoints.py +1 -0
  225. pygeai/core/feedback/models.py +10 -0
  226. pygeai/core/files/__init__.py +0 -0
  227. pygeai/core/files/clients.py +156 -0
  228. pygeai/core/files/endpoints.py +5 -0
  229. pygeai/core/files/managers.py +224 -0
  230. pygeai/core/files/mappers.py +44 -0
  231. pygeai/core/files/models.py +24 -0
  232. pygeai/core/files/responses.py +19 -0
  233. pygeai/core/handlers.py +32 -0
  234. pygeai/core/llm/__init__.py +0 -0
  235. pygeai/core/llm/clients.py +53 -0
  236. pygeai/core/llm/endpoints.py +4 -0
  237. pygeai/core/models.py +799 -0
  238. pygeai/core/plugins/__init__.py +0 -0
  239. pygeai/core/plugins/clients.py +32 -0
  240. pygeai/core/plugins/endpoints.py +1 -0
  241. pygeai/core/plugins/models.py +86 -0
  242. pygeai/core/rerank/__init__.py +0 -0
  243. pygeai/core/rerank/clients.py +35 -0
  244. pygeai/core/rerank/endpoints.py +1 -0
  245. pygeai/core/rerank/managers.py +47 -0
  246. pygeai/core/rerank/mappers.py +23 -0
  247. pygeai/core/rerank/models.py +27 -0
  248. pygeai/core/responses.py +104 -0
  249. pygeai/core/secrets/__init__.py +0 -0
  250. pygeai/core/secrets/clients.py +212 -0
  251. pygeai/core/secrets/endpoints.py +7 -0
  252. pygeai/core/services/llm/__init__.py +0 -0
  253. pygeai/core/services/llm/model.py +186 -0
  254. pygeai/core/services/llm/providers.py +15 -0
  255. pygeai/core/services/response.py +18 -0
  256. pygeai/core/services/rest.py +311 -89
  257. pygeai/core/utils/__init__.py +0 -0
  258. pygeai/core/utils/console.py +83 -0
  259. pygeai/core/utils/parsers.py +32 -0
  260. pygeai/core/utils/validators.py +10 -0
  261. pygeai/dbg/__init__.py +3 -0
  262. pygeai/dbg/debugger.py +870 -0
  263. pygeai/evaluation/__init__.py +0 -0
  264. pygeai/evaluation/clients.py +19 -0
  265. pygeai/evaluation/dataset/__init__.py +0 -0
  266. pygeai/evaluation/dataset/clients.py +514 -0
  267. pygeai/evaluation/dataset/endpoints.py +26 -0
  268. pygeai/evaluation/plan/__init__.py +0 -0
  269. pygeai/evaluation/plan/clients.py +302 -0
  270. pygeai/evaluation/plan/endpoints.py +16 -0
  271. pygeai/evaluation/result/__init__.py +0 -0
  272. pygeai/evaluation/result/clients.py +70 -0
  273. pygeai/evaluation/result/endpoints.py +2 -0
  274. pygeai/flows/__init__.py +0 -0
  275. pygeai/flows/endpoints.py +362 -0
  276. pygeai/flows/models.py +1304 -0
  277. pygeai/gam/__init__.py +0 -0
  278. pygeai/gam/clients.py +178 -0
  279. pygeai/gam/endpoints.py +4 -0
  280. pygeai/health/__init__.py +0 -0
  281. pygeai/health/clients.py +24 -0
  282. pygeai/health/endpoints.py +1 -0
  283. pygeai/lab/__init__.py +0 -0
  284. pygeai/lab/agents/__init__.py +0 -0
  285. pygeai/lab/agents/clients.py +426 -0
  286. pygeai/lab/agents/endpoints.py +12 -0
  287. pygeai/lab/agents/mappers.py +319 -0
  288. pygeai/lab/clients.py +24 -0
  289. pygeai/lab/constants.py +3 -0
  290. pygeai/lab/managers.py +1558 -0
  291. pygeai/lab/models.py +1719 -0
  292. pygeai/lab/processes/__init__.py +0 -0
  293. pygeai/lab/processes/clients.py +1051 -0
  294. pygeai/lab/processes/endpoints.py +26 -0
  295. pygeai/lab/processes/mappers.py +395 -0
  296. pygeai/lab/runners.py +90 -0
  297. pygeai/lab/spec/__init__.py +0 -0
  298. pygeai/lab/spec/loader.py +24 -0
  299. pygeai/lab/spec/parsers.py +39 -0
  300. pygeai/lab/strategies/__init__.py +0 -0
  301. pygeai/lab/strategies/clients.py +212 -0
  302. pygeai/lab/strategies/endpoints.py +5 -0
  303. pygeai/lab/strategies/mappers.py +58 -0
  304. pygeai/lab/tools/__init__.py +0 -0
  305. pygeai/lab/tools/clients.py +465 -0
  306. pygeai/lab/tools/endpoints.py +13 -0
  307. pygeai/lab/tools/mappers.py +131 -0
  308. pygeai/man/__init__.py +1 -0
  309. pygeai/man/man1/__init__.py +1 -0
  310. pygeai/man/man1/geai-proxy.1 +246 -0
  311. pygeai/man/man1/geai.1 +2615 -0
  312. pygeai/migration/__init__.py +33 -0
  313. pygeai/migration/strategies.py +603 -0
  314. pygeai/migration/tools.py +180 -0
  315. pygeai/organization/clients.py +246 -18
  316. pygeai/organization/endpoints.py +17 -8
  317. pygeai/organization/limits/__init__.py +0 -0
  318. pygeai/organization/limits/clients.py +281 -0
  319. pygeai/organization/limits/endpoints.py +15 -0
  320. pygeai/organization/limits/managers.py +331 -0
  321. pygeai/organization/limits/mappers.py +21 -0
  322. pygeai/organization/managers.py +537 -0
  323. pygeai/organization/mappers.py +111 -46
  324. pygeai/organization/responses.py +61 -11
  325. pygeai/proxy/__init__.py +0 -0
  326. pygeai/proxy/clients.py +216 -0
  327. pygeai/proxy/config.py +128 -0
  328. pygeai/proxy/managers.py +232 -0
  329. pygeai/proxy/servers.py +304 -0
  330. pygeai/proxy/tool.py +69 -0
  331. pygeai/tests/admin/__init__.py +0 -0
  332. pygeai/tests/admin/test_clients.py +148 -0
  333. pygeai/tests/analytics/__init__.py +0 -0
  334. pygeai/tests/analytics/test_clients.py +86 -0
  335. pygeai/tests/analytics/test_managers.py +94 -0
  336. pygeai/tests/analytics/test_mappers.py +84 -0
  337. pygeai/tests/analytics/test_responses.py +73 -0
  338. pygeai/tests/assistants/rag/__init__.py +0 -0
  339. pygeai/tests/assistants/rag/test_clients.py +346 -0
  340. pygeai/tests/assistants/rag/test_mappers.py +189 -0
  341. pygeai/tests/assistants/rag/test_models.py +292 -0
  342. pygeai/tests/assistants/test_clients.py +176 -80
  343. pygeai/tests/assistants/test_managers.py +198 -0
  344. pygeai/tests/assistants/test_mappers.py +111 -0
  345. pygeai/tests/auth/__init__.py +0 -0
  346. pygeai/tests/auth/test_clients.py +289 -0
  347. pygeai/tests/auth/test_oauth.py +172 -0
  348. pygeai/tests/auth/test_session_logging.py +150 -0
  349. pygeai/tests/chat/__init__.py +0 -0
  350. pygeai/tests/chat/test_clients.py +393 -0
  351. pygeai/tests/chat/test_iris.py +38 -0
  352. pygeai/tests/chat/test_session.py +62 -0
  353. pygeai/tests/chat/test_ui.py +224 -0
  354. pygeai/tests/cli/__init__.py +0 -0
  355. pygeai/tests/cli/commands/__init__.py +0 -0
  356. pygeai/tests/cli/commands/lab/__init__.py +0 -0
  357. pygeai/tests/cli/commands/lab/test_ai_lab.py +786 -0
  358. pygeai/tests/cli/commands/lab/test_common.py +208 -0
  359. pygeai/tests/cli/commands/lab/test_spec.py +246 -0
  360. pygeai/tests/cli/commands/test_assistant.py +202 -0
  361. pygeai/tests/cli/commands/test_chat.py +130 -0
  362. pygeai/tests/cli/commands/test_common.py +350 -0
  363. pygeai/tests/cli/commands/test_embeddings.py +132 -0
  364. pygeai/tests/cli/commands/test_evaluation.py +656 -0
  365. pygeai/tests/cli/commands/test_feedback.py +65 -0
  366. pygeai/tests/cli/commands/test_files.py +161 -0
  367. pygeai/tests/cli/commands/test_gam.py +201 -0
  368. pygeai/tests/cli/commands/test_llm.py +114 -0
  369. pygeai/tests/cli/commands/test_migrate.py +176 -0
  370. pygeai/tests/cli/commands/test_organization.py +276 -0
  371. pygeai/tests/cli/commands/test_rag.py +266 -0
  372. pygeai/tests/cli/commands/test_rerank.py +110 -0
  373. pygeai/tests/cli/commands/test_secrets.py +171 -0
  374. pygeai/tests/cli/commands/test_show_help.py +41 -0
  375. pygeai/tests/cli/commands/test_usage_limits.py +412 -0
  376. pygeai/tests/cli/commands/test_validators.py +160 -0
  377. pygeai/tests/cli/commands/test_version.py +81 -0
  378. pygeai/tests/cli/docker/__init__.py +0 -0
  379. pygeai/tests/cli/test_credentials_flag.py +316 -0
  380. pygeai/tests/cli/test_error_handler.py +225 -0
  381. pygeai/tests/cli/test_geai_driver.py +154 -0
  382. pygeai/tests/cli/test_parsers.py +154 -0
  383. pygeai/tests/core/base/__init__.py +0 -0
  384. pygeai/tests/core/base/data/__init__.py +0 -0
  385. pygeai/tests/core/base/data/mappers.py +117 -0
  386. pygeai/tests/core/base/data/models.py +312 -0
  387. pygeai/tests/core/base/test_mappers.py +569 -0
  388. pygeai/tests/core/base/test_models.py +261 -0
  389. pygeai/tests/core/base/test_responses.py +53 -0
  390. pygeai/tests/core/common/__init__.py +0 -0
  391. pygeai/tests/core/common/data/__init__.py +0 -0
  392. pygeai/tests/core/common/test_config.py +186 -0
  393. pygeai/tests/core/common/test_decorators.py +69 -0
  394. pygeai/tests/core/embeddings/__init__.py +0 -0
  395. pygeai/tests/core/embeddings/test_clients.py +225 -0
  396. pygeai/tests/core/embeddings/test_managers.py +171 -0
  397. pygeai/tests/core/embeddings/test_mappers.py +142 -0
  398. pygeai/tests/core/feedback/__init__.py +0 -0
  399. pygeai/tests/core/feedback/test_clients.py +64 -0
  400. pygeai/tests/core/files/__init__.py +0 -0
  401. pygeai/tests/core/files/test_clients.py +128 -0
  402. pygeai/tests/core/files/test_managers.py +219 -0
  403. pygeai/tests/core/files/test_mappers.py +137 -0
  404. pygeai/tests/core/files/test_models.py +103 -0
  405. pygeai/tests/core/files/test_responses.py +122 -0
  406. pygeai/tests/core/llm/__init__.py +0 -0
  407. pygeai/tests/core/llm/test_clients.py +142 -0
  408. pygeai/tests/core/plugins/__init__.py +0 -0
  409. pygeai/tests/core/plugins/test_clients.py +66 -0
  410. pygeai/tests/core/rerank/__init__.py +0 -0
  411. pygeai/tests/core/rerank/test_clients.py +76 -0
  412. pygeai/tests/core/rerank/test_managers.py +99 -0
  413. pygeai/tests/core/rerank/test_mappers.py +54 -0
  414. pygeai/tests/core/secrets/__init__.py +0 -0
  415. pygeai/tests/core/secrets/test_clients.py +264 -0
  416. pygeai/tests/core/services/__init__.py +0 -0
  417. pygeai/tests/core/services/test_rest.py +273 -0
  418. pygeai/tests/core/test_handlers.py +66 -0
  419. pygeai/tests/core/utils/__init__.py +0 -0
  420. pygeai/tests/core/utils/test_console.py +80 -0
  421. pygeai/tests/dbg/__init__.py +0 -0
  422. pygeai/tests/dbg/test_debugger.py +591 -0
  423. pygeai/tests/evaluation/__init__.py +0 -0
  424. pygeai/tests/evaluation/dataset/__init__.py +0 -0
  425. pygeai/tests/evaluation/dataset/test_clients.py +265 -0
  426. pygeai/tests/evaluation/plan/__init__.py +0 -0
  427. pygeai/tests/evaluation/plan/test_clients.py +195 -0
  428. pygeai/tests/evaluation/result/__init__.py +0 -0
  429. pygeai/tests/evaluation/result/test_clients.py +66 -0
  430. pygeai/tests/gam/__init__.py +0 -0
  431. pygeai/tests/gam/test_clients.py +195 -0
  432. pygeai/tests/health/__init__.py +0 -0
  433. pygeai/tests/health/test_clients.py +41 -0
  434. pygeai/tests/integration/__init__.py +0 -0
  435. pygeai/tests/integration/assistants/__init__.py +0 -0
  436. pygeai/tests/integration/assistants/rag/__init__.py +0 -0
  437. pygeai/tests/integration/assistants/rag/test_create_rag.py +91 -0
  438. pygeai/tests/integration/chat/__init__.py +0 -0
  439. pygeai/tests/integration/chat/test_generate_image.py +158 -0
  440. pygeai/tests/integration/lab/__init__.py +0 -0
  441. pygeai/tests/integration/lab/agents/__init__.py +0 -0
  442. pygeai/tests/integration/lab/agents/test_agents_list.py +106 -0
  443. pygeai/tests/integration/lab/agents/test_create_agent.py +319 -0
  444. pygeai/tests/integration/lab/agents/test_create_sharing_link.py +70 -0
  445. pygeai/tests/integration/lab/agents/test_delete_agent.py +75 -0
  446. pygeai/tests/integration/lab/agents/test_get_agent.py +94 -0
  447. pygeai/tests/integration/lab/agents/test_publish_agent_revision.py +127 -0
  448. pygeai/tests/integration/lab/agents/test_update_agent.py +250 -0
  449. pygeai/tests/integration/lab/processes/__init__.py +0 -0
  450. pygeai/tests/integration/lab/processes/test_create_process.py +345 -0
  451. pygeai/tests/integration/lab/processes/test_create_task.py +211 -0
  452. pygeai/tests/integration/lab/processes/test_delete_process.py +111 -0
  453. pygeai/tests/integration/lab/processes/test_get_process.py +201 -0
  454. pygeai/tests/integration/lab/processes/test_list_process_instances.py +91 -0
  455. pygeai/tests/integration/lab/processes/test_list_processes.py +138 -0
  456. pygeai/tests/integration/lab/processes/test_publish_process_revision.py +232 -0
  457. pygeai/tests/integration/lab/processes/test_update_process.py +289 -0
  458. pygeai/tests/integration/lab/reasoning_strategies/__init__.py +0 -0
  459. pygeai/tests/integration/lab/reasoning_strategies/test_get_reasoning_strategy.py +70 -0
  460. pygeai/tests/integration/lab/reasoning_strategies/test_list_reasoning_strategies.py +93 -0
  461. pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +149 -0
  462. pygeai/tests/integration/lab/tools/__init__.py +0 -0
  463. pygeai/tests/integration/lab/tools/test_create_tool.py +288 -0
  464. pygeai/tests/integration/lab/tools/test_delete_tool.py +87 -0
  465. pygeai/tests/integration/lab/tools/test_get_parameter.py +98 -0
  466. pygeai/tests/integration/lab/tools/test_get_tool.py +91 -0
  467. pygeai/tests/integration/lab/tools/test_list_tools.py +106 -0
  468. pygeai/tests/integration/lab/tools/test_publish_tool_revision.py +119 -0
  469. pygeai/tests/integration/lab/tools/test_set_parameter.py +114 -0
  470. pygeai/tests/integration/lab/tools/test_update_tool.py +267 -0
  471. pygeai/tests/lab/__init__.py +0 -0
  472. pygeai/tests/lab/agents/__init__.py +0 -0
  473. pygeai/tests/lab/agents/test_clients.py +481 -0
  474. pygeai/tests/lab/agents/test_mappers.py +440 -0
  475. pygeai/tests/lab/processes/__init__.py +0 -0
  476. pygeai/tests/lab/processes/test_clients.py +1416 -0
  477. pygeai/tests/lab/processes/test_mappers.py +1092 -0
  478. pygeai/tests/lab/spec/__init__.py +0 -0
  479. pygeai/tests/lab/spec/test_loader.py +59 -0
  480. pygeai/tests/lab/spec/test_parsers.py +182 -0
  481. pygeai/tests/lab/strategies/__init__.py +0 -0
  482. pygeai/tests/lab/strategies/test_clients.py +241 -0
  483. pygeai/tests/lab/strategies/test_mappers.py +132 -0
  484. pygeai/tests/lab/test_managers.py +553 -0
  485. pygeai/tests/lab/test_mappers.py +245 -0
  486. pygeai/tests/lab/test_models.py +1154 -0
  487. pygeai/tests/lab/tools/__init__.py +0 -0
  488. pygeai/tests/lab/tools/test_clients.py +521 -0
  489. pygeai/tests/lab/tools/test_mappers.py +198 -0
  490. pygeai/tests/migration/__init__.py +0 -0
  491. pygeai/tests/migration/test_strategies.py +405 -0
  492. pygeai/tests/migration/test_tools.py +159 -0
  493. pygeai/tests/organization/limits/__init__.py +0 -0
  494. pygeai/tests/organization/limits/test_clients.py +567 -0
  495. pygeai/tests/organization/limits/test_managers.py +402 -0
  496. pygeai/tests/organization/test_clients.py +615 -64
  497. pygeai/tests/organization/test_managers.py +424 -0
  498. pygeai/tests/organization/test_mappers.py +153 -0
  499. pygeai/tests/organization/test_responses.py +137 -0
  500. pygeai/tests/proxy/__init__.py +1 -0
  501. pygeai/tests/proxy/test_clients.py +397 -0
  502. pygeai/tests/proxy/test_config.py +171 -0
  503. pygeai/tests/proxy/test_integration.py +305 -0
  504. pygeai/tests/proxy/test_managers.py +312 -0
  505. pygeai/tests/proxy/test_servers.py +387 -0
  506. pygeai/tests/proxy/test_tool.py +176 -0
  507. pygeai/tests/snippets/__init__.py +0 -0
  508. pygeai/tests/snippets/analytics/__init__.py +0 -0
  509. pygeai/tests/snippets/analytics/get_agent_usage_per_user.py +16 -0
  510. pygeai/tests/snippets/analytics/get_agents_created_and_modified.py +11 -0
  511. pygeai/tests/snippets/analytics/get_average_cost_per_request.py +10 -0
  512. pygeai/tests/snippets/analytics/get_overall_error_rate.py +10 -0
  513. pygeai/tests/snippets/analytics/get_top_10_agents_by_requests.py +12 -0
  514. pygeai/tests/snippets/analytics/get_total_active_users.py +10 -0
  515. pygeai/tests/snippets/analytics/get_total_cost.py +10 -0
  516. pygeai/tests/snippets/analytics/get_total_requests_per_day.py +12 -0
  517. pygeai/tests/snippets/analytics/get_total_tokens.py +12 -0
  518. pygeai/tests/snippets/assistants/__init__.py +0 -0
  519. pygeai/tests/snippets/assistants/create_chat_assistant.py +54 -0
  520. pygeai/tests/snippets/assistants/create_text_assistant.py +51 -0
  521. pygeai/tests/snippets/assistants/data_analyst/__init__.py +0 -0
  522. pygeai/tests/snippets/assistants/data_analyst/extend_and_check.py +100 -0
  523. pygeai/tests/snippets/assistants/data_analyst/extend_dataset.py +9 -0
  524. pygeai/tests/snippets/assistants/data_analyst/get_status.py +9 -0
  525. pygeai/tests/snippets/assistants/file_summarizer_assistant.py +149 -0
  526. pygeai/tests/snippets/assistants/get_assistant_data.py +8 -0
  527. pygeai/tests/snippets/assistants/get_assistant_list.py +7 -0
  528. pygeai/tests/snippets/assistants/rag/__init__.py +0 -0
  529. pygeai/tests/snippets/assistants/rag/create_rag_assistant.py +65 -0
  530. pygeai/tests/snippets/assistants/rag/delete_al_documents.py +7 -0
  531. pygeai/tests/snippets/assistants/rag/delete_document.py +10 -0
  532. pygeai/tests/snippets/assistants/rag/delete_rag_assistant.py +8 -0
  533. pygeai/tests/snippets/assistants/rag/get_document.py +10 -0
  534. pygeai/tests/snippets/assistants/rag/get_documents.py +7 -0
  535. pygeai/tests/snippets/assistants/rag/get_rag_assistant_data.py +8 -0
  536. pygeai/tests/snippets/assistants/rag/update_rag_assistant.py +48 -0
  537. pygeai/tests/snippets/assistants/rag/upload_document.py +19 -0
  538. pygeai/tests/snippets/assistants/send_feedback.py +14 -0
  539. pygeai/tests/snippets/assistants/update_chat_assistant.py +63 -0
  540. pygeai/tests/snippets/auth/__init__.py +0 -0
  541. pygeai/tests/snippets/chat/__init__.py +0 -0
  542. pygeai/tests/snippets/chat/cancel_request.py +7 -0
  543. pygeai/tests/snippets/chat/chat_completion.py +28 -0
  544. pygeai/tests/snippets/chat/chat_completion_1.py +40 -0
  545. pygeai/tests/snippets/chat/chat_completion_2.py +60 -0
  546. pygeai/tests/snippets/chat/chat_completion_3.py +27 -0
  547. pygeai/tests/snippets/chat/chat_completion_4.py +67 -0
  548. pygeai/tests/snippets/chat/chat_completion_streaming.py +63 -0
  549. pygeai/tests/snippets/chat/chat_completion_with_reasoning_effort.py +18 -0
  550. pygeai/tests/snippets/chat/get_request_status.py +7 -0
  551. pygeai/tests/snippets/chat/get_response.py +15 -0
  552. pygeai/tests/snippets/chat/get_response_complete_example.py +67 -0
  553. pygeai/tests/snippets/chat/get_response_streaming.py +20 -0
  554. pygeai/tests/snippets/chat/get_response_with_files.py +16 -0
  555. pygeai/tests/snippets/chat/get_response_with_instructions.py +19 -0
  556. pygeai/tests/snippets/chat/get_response_with_metadata.py +24 -0
  557. pygeai/tests/snippets/chat/get_response_with_parallel_tools.py +58 -0
  558. pygeai/tests/snippets/chat/get_response_with_reasoning.py +21 -0
  559. pygeai/tests/snippets/chat/get_response_with_store.py +38 -0
  560. pygeai/tests/snippets/chat/get_response_with_tools.py +36 -0
  561. pygeai/tests/snippets/chat/get_response_with_truncation.py +24 -0
  562. pygeai/tests/snippets/chat/send_chat_request.py +33 -0
  563. pygeai/tests/snippets/dbg/__init__.py +0 -0
  564. pygeai/tests/snippets/dbg/basic_debugging.py +32 -0
  565. pygeai/tests/snippets/dbg/breakpoint_management.py +48 -0
  566. pygeai/tests/snippets/dbg/file_debugging.py +72 -0
  567. pygeai/tests/snippets/dbg/module_debugging.py +61 -0
  568. pygeai/tests/snippets/dbg/stack_navigation.py +45 -0
  569. pygeai/tests/snippets/dbg/stepping_example.py +40 -0
  570. pygeai/tests/snippets/embeddings/__init__.py +0 -0
  571. pygeai/tests/snippets/embeddings/cache_example.py +31 -0
  572. pygeai/tests/snippets/embeddings/cohere_example.py +41 -0
  573. pygeai/tests/snippets/embeddings/generate_embeddings.py +26 -0
  574. pygeai/tests/snippets/embeddings/openai_base64_example.py +27 -0
  575. pygeai/tests/snippets/embeddings/openai_example.py +30 -0
  576. pygeai/tests/snippets/embeddings/similarity_example.py +42 -0
  577. pygeai/tests/snippets/evaluation/__init__.py +0 -0
  578. pygeai/tests/snippets/evaluation/dataset/__init__.py +0 -0
  579. pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +195 -0
  580. pygeai/tests/snippets/evaluation/dataset/create_dataset.py +26 -0
  581. pygeai/tests/snippets/evaluation/dataset/create_dataset_from_file.py +11 -0
  582. pygeai/tests/snippets/evaluation/dataset/create_dataset_row.py +17 -0
  583. pygeai/tests/snippets/evaluation/dataset/create_expected_source.py +18 -0
  584. pygeai/tests/snippets/evaluation/dataset/create_filter_variable.py +19 -0
  585. pygeai/tests/snippets/evaluation/dataset/delete_dataset.py +9 -0
  586. pygeai/tests/snippets/evaluation/dataset/delete_dataset_row.py +10 -0
  587. pygeai/tests/snippets/evaluation/dataset/delete_expected_source.py +15 -0
  588. pygeai/tests/snippets/evaluation/dataset/delete_filter_variable.py +15 -0
  589. pygeai/tests/snippets/evaluation/dataset/get_dataset.py +9 -0
  590. pygeai/tests/snippets/evaluation/dataset/get_dataset_row.py +10 -0
  591. pygeai/tests/snippets/evaluation/dataset/get_expected_source.py +15 -0
  592. pygeai/tests/snippets/evaluation/dataset/get_filter_variable.py +15 -0
  593. pygeai/tests/snippets/evaluation/dataset/list_dataset_rows.py +9 -0
  594. pygeai/tests/snippets/evaluation/dataset/list_datasets.py +6 -0
  595. pygeai/tests/snippets/evaluation/dataset/list_expected_sources.py +10 -0
  596. pygeai/tests/snippets/evaluation/dataset/list_filter_variables.py +10 -0
  597. pygeai/tests/snippets/evaluation/dataset/update_dataset.py +15 -0
  598. pygeai/tests/snippets/evaluation/dataset/update_dataset_row.py +20 -0
  599. pygeai/tests/snippets/evaluation/dataset/update_expected_source.py +18 -0
  600. pygeai/tests/snippets/evaluation/dataset/update_filter_variable.py +19 -0
  601. pygeai/tests/snippets/evaluation/dataset/upload_dataset_rows_file.py +10 -0
  602. pygeai/tests/snippets/evaluation/plan/__init__.py +0 -0
  603. pygeai/tests/snippets/evaluation/plan/add_plan_system_metric.py +13 -0
  604. pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +136 -0
  605. pygeai/tests/snippets/evaluation/plan/create_evaluation_plan.py +24 -0
  606. pygeai/tests/snippets/evaluation/plan/create_rag_evaluation_plan.py +22 -0
  607. pygeai/tests/snippets/evaluation/plan/delete_evaluation_plan.py +9 -0
  608. pygeai/tests/snippets/evaluation/plan/delete_plan_system_metric.py +13 -0
  609. pygeai/tests/snippets/evaluation/plan/execute_evaluation_plan.py +11 -0
  610. pygeai/tests/snippets/evaluation/plan/get_evaluation_plan.py +9 -0
  611. pygeai/tests/snippets/evaluation/plan/get_plan_system_metric.py +13 -0
  612. pygeai/tests/snippets/evaluation/plan/get_system_metric.py +9 -0
  613. pygeai/tests/snippets/evaluation/plan/list_evaluation_plans.py +7 -0
  614. pygeai/tests/snippets/evaluation/plan/list_plan_system_metrics.py +9 -0
  615. pygeai/tests/snippets/evaluation/plan/list_system_metrics.py +7 -0
  616. pygeai/tests/snippets/evaluation/plan/update_evaluation_plan.py +22 -0
  617. pygeai/tests/snippets/evaluation/plan/update_plan_system_metric.py +14 -0
  618. pygeai/tests/snippets/evaluation/result/__init__.py +0 -0
  619. pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +150 -0
  620. pygeai/tests/snippets/evaluation/result/get_evaluation_result.py +26 -0
  621. pygeai/tests/snippets/evaluation/result/list_evaluation_results.py +17 -0
  622. pygeai/tests/snippets/files/__init__.py +0 -0
  623. pygeai/tests/snippets/files/delete_file.py +9 -0
  624. pygeai/tests/snippets/files/get_file_content.py +10 -0
  625. pygeai/tests/snippets/files/get_file_data.py +9 -0
  626. pygeai/tests/snippets/files/get_file_list.py +6 -0
  627. pygeai/tests/snippets/files/upload_file.py +13 -0
  628. pygeai/tests/snippets/gam/__init__.py +0 -0
  629. pygeai/tests/snippets/gam/gam_access_token.py +87 -0
  630. pygeai/tests/snippets/lab/__init__.py +0 -0
  631. pygeai/tests/snippets/lab/agentic_flow_example_1.py +326 -0
  632. pygeai/tests/snippets/lab/agentic_flow_example_2.py +206 -0
  633. pygeai/tests/snippets/lab/agentic_flow_example_3.py +486 -0
  634. pygeai/tests/snippets/lab/agentic_flow_example_4.py +446 -0
  635. pygeai/tests/snippets/lab/agents/__init__.py +0 -0
  636. pygeai/tests/snippets/lab/agents/create_agent.py +48 -0
  637. pygeai/tests/snippets/lab/agents/create_agent_2.py +48 -0
  638. pygeai/tests/snippets/lab/agents/create_agent_edge_case.py +48 -0
  639. pygeai/tests/snippets/lab/agents/create_agent_with_permissions.py +39 -0
  640. pygeai/tests/snippets/lab/agents/create_agent_with_properties.py +46 -0
  641. pygeai/tests/snippets/lab/agents/create_agent_without_instructions.py +48 -0
  642. pygeai/tests/snippets/lab/agents/delete_agent.py +12 -0
  643. pygeai/tests/snippets/lab/agents/get_agent.py +24 -0
  644. pygeai/tests/snippets/lab/agents/get_agent_with_new_fields.py +62 -0
  645. pygeai/tests/snippets/lab/agents/get_sharing_link.py +13 -0
  646. pygeai/tests/snippets/lab/agents/list_agents.py +18 -0
  647. pygeai/tests/snippets/lab/agents/publish_agent_revision.py +12 -0
  648. pygeai/tests/snippets/lab/agents/update_agent.py +50 -0
  649. pygeai/tests/snippets/lab/agents/update_agent_properties.py +50 -0
  650. pygeai/tests/snippets/lab/assistant_to_agent.py +191 -0
  651. pygeai/tests/snippets/lab/crud_ui.py +462 -0
  652. pygeai/tests/snippets/lab/processes/__init__.py +0 -0
  653. pygeai/tests/snippets/lab/processes/create_process.py +24 -0
  654. pygeai/tests/snippets/lab/processes/create_task.py +8 -0
  655. pygeai/tests/snippets/lab/processes/jobs/__init__.py +0 -0
  656. pygeai/tests/snippets/lab/processes/jobs/list_jobs.py +21 -0
  657. pygeai/tests/snippets/lab/processes/kbs/__init__.py +0 -0
  658. pygeai/tests/snippets/lab/processes/kbs/create_kb.py +18 -0
  659. pygeai/tests/snippets/lab/processes/kbs/get_kb.py +26 -0
  660. pygeai/tests/snippets/lab/processes/kbs/list_kbs.py +30 -0
  661. pygeai/tests/snippets/lab/processes/kbs/try_all.py +73 -0
  662. pygeai/tests/snippets/lab/processes/list_processes.py +10 -0
  663. pygeai/tests/snippets/lab/runner_1.py +212 -0
  664. pygeai/tests/snippets/lab/samples/__init__.py +0 -0
  665. pygeai/tests/snippets/lab/samples/summarize_files.py +162 -0
  666. pygeai/tests/snippets/lab/strategies/__init__.py +0 -0
  667. pygeai/tests/snippets/lab/strategies/create_reasoning_strategy.py +22 -0
  668. pygeai/tests/snippets/lab/strategies/get_reasoning_strategy.py +10 -0
  669. pygeai/tests/snippets/lab/strategies/list_reasoning_strategies.py +16 -0
  670. pygeai/tests/snippets/lab/strategies/update_reasoning_strategy.py +26 -0
  671. pygeai/tests/snippets/lab/tools/__init__.py +0 -0
  672. pygeai/tests/snippets/lab/tools/create_tool.py +48 -0
  673. pygeai/tests/snippets/lab/tools/create_tool_edge_case.py +50 -0
  674. pygeai/tests/snippets/lab/tools/delete_tool.py +21 -0
  675. pygeai/tests/snippets/lab/tools/get_parameter.py +21 -0
  676. pygeai/tests/snippets/lab/tools/get_tool.py +22 -0
  677. pygeai/tests/snippets/lab/tools/list_tools.py +23 -0
  678. pygeai/tests/snippets/lab/tools/publish_tool_revision.py +13 -0
  679. pygeai/tests/snippets/lab/tools/set_parameters.py +33 -0
  680. pygeai/tests/snippets/lab/tools/update_tool.py +52 -0
  681. pygeai/tests/snippets/lab/use_cases/__init__.py +0 -0
  682. pygeai/tests/snippets/lab/use_cases/c_code_fixer_agent_flow.py +238 -0
  683. pygeai/tests/snippets/lab/use_cases/create_cli_expert.py +1640 -0
  684. pygeai/tests/snippets/lab/use_cases/create_lab_expert.py +4541 -0
  685. pygeai/tests/snippets/lab/use_cases/create_tool_headless_web_browser.py +133 -0
  686. pygeai/tests/snippets/lab/use_cases/create_web_designer.py +189 -0
  687. pygeai/tests/snippets/lab/use_cases/create_web_reader.py +185 -0
  688. pygeai/tests/snippets/lab/use_cases/file_summarizer_example.py +157 -0
  689. pygeai/tests/snippets/lab/use_cases/file_summarizer_example_2.py +157 -0
  690. pygeai/tests/snippets/lab/use_cases/update_cli_expert.py +1773 -0
  691. pygeai/tests/snippets/lab/use_cases/update_lab_expert.py +4541 -0
  692. pygeai/tests/snippets/lab/use_cases/update_web_designer.py +188 -0
  693. pygeai/tests/snippets/lab/use_cases/update_web_reader.py +195 -0
  694. pygeai/tests/snippets/lab/use_cases/update_web_reader_with_tool.py +210 -0
  695. pygeai/tests/snippets/migrate/__init__.py +45 -0
  696. pygeai/tests/snippets/migrate/agent_migration.py +110 -0
  697. pygeai/tests/snippets/migrate/assistant_migration.py +64 -0
  698. pygeai/tests/snippets/migrate/orchestrator_examples.py +179 -0
  699. pygeai/tests/snippets/migrate/process_migration.py +64 -0
  700. pygeai/tests/snippets/migrate/project_migration.py +42 -0
  701. pygeai/tests/snippets/migrate/tool_migration.py +64 -0
  702. pygeai/tests/snippets/organization/__init__.py +0 -0
  703. pygeai/tests/snippets/organization/add_project_member.py +10 -0
  704. pygeai/tests/snippets/organization/add_project_member_batch.py +44 -0
  705. pygeai/tests/snippets/organization/create_project.py +23 -0
  706. pygeai/tests/snippets/organization/delete_project.py +7 -0
  707. pygeai/tests/snippets/organization/export_request_data.py +7 -0
  708. pygeai/tests/snippets/organization/get_memberships.py +12 -0
  709. pygeai/tests/snippets/organization/get_organization_members.py +6 -0
  710. pygeai/tests/snippets/organization/get_project_data.py +7 -0
  711. pygeai/tests/snippets/organization/get_project_list.py +8 -0
  712. pygeai/tests/snippets/organization/get_project_members.py +6 -0
  713. pygeai/tests/snippets/organization/get_project_memberships.py +12 -0
  714. pygeai/tests/snippets/organization/get_project_roles.py +6 -0
  715. pygeai/tests/snippets/organization/get_project_tokens.py +7 -0
  716. pygeai/tests/snippets/organization/update_project.py +14 -0
  717. pygeai/tests/snippets/rerank/__init__.py +0 -0
  718. pygeai/tests/snippets/rerank/rerank_chunks.py +19 -0
  719. pygeai/tests/snippets/secrets/__init__.py +0 -0
  720. pygeai/tests/snippets/usage_limit/__init__.py +0 -0
  721. pygeai/tests/snippets/usage_limit/delete_usage_limit.py +16 -0
  722. pygeai/tests/snippets/usage_limit/get_all_usage_limit_from_organization.py +12 -0
  723. pygeai/tests/snippets/usage_limit/get_usage_limit_from_organization.py +11 -0
  724. pygeai/tests/snippets/usage_limit/get_usage_limit_from_project.py +13 -0
  725. pygeai/tests/snippets/usage_limit/set_usage_limit_organization.py +22 -0
  726. pygeai/tests/snippets/usage_limit/set_usage_limit_project.py +23 -0
  727. pygeai/tests/snippets/usage_limit/update_usage_limit_organization.py +23 -0
  728. pygeai/tests/snippets/usage_limit/update_usage_limit_project.py +24 -0
  729. pygeai/vendor/a2a/__init__.py +1 -0
  730. pygeai/vendor/a2a/auth/__init__.py +0 -0
  731. pygeai/vendor/a2a/auth/user.py +31 -0
  732. pygeai/vendor/a2a/client/__init__.py +19 -0
  733. pygeai/vendor/a2a/client/client.py +425 -0
  734. pygeai/vendor/a2a/client/errors.py +33 -0
  735. pygeai/vendor/a2a/client/helpers.py +22 -0
  736. pygeai/vendor/a2a/py.typed +0 -0
  737. pygeai/vendor/a2a/server/__init__.py +1 -0
  738. pygeai/vendor/a2a/server/agent_execution/__init__.py +18 -0
  739. pygeai/vendor/a2a/server/agent_execution/agent_executor.py +44 -0
  740. pygeai/vendor/a2a/server/agent_execution/context.py +155 -0
  741. pygeai/vendor/a2a/server/agent_execution/request_context_builder.py +20 -0
  742. pygeai/vendor/a2a/server/agent_execution/simple_request_context_builder.py +77 -0
  743. pygeai/vendor/a2a/server/apps/__init__.py +16 -0
  744. pygeai/vendor/a2a/server/apps/jsonrpc/__init__.py +16 -0
  745. pygeai/vendor/a2a/server/apps/jsonrpc/fastapi_app.py +88 -0
  746. pygeai/vendor/a2a/server/apps/jsonrpc/jsonrpc_app.py +426 -0
  747. pygeai/vendor/a2a/server/apps/jsonrpc/starlette_app.py +123 -0
  748. pygeai/vendor/a2a/server/context.py +23 -0
  749. pygeai/vendor/a2a/server/events/__init__.py +21 -0
  750. pygeai/vendor/a2a/server/events/event_consumer.py +149 -0
  751. pygeai/vendor/a2a/server/events/event_queue.py +156 -0
  752. pygeai/vendor/a2a/server/events/in_memory_queue_manager.py +85 -0
  753. pygeai/vendor/a2a/server/events/queue_manager.py +35 -0
  754. pygeai/vendor/a2a/server/request_handlers/__init__.py +20 -0
  755. pygeai/vendor/a2a/server/request_handlers/default_request_handler.py +435 -0
  756. pygeai/vendor/a2a/server/request_handlers/jsonrpc_handler.py +327 -0
  757. pygeai/vendor/a2a/server/request_handlers/request_handler.py +161 -0
  758. pygeai/vendor/a2a/server/request_handlers/response_helpers.py +133 -0
  759. pygeai/vendor/a2a/server/tasks/__init__.py +20 -0
  760. pygeai/vendor/a2a/server/tasks/inmemory_push_notifier.py +62 -0
  761. pygeai/vendor/a2a/server/tasks/inmemory_task_store.py +51 -0
  762. pygeai/vendor/a2a/server/tasks/push_notifier.py +25 -0
  763. pygeai/vendor/a2a/server/tasks/result_aggregator.py +151 -0
  764. pygeai/vendor/a2a/server/tasks/task_manager.py +253 -0
  765. pygeai/vendor/a2a/server/tasks/task_store.py +22 -0
  766. pygeai/vendor/a2a/server/tasks/task_updater.py +155 -0
  767. pygeai/vendor/a2a/types.py +1624 -0
  768. pygeai/vendor/a2a/utils/__init__.py +40 -0
  769. pygeai/vendor/a2a/utils/artifact.py +72 -0
  770. pygeai/vendor/a2a/utils/errors.py +69 -0
  771. pygeai/vendor/a2a/utils/helpers.py +176 -0
  772. pygeai/vendor/a2a/utils/message.py +83 -0
  773. pygeai/vendor/a2a/utils/task.py +57 -0
  774. pygeai/vendor/a2a/utils/telemetry.py +299 -0
  775. pygeai-0.6.0b15.dist-info/METADATA +205 -0
  776. pygeai-0.6.0b15.dist-info/RECORD +799 -0
  777. {pygeai-0.1.6.dist-info → pygeai-0.6.0b15.dist-info}/WHEEL +1 -1
  778. pygeai-0.6.0b15.dist-info/entry_points.txt +5 -0
  779. {pygeai-0.1.6.dist-info → pygeai-0.6.0b15.dist-info/licenses}/LICENSE +13 -1
  780. {pygeai-0.1.6.dist-info → pygeai-0.6.0b15.dist-info}/top_level.txt +0 -1
  781. docs/source/conf.py +0 -45
  782. pygeai/core/clients.py +0 -240
  783. pygeai/tests/core/test_clients.py +0 -49
  784. pygeai-0.1.6.dist-info/METADATA +0 -92
  785. pygeai-0.1.6.dist-info/RECORD +0 -65
  786. pygeai-0.1.6.dist-info/SOURCES.sync-conflict-20241223-145950-3QD4F42.txt +0 -41
  787. pygeai-0.1.6.dist-info/entry_points.txt +0 -2
  788. /pygeai/{agent → analytics}/__init__.py +0 -0
pygeai/lab/models.py ADDED
@@ -0,0 +1,1719 @@
1
+ import re
2
+ from typing import Literal, Optional, List, Dict, Any, Union, Iterator
3
+
4
+ from pydantic import model_validator, Field, field_validator
5
+
6
+ from pygeai.core import CustomBaseModel
7
+
8
+
9
+ class FilterSettings(CustomBaseModel):
10
+ """
11
+ Represents filter settings for querying or filtering data.
12
+
13
+ :param id: str - The ID to filter by (e.g., an agent's ID), defaults to an empty string.
14
+ :param name: str - The name to filter by (e.g., reasoning strategy name), defaults to an empty string.
15
+ :param status: str - Status filter, defaults to None.
16
+ :param start: int - Starting index for pagination, defaults to None.
17
+ :param count: int - Number of items to return, defaults to None.
18
+ :param is_active: bool - If it's active. Defaults to false.
19
+ :param access_scope: str - Access scope filter, defaults to "private".
20
+ :param allow_drafts: bool - Whether to include draft items, defaults to True.
21
+ :param allow_external: bool - Whether to include external items, defaults to False.
22
+ :param revision: str - Revision of the agent, defaults to 0.
23
+ :param version: str - Version of the agent, defaults to 0
24
+ :param scope: Optional[str] - Filter by scope (e.g., "builtin", "external", "api").
25
+ """
26
+ id: Optional[str] = Field(default=None, description="The ID to filter by (e.g., an agent's ID)")
27
+ name: Optional[str] = Field(default=None, description="The name to filter by (e.g., a reasoning strategy name)")
28
+ status: Optional[str] = Field(default=None, description="Status filter")
29
+ start: Optional[int] = Field(default=None, description="Starting index for pagination")
30
+ count: Optional[int] = Field(default=None, description="Number of items to return")
31
+ access_scope: Optional[str] = Field(default="private", alias="accessScope", description="Access scope filter")
32
+ allow_drafts: Optional[bool] = Field(default=True, alias="allowDrafts", description="Whether to include draft items")
33
+ allow_external: Optional[bool] = Field(default=False, alias="allowExternal", description="Whether to include external items")
34
+ is_active: Optional[bool] = Field(default=False, alias="isActive", description="Whether it's active")
35
+ revision: Optional[str] = Field(default=None, description="Revision of the agent")
36
+ version: Optional[int] = Field(default=None, description="Version of the agent")
37
+ scope: Optional[str] = Field(None, description="Filter by scope (e.g., 'builtin', 'external', 'api')")
38
+
39
+ def to_dict(self):
40
+ return self.model_dump(by_alias=True, exclude_none=True)
41
+
42
+ def __str__(self):
43
+ return str(self.to_dict())
44
+
45
+
46
+ class Sampling(CustomBaseModel):
47
+ """
48
+ Represents sampling configuration for an LLM.
49
+
50
+ :param temperature: float - Temperature value for sampling, controlling randomness.
51
+ :param top_k: int - Top-K sampling parameter, limiting to the top K probable tokens.
52
+ :param top_p: float - Top-P (nucleus) sampling parameter, limiting to the smallest set of tokens whose cumulative probability exceeds P.
53
+ """
54
+ temperature: float = Field(1.0, alias="temperature")
55
+ top_k: int = Field(50, alias="topK")
56
+ top_p: float = Field(1.0, alias="topP")
57
+
58
+ def to_dict(self):
59
+ return self.model_dump(by_alias=True, exclude_none=True)
60
+
61
+ def __str__(self):
62
+ return str(self.to_dict())
63
+
64
+
65
+ class LlmConfig(CustomBaseModel):
66
+ """
67
+ Represents the configuration parameters for an LLM.
68
+
69
+ :param max_tokens: int - Maximum number of tokens the LLM can generate.
70
+ :param timeout: int - Timeout value in seconds (0 means no timeout).
71
+ :param sampling: Sampling - Sampling configuration for the LLM.
72
+ """
73
+ max_tokens: int = Field(..., alias="maxTokens")
74
+ timeout: Optional[int] = Field(60, alias="timeout")
75
+ sampling: Optional[Sampling] = Field(Sampling(), alias="sampling")
76
+
77
+ def to_dict(self):
78
+ result = {
79
+ "maxTokens": self.max_tokens,
80
+ "timeout": self.timeout,
81
+ "sampling": self.sampling.to_dict() if self.sampling else None
82
+ }
83
+ return {k: v for k, v in result.items() if v is not None}
84
+
85
+ def __str__(self):
86
+ return str(self.to_dict())
87
+
88
+
89
+ class Model(CustomBaseModel):
90
+ """
91
+ Represents a language model configuration used by an agent.
92
+
93
+ :param name: str - The unique name identifying the model.
94
+ :param llm_config: Optional[LlmConfig] - Overrides default agent LLM settings.
95
+ :param prompt: Optional[dict] - A tailored prompt specific to this model.
96
+ """
97
+ name: Optional[str] = Field(None, alias="name")
98
+ llm_config: Optional[LlmConfig] = Field(None, alias="llmConfig")
99
+ prompt: Optional[Dict[str, Any]] = Field(None, alias="prompt")
100
+
101
+ @field_validator("llm_config", mode="before")
102
+ @classmethod
103
+ def normalize_llm_config(cls, value):
104
+ if isinstance(value, dict):
105
+ return LlmConfig.model_validate(value)
106
+ return value
107
+
108
+ def to_dict(self):
109
+ result = {"name": self.name}
110
+ if self.llm_config is not None:
111
+ result["llmConfig"] = self.llm_config.to_dict()
112
+ if self.prompt is not None:
113
+ result["prompt"] = self.prompt
114
+ return result
115
+
116
+ def __str__(self):
117
+ return str(self.to_dict())
118
+
119
+
120
+ class PromptExample(CustomBaseModel):
121
+ """
122
+ Represents an example for the prompt configuration.
123
+
124
+ :param input_data: str - Example input data provided to the agent.
125
+ :param output: str - Example output in JSON string format.
126
+ """
127
+ input_data: str = Field(..., alias="inputData")
128
+ output: str = Field(..., alias="output")
129
+
130
+ def to_dict(self):
131
+ return self.model_dump(by_alias=True, exclude_none=True)
132
+
133
+ def __str__(self):
134
+ return str(self.to_dict())
135
+
136
+
137
+ class PromptOutput(CustomBaseModel):
138
+ """
139
+ Represents an output definition for the prompt configuration.
140
+
141
+ :param key: str - Key identifying the output.
142
+ :param description: str - Description of the output's purpose and format.
143
+ """
144
+ key: str = Field(..., alias="key")
145
+ description: str = Field(..., alias="description")
146
+
147
+ def to_dict(self):
148
+ return self.model_dump(by_alias=True, exclude_none=True)
149
+
150
+ def __str__(self):
151
+ return str(self.to_dict())
152
+
153
+
154
+ class Prompt(CustomBaseModel):
155
+ """
156
+ Represents the prompt configuration for an agent.
157
+
158
+ :param instructions: str - Instructions for the agent's behavior.
159
+ :param inputs: List[str] - List of input parameters the agent expects.
160
+ :param outputs: List[PromptOutput] - List of output definitions the agent produces.
161
+ :param context: Optional[str] - Background context for the agent # NOT IMPLEMENTED YET
162
+ :param examples: List[PromptExample] - List of example input-output pairs.
163
+ """
164
+ instructions: Optional[str] = Field(None, alias="instructions")
165
+ inputs: Optional[List[str]] = Field(None, alias="inputs")
166
+ outputs: Optional[List[PromptOutput]] = Field([], alias="outputs")
167
+ context: Optional[str] = Field(None, alias="context", description="Background context for the agent")
168
+ examples: Optional[List[PromptExample]] = Field(None, alias="examples")
169
+
170
+ '''
171
+ @field_validator("instructions")
172
+ @classmethod
173
+ def validate_instructions(cls, value: str) -> str:
174
+ if not value.strip():
175
+ raise ValueError("instructions cannot be blank")
176
+
177
+ return value
178
+ '''
179
+
180
+ @field_validator("outputs", mode="before")
181
+ @classmethod
182
+ def normalize_outputs(cls, value):
183
+ if isinstance(value, list):
184
+ return [PromptOutput.model_validate(item) if isinstance(item, dict) else item for item in value]
185
+ return value
186
+
187
+ @field_validator("examples", mode="before")
188
+ @classmethod
189
+ def normalize_examples(cls, value):
190
+ if isinstance(value, list):
191
+ return [PromptExample.model_validate(item) if isinstance(item, dict) else item for item in value]
192
+ return value
193
+
194
+ def to_dict(self):
195
+ result = {
196
+ "instructions": self.instructions,
197
+ "context": self.context,
198
+ "inputs": self.inputs,
199
+ "outputs": [output.to_dict() for output in self.outputs] if self.outputs else None,
200
+ "examples": [example.to_dict() for example in self.examples] if self.examples else None
201
+ }
202
+ return {k: v for k, v in result.items() if v is not None}
203
+
204
+ def __str__(self):
205
+ return str(self.to_dict())
206
+
207
+
208
+ class ModelList(CustomBaseModel):
209
+ models: List[Model] = Field(..., alias="models")
210
+
211
+ @field_validator("models", mode="before")
212
+ @classmethod
213
+ def normalize_models(cls, value):
214
+ if isinstance(value, list):
215
+ return [Model.model_validate(item) if isinstance(item, dict) else item for item in value]
216
+ return value
217
+
218
+ def to_dict(self):
219
+ return [model.to_dict() for model in self.models]
220
+
221
+ def __getitem__(self, index: int) -> Model:
222
+ if self.models is None:
223
+ raise IndexError("ModelList is empty")
224
+ return self.models[index]
225
+
226
+ def __len__(self) -> int:
227
+ return len(self.models) if self.models else 0
228
+
229
+ def __iter__(self):
230
+ """Make ModelList iterable over its models."""
231
+ if self.models is None:
232
+ return iter([])
233
+ return iter(self.models)
234
+
235
+ def append(self, item: Model) -> None:
236
+ """Append a Model instance to the models list."""
237
+ if self.models is None:
238
+ self.models = []
239
+ self.models.append(item)
240
+
241
+
242
+ class ResourcePoolTool(CustomBaseModel):
243
+ """
244
+ Represents a tool within a resource pool.
245
+
246
+ :param name: str - The ID or name of the tool.
247
+ :param revision: Optional[int] - Specific revision of the tool; if None, uses latest published version.
248
+ """
249
+ name: str = Field(..., alias="name", description="The ID or name of the tool")
250
+ revision: Optional[int] = Field(None, alias="revision", description="Specific revision of the tool; if None, uses latest published version")
251
+
252
+ @field_validator("name")
253
+ @classmethod
254
+ def validate_name(cls, value: str) -> str:
255
+ if not value.strip():
256
+ raise ValueError("name cannot be blank")
257
+ if ":" in value or "/" in value:
258
+ raise ValueError("name cannot contain ':' or '/'")
259
+ return value
260
+
261
+ def to_dict(self):
262
+ return self.model_dump(by_alias=True, exclude_none=True)
263
+
264
+ def __str__(self):
265
+ return str(self.to_dict())
266
+
267
+
268
+ class ResourcePoolAgent(CustomBaseModel):
269
+ """
270
+ Represents a helper agent within a resource pool.
271
+
272
+ :param name: str - The ID or name of the agent.
273
+ :param revision: Optional[int] - Specific revision of the agent; if None, uses latest published version.
274
+ """
275
+ name: str = Field(..., alias="name", description="The ID or name of the agent")
276
+ revision: Optional[int] = Field(None, alias="revision", description="Specific revision of the agent; if None, uses latest published version")
277
+
278
+ @field_validator("name")
279
+ @classmethod
280
+ def validate_name(cls, value: str) -> str:
281
+ if not value.strip():
282
+ raise ValueError("name cannot be blank")
283
+ if ":" in value or "/" in value:
284
+ raise ValueError("name cannot contain ':' or '/'")
285
+ return value
286
+
287
+ def to_dict(self):
288
+ return self.model_dump(by_alias=True, exclude_none=True)
289
+
290
+ def __str__(self):
291
+ return str(self.to_dict())
292
+
293
+
294
+ class ResourcePool(CustomBaseModel):
295
+ """
296
+ Represents a resource pool organizing tools and helper agents.
297
+
298
+ :param name: str - The name of the resource pool.
299
+ :param tools: Optional[List[ResourcePoolTool]] - List of tools in the pool.
300
+ :param agents: Optional[List[ResourcePoolAgent]] - List of helper agents in the pool.
301
+ """
302
+ name: str = Field(..., alias="name", description="The name of the resource pool")
303
+ tools: Optional[List[ResourcePoolTool]] = Field(None, alias="tools", description="List of tools in the pool")
304
+ agents: Optional[List[ResourcePoolAgent]] = Field(None, alias="agents", description="List of helper agents in the pool")
305
+
306
+ @field_validator("name")
307
+ @classmethod
308
+ def validate_name(cls, value: str) -> str:
309
+ if not value.strip():
310
+ raise ValueError("name cannot be blank")
311
+ if ":" in value or "/" in value:
312
+ raise ValueError("name cannot contain ':' or '/'")
313
+ return value
314
+
315
+ @field_validator("tools", mode="before")
316
+ @classmethod
317
+ def normalize_tools(cls, value):
318
+ if isinstance(value, list):
319
+ return [ResourcePoolTool.model_validate(item) if isinstance(item, dict) else item for item in value]
320
+ return value
321
+
322
+ @field_validator("agents", mode="before")
323
+ @classmethod
324
+ def normalize_agents(cls, value):
325
+ if isinstance(value, list):
326
+ return [ResourcePoolAgent.model_validate(item) if isinstance(item, dict) else item for item in value]
327
+ return value
328
+
329
+ def to_dict(self):
330
+ result = {
331
+ "name": self.name,
332
+ "tools": [tool.to_dict() for tool in self.tools] if self.tools else None,
333
+ "agents": [agent.to_dict() for agent in self.agents] if self.agents else None
334
+ }
335
+ return {k: v for k, v in result.items() if v is not None}
336
+
337
+ def __str__(self):
338
+ return str(self.to_dict())
339
+
340
+
341
+ class ResourcePoolList(CustomBaseModel):
342
+ """
343
+ Represents a list of resource pools for an agent.
344
+
345
+ :param resource_pools: List[ResourcePool] - The list of resource pools.
346
+ """
347
+ resource_pools: List[ResourcePool] = Field(..., alias="resourcePools", description="The list of resource pools")
348
+
349
+ @field_validator("resource_pools", mode="before")
350
+ @classmethod
351
+ def normalize_resource_pools(cls, value):
352
+ if isinstance(value, list):
353
+ return [ResourcePool.model_validate(item) if isinstance(item, dict) else item for item in value]
354
+ raise ValueError("resource_pools must be a list of ResourcePool instances or dictionaries")
355
+
356
+ def to_dict(self):
357
+ """
358
+ Serializes the ResourcePoolList to a list of dictionaries.
359
+
360
+ :return: List[Dict] - A list of dictionary representations of the resource pools.
361
+ """
362
+ return [pool.to_dict() for pool in self.resource_pools]
363
+
364
+ def __str__(self):
365
+ return str(self.to_dict())
366
+
367
+ def __getitem__(self, index: int) -> ResourcePool:
368
+ if self.resource_pools is None:
369
+ raise IndexError("ResourcePoolList is empty")
370
+ return self.resource_pools[index]
371
+
372
+ def __len__(self) -> int:
373
+ return len(self.resource_pools) if self.resource_pools else 0
374
+
375
+ def __iter__(self) -> Iterator[ResourcePool]:
376
+ """Make ResourcePoolList iterable over its resource pools."""
377
+ if self.resource_pools is None:
378
+ return iter([])
379
+ return iter(self.resource_pools)
380
+
381
+ def append(self, item: ResourcePool) -> None:
382
+ """Append a ResourcePool instance to the resource_pools list."""
383
+ if self.resource_pools is None:
384
+ self.resource_pools = []
385
+ self.resource_pools.append(item)
386
+
387
+
388
+ class Permission(CustomBaseModel):
389
+ """
390
+ Represents permission settings for an agent.
391
+
392
+ :param chat_sharing: Literal["none", "organization", "project"] - Chat sharing permission level.
393
+ :param external_execution: Literal["none", "organization", "project"] - External execution permission level.
394
+ """
395
+ chat_sharing: Optional[Literal["none", "organization", "project"]] = Field(None, alias="chatSharing", description="Chat sharing permission level")
396
+ external_execution: Optional[Literal["none", "organization", "project"]] = Field(None, alias="externalExecution", description="External execution permission level")
397
+
398
+ def to_dict(self):
399
+ """Convert Permission to dictionary with API aliases."""
400
+ return self.model_dump(by_alias=True, exclude_none=True)
401
+
402
+
403
+ class Property(CustomBaseModel):
404
+ """
405
+ Represents a property key-value pair with data type.
406
+
407
+ :param data_type: str - Data type of the property (e.g., "String", "Number", "Boolean").
408
+ :param key: str - Property key identifier.
409
+ :param value: str - Property value.
410
+ """
411
+ data_type: str = Field(..., alias="dataType", description="Data type of the property")
412
+ key: str = Field(..., alias="key", description="Property key identifier")
413
+ value: str = Field(..., alias="value", description="Property value")
414
+
415
+ def to_dict(self):
416
+ """Convert Property to dictionary with API aliases."""
417
+ return self.model_dump(by_alias=True, exclude_none=True)
418
+
419
+
420
+ class AgentData(CustomBaseModel):
421
+ """
422
+ Represents the detailed configuration data for an agent.
423
+
424
+ :param prompt: dict - Prompt instructions, inputs, outputs, and examples for the agent.
425
+ :param llm_config: dict - Configuration parameters for the LLM (e.g., max tokens, timeout, temperature).
426
+ :param strategy_name: str - Strategy name used for the agent (e.g., Dynamic Prompting, Chain of Thought, Question Refinement, etc)
427
+ :param models: ModelList - List of models available for the agent.
428
+ :param resource_pools: Optional[List[ResourcePool]] - List of resource pools organizing tools and helper agents.
429
+ """
430
+ prompt: Prompt = Field(..., alias="prompt")
431
+ llm_config: LlmConfig = Field(..., alias="llmConfig")
432
+ strategy_name: Optional[str] = Field("Dynamic Prompting", alias="strategyName")
433
+ models: Optional[Union[ModelList, List[Model]]] = Field(None, alias="models")
434
+ resource_pools: Optional[ResourcePoolList] = Field(None, alias="resourcePools", description="List of resource pools organizing tools and helper agents")
435
+ properties: Optional[List[Property]] = Field(None, alias="properties", description="List of agent properties")
436
+
437
+ @field_validator("prompt", mode="before")
438
+ @classmethod
439
+ def normalize_prompt(cls, value):
440
+ if isinstance(value, dict):
441
+ return Prompt.model_validate(value)
442
+ return value
443
+
444
+ @field_validator("llm_config", mode="before")
445
+ @classmethod
446
+ def normalize_llm_config(cls, value):
447
+ if isinstance(value, dict):
448
+ return LlmConfig.model_validate(value)
449
+ return value
450
+
451
+ @field_validator("models", mode="before")
452
+ @classmethod
453
+ def normalize_models(cls, value):
454
+ if value is None:
455
+ return None
456
+ if isinstance(value, ModelList):
457
+ return value
458
+ elif isinstance(value, list):
459
+ return ModelList(models=[Model.model_validate(item) if isinstance(item, dict) else item for item in value])
460
+ raise ValueError("models must be a ModelList or a list of Model instances/dictionaries")
461
+
462
+ @field_validator("resource_pools", mode="before")
463
+ @classmethod
464
+ def normalize_resource_pools(cls, value):
465
+ if isinstance(value, ResourcePoolList):
466
+ return value
467
+ elif isinstance(value, list):
468
+ return ResourcePoolList(resource_pools=[ResourcePool.model_validate(item) if isinstance(item, dict) else item for item in value])
469
+ return value
470
+
471
+ @field_validator("properties", mode="before")
472
+ @classmethod
473
+ def normalize_properties(cls, value):
474
+ if isinstance(value, list):
475
+ return [Property.model_validate(item) if isinstance(item, dict) else item for item in value]
476
+ return value
477
+
478
+ @model_validator(mode="after")
479
+ def validate_resource_pools_unique_names(self):
480
+ if self.resource_pools:
481
+ pools = self.resource_pools.resource_pools if isinstance(self.resource_pools, ResourcePoolList) else self.resource_pools
482
+ names = [pool.name for pool in pools]
483
+ if len(names) != len(set(names)):
484
+ raise ValueError("Resource pool names must be unique within agentData")
485
+ return self
486
+
487
+ def to_dict(self):
488
+ """
489
+ Serializes the AgentData instance to a dictionary, ensuring each Model in models calls its to_dict method.
490
+
491
+ :return: dict - A dictionary representation of the agent data with aliases.
492
+ """
493
+ result = {
494
+ "prompt": self.prompt.to_dict(),
495
+ "llmConfig": self.llm_config.to_dict(),
496
+ "strategyName": self.strategy_name,
497
+ "models": self.models.to_dict() if self.models else None,
498
+ "resourcePools": [pool.to_dict() for pool in self.resource_pools] if self.resource_pools else None,
499
+ "properties": [prop.to_dict() for prop in self.properties] if self.properties else None
500
+ }
501
+ return {k: v for k, v in result.items() if v is not None}
502
+
503
+ def __str__(self):
504
+ return str(self.to_dict())
505
+
506
+
507
+ class Agent(CustomBaseModel):
508
+ """
509
+ Represents an agent configuration returned by the API.
510
+
511
+ :param id: str - Unique identifier for the agent.
512
+ :param status: Literal["active", "inactive"] - Current status of the agent.
513
+ :param name: str - Name of the agent.
514
+ :param access_scope: Literal["public", "private"] - Access scope of the agent.
515
+ :param public_name: Optional[str] - Public identifier for the agent, required if access_scope is "public".
516
+ :param avatar_image: Optional[str] - URL to the agent's avatar image.
517
+ :param description: str - Description of the agent's purpose.
518
+ :param job_description: Optional[str] - Detailed job description of the agent.
519
+ :param is_draft: bool - Indicates if the agent is in draft mode.
520
+ :param is_readonly: bool - Indicates if the agent is read-only.
521
+ :param revision: int - Revision number of the agent.
522
+ :param version: Optional[int] - Version number of the agent, if applicable.
523
+ :param agent_data: AgentData - Detailed configuration data for the agent.
524
+ """
525
+ id: str = Field(None, alias="id")
526
+ status: Optional[Literal["active", "inactive", "pending"]] = Field("active", alias="status")
527
+ name: str = Field(..., alias="name")
528
+ access_scope: Literal["public", "private"] = Field("private", alias="accessScope")
529
+ public_name: Optional[str] = Field(None, alias="publicName")
530
+ avatar_image: Optional[str] = Field(None, alias="avatarImage")
531
+ description: Optional[str] = Field(None, alias="description")
532
+ job_description: Optional[str] = Field(None, alias="jobDescription")
533
+ is_draft: Optional[bool] = Field(True, alias="isDraft")
534
+ is_readonly: Optional[bool] = Field(False, alias="isReadonly")
535
+ revision: Optional[int] = Field(None, alias="revision")
536
+ version: Optional[Union[int | float]] = Field(None, alias="version")
537
+ sharing_scope: Optional[str] = Field(None, alias="sharingScope", description="Sharing scope of the agent")
538
+ permissions: Optional[Permission] = Field(None, alias="permissions", description="Permission settings")
539
+ effective_permissions: Optional[Permission] = Field(None, alias="effectivePermissions", description="Effective permission settings")
540
+ agent_data: Optional[AgentData] = Field(None, alias="agentData")
541
+
542
+ @field_validator("name")
543
+ @classmethod
544
+ def validate_name(cls, value: str) -> str:
545
+ if not value.strip():
546
+ raise ValueError("name cannot be blank")
547
+ if ":" in value or "/" in value:
548
+ raise ValueError("name cannot contain ':' or '/'")
549
+ return value
550
+
551
+ @field_validator("public_name")
552
+ @classmethod
553
+ def validate_public_name_format(cls, value: Optional[str], values: dict) -> Optional[str]:
554
+ access_scope = values.data.get("access_scope", "private")
555
+ if access_scope == "public" and not value:
556
+ raise ValueError("public_name is required if access_scope is 'public'")
557
+ if value and not all(c.isalnum() or c in ".-_" for c in value):
558
+ raise ValueError("public_name must contain only letters, numbers, periods, dashes, or underscores")
559
+ return value
560
+
561
+ @model_validator(mode="after")
562
+ def validate_agent_data_for_publication(self):
563
+ if self.is_draft is False and self.agent_data:
564
+ if not self.agent_data.models or len(self.agent_data.models) == 0:
565
+ raise ValueError("At least one valid model must be provided in agent_data.models for publication")
566
+ # if not (self.agent_data.prompt.instructions or self.agent_data.prompt.context): # TODO -> Review implementation of context vs instructions
567
+ if not self.agent_data.prompt.instructions:
568
+ raise ValueError("agent_data.prompt must have at least instructions for publication")
569
+ return self
570
+
571
+ @field_validator("agent_data", mode="before")
572
+ @classmethod
573
+ def normalize_agent_data(cls, value):
574
+ if isinstance(value, dict):
575
+ return AgentData.model_validate(value)
576
+ return value
577
+
578
+ @field_validator("permissions", mode="before")
579
+ @classmethod
580
+ def normalize_permissions(cls, value):
581
+ if isinstance(value, dict):
582
+ return Permission.model_validate(value)
583
+ return value
584
+
585
+ @field_validator("effective_permissions", mode="before")
586
+ @classmethod
587
+ def normalize_effective_permissions(cls, value):
588
+ if isinstance(value, dict):
589
+ return Permission.model_validate(value)
590
+ return value
591
+
592
+ @model_validator(mode="after")
593
+ def check_public_name(self):
594
+ """
595
+ Validates that public_name is provided if access_scope is set to "public".
596
+
597
+ :raises ValueError: If access_scope is "public" but public_name is missing.
598
+ """
599
+ if self.access_scope == "public" and not self.public_name:
600
+ raise ValueError("public_name is required if access_scope is public")
601
+ return self
602
+
603
+ def to_dict(self):
604
+ result = {
605
+ "id": self.id,
606
+ "status": self.status,
607
+ "name": self.name,
608
+ "accessScope": self.access_scope,
609
+ "publicName": self.public_name,
610
+ "avatarImage": self.avatar_image,
611
+ "description": self.description,
612
+ "jobDescription": self.job_description,
613
+ "isDraft": self.is_draft,
614
+ "isReadonly": self.is_readonly,
615
+ "revision": self.revision,
616
+ "version": self.version,
617
+ "sharingScope": self.sharing_scope,
618
+ "permissions": self.permissions.to_dict() if self.permissions else None,
619
+ "effectivePermissions": self.effective_permissions.to_dict() if self.effective_permissions else None,
620
+ "agentData": self.agent_data.to_dict() if self.agent_data else None
621
+ }
622
+ return {k: v for k, v in result.items() if v is not None}
623
+
624
+ def __str__(self):
625
+ return str(self.to_dict())
626
+
627
+
628
+ class AgentList(CustomBaseModel):
629
+ """
630
+ Represents a list of agents returned by the API.
631
+
632
+ :param agents: List[Agent] - List of agent configurations.
633
+ """
634
+ agents: List[Agent] = Field(..., alias="agents")
635
+
636
+ @field_validator("agents", mode="before")
637
+ @classmethod
638
+ def normalize_agents(cls, value):
639
+ if isinstance(value, list):
640
+ return [Agent.model_validate(item) if isinstance(item, dict) else item for item in value]
641
+ return value
642
+
643
+ def to_list(self):
644
+ return [agent.to_dict() for agent in self.agents] if self.agents else []
645
+
646
+ def __getitem__(self, index: int) -> Agent:
647
+ if self.agents is None:
648
+ raise IndexError("AgentList is empty")
649
+ return self.agents[index]
650
+
651
+ def __len__(self) -> int:
652
+ return len(self.agents) if self.agents else 0
653
+
654
+ def __iter__(self):
655
+ """Make AgentList iterable over its agents."""
656
+ if self.agents is None:
657
+ return iter([])
658
+ return iter(self.agents)
659
+
660
+ def append(self, item: Agent) -> None:
661
+ """Append an Agent instance to the agents list."""
662
+ if self.agents is None:
663
+ self.agents = []
664
+ self.agents.append(item)
665
+
666
+
667
+ class SharingLink(CustomBaseModel):
668
+ """
669
+ Represents a sharing link for an agent.
670
+
671
+ :param agent_id: str - Unique identifier of the agent.
672
+ :param api_token: str - API token associated with the sharing link.
673
+ :param shared_link: str - The full URL of the sharing link.
674
+ """
675
+ agent_id: str = Field(..., alias="agentId", description="Unique identifier of the agent")
676
+ api_token: str = Field(..., alias="apiToken", description="API token associated with the sharing link")
677
+ shared_link: str = Field(..., alias="sharedLink", description="The full URL of the sharing link")
678
+
679
+ def to_dict(self):
680
+ """
681
+ Serializes the SharingLink instance to a dictionary.
682
+
683
+ :return: dict - A dictionary representation of the sharing link with aliases.
684
+ """
685
+ return self.model_dump(by_alias=True, exclude_none=True)
686
+
687
+ def __str__(self):
688
+ return str(self.to_dict())
689
+
690
+
691
+ class ToolParameter(CustomBaseModel):
692
+ """
693
+ Represents a parameter for a tool.
694
+
695
+ :param key: str - The identifier of the parameter.
696
+ :param data_type: str - The data type of the parameter (e.g., "String").
697
+ :param description: str - Description of the parameter's purpose.
698
+ :param is_required: bool - Whether the parameter is required.
699
+ :param type: Optional[str] - Type of parameter (e.g., "config"), defaults to None.
700
+ :param from_secret: Optional[bool] - Whether the value comes from a secret manager, defaults to None.
701
+ :param value: Optional[str] - The static value of the parameter, defaults to None.
702
+ """
703
+ key: str = Field(..., alias="key", description="The identifier of the parameter")
704
+ data_type: str = Field(..., alias="dataType", description="The data type of the parameter (e.g., 'String')")
705
+ description: str = Field(..., alias="description", description="Description of the parameter's purpose")
706
+ is_required: bool = Field(..., alias="isRequired", description="Whether the parameter is required")
707
+ type: Optional[Literal["config", "app", "context"]] = Field("app", alias="type", description="Type of parameter (e.g., 'config')")
708
+ from_secret: Optional[bool] = Field(None, alias="fromSecret", description="Whether the value comes from a secret manager")
709
+ value: Optional[str] = Field(None, alias="value", description="The static value of the parameter")
710
+
711
+ def to_dict(self):
712
+ return self.model_dump(by_alias=True, exclude_none=True)
713
+
714
+ def __str__(self):
715
+ return str(self.to_dict())
716
+
717
+
718
+ class ToolMessage(CustomBaseModel):
719
+ """
720
+ Represents a message (e.g., warning or error) in the tool response.
721
+
722
+ :param description: str - Description of the message.
723
+ :param type: str - Type of the message (e.g., "warning", "error").
724
+ """
725
+ description: str = Field(..., alias="description", description="Description of the message")
726
+ type: str = Field(..., alias="type", description="Type of the message (e.g., 'warning', 'error')")
727
+
728
+ def to_dict(self):
729
+ return self.model_dump(by_alias=True, exclude_none=True)
730
+
731
+ def __str__(self):
732
+ return str(self.to_dict())
733
+
734
+
735
+ class Tool(CustomBaseModel):
736
+ """
737
+ Represents a tool configuration, used for both input and output.
738
+
739
+ :param name: str - The name of the tool.
740
+ :param description: str - Description of the tool's purpose.
741
+ :param scope: str - The scope of the tool (e.g., "builtin", "external", "api").
742
+ :param parameters: List[ToolParameter] - List of parameters required by the tool.
743
+ :param access_scope: Optional[str] - The access scope of the tool ("public" or "private"), defaults to None.
744
+ :param public_name: Optional[str] - Public name of the tool, required if access_scope is "public", defaults to None.
745
+ :param icon: Optional[str] - URL for the tool's icon or avatar, defaults to None.
746
+ :param open_api: Optional[str] - URL where the OpenAPI specification can be loaded, defaults to None.
747
+ :param open_api_json: Optional[dict] - OpenAPI specification as a dictionary, defaults to None.
748
+ :param report_events: Optional[str] - Event reporting mode ("None", "All", "Start", "Finish", "Progress"), defaults to None.
749
+ :param id: Optional[str] - Unique identifier of the tool, defaults to None.
750
+ :param is_draft: Optional[bool] - Whether the tool is in draft mode, defaults to None.
751
+ :param messages: Optional[List[ToolMessage]] - List of messages (e.g., warnings or errors), defaults to None.
752
+ :param revision: Optional[int] - Revision number of the tool, defaults to None.
753
+ :param status: Optional[str] - Current status of the tool (e.g., "active"), defaults to None.
754
+ """
755
+ name: str = Field(..., alias="name", description="The name of the tool")
756
+ description: Optional[str] = Field(None, alias="description", description="Description of the tool's purpose")
757
+ scope: str = Field("builtin", alias="scope", description="The scope of the tool (e.g., 'builtin', 'external', 'api')")
758
+ parameters: Optional[List[ToolParameter]] = Field(None, alias="parameters", description="List of parameters required by the tool")
759
+ access_scope: Optional[str] = Field(None, alias="accessScope", description="The access scope of the tool ('public' or 'private')")
760
+ public_name: Optional[str] = Field(None, alias="publicName", description="Public name of the tool, required if access_scope is 'public'")
761
+ icon: Optional[str] = Field(None, alias="icon", description="URL for the tool's icon or avatar")
762
+ open_api: Optional[str] = Field(None, alias="openApi", description="URL where the OpenAPI specification can be loaded")
763
+ open_api_json: Optional[dict] = Field(None, alias="openApiJson", description="OpenAPI specification as a dictionary")
764
+ report_events: Optional[Literal['None', 'All', 'Start', 'Finish', 'Progress']] = Field("None", alias="reportEvents", description="Event reporting mode ('None', 'All', 'Start', 'Finish', 'Progress')")
765
+ id: Optional[str] = Field(None, alias="id", description="Unique identifier of the tool")
766
+ is_draft: Optional[bool] = Field(None, alias="isDraft", description="Whether the tool is in draft mode")
767
+ messages: Optional[List[ToolMessage]] = Field(None, alias="messages", description="List of messages (e.g., warnings or errors)")
768
+ revision: Optional[int] = Field(None, alias="revision", description="Revision number of the tool")
769
+ status: Optional[str] = Field(None, alias="status", description="Current status of the tool (e.g., 'active')")
770
+
771
+ @field_validator("name")
772
+ @classmethod
773
+ def validate_name(cls, value: str) -> str:
774
+ if not value.strip():
775
+ raise ValueError("name cannot be blank")
776
+ if ":" in value or "/" in value:
777
+ raise ValueError("name cannot contain ':' or '/'")
778
+ # if not re.match(r'^[A-Za-z0-9_-]{1,64}$', value):
779
+ # raise ValueError(
780
+ # "name must contain only letters, numbers, underscores, or hyphens, and be 1-64 characters long")
781
+ return value
782
+
783
+ @field_validator("public_name")
784
+ @classmethod
785
+ def validate_public_name_format(cls, value: Optional[str], values: dict) -> Optional[str]:
786
+ access_scope = values.data.get("access_scope", "private")
787
+ if access_scope == "public" and not value:
788
+ raise ValueError("public_name is required if access_scope is 'public'")
789
+ if value and not all(c.isalnum() or c in ".-_" for c in value):
790
+ raise ValueError("public_name must contain only letters, numbers, periods, dashes, or underscores")
791
+ return value
792
+
793
+ @model_validator(mode="after")
794
+ def check_public_name(self):
795
+ if self.access_scope == "public" and not self.public_name:
796
+ raise ValueError("public_name is required if access_scope is 'public'")
797
+ return self
798
+
799
+ '''
800
+ @model_validator(mode="after")
801
+ def validate_api_tool_requirements(self):
802
+ if self.scope == "api" and not (self.open_api or self.open_api_json):
803
+ raise ValueError("For scope='api', either open_api or open_api_json must be provided")
804
+ if self.parameters:
805
+ param_keys = [p.key for p in self.parameters]
806
+ if len(param_keys) != len(set(param_keys)):
807
+ raise ValueError("All parameter keys must be unique within the tool")
808
+ return self
809
+ '''
810
+
811
+ @field_validator("parameters", mode="before")
812
+ @classmethod
813
+ def normalize_parameters(cls, value):
814
+ if isinstance(value, list):
815
+ return [ToolParameter.model_validate(item) if isinstance(item, dict) else item for item in value]
816
+ return value
817
+
818
+ @field_validator("messages", mode="before")
819
+ @classmethod
820
+ def normalize_messages(cls, value):
821
+ if isinstance(value, list):
822
+ return [ToolMessage.model_validate(item) if isinstance(item, dict) else item for item in value]
823
+ return value
824
+
825
+ def to_dict(self):
826
+ result = {
827
+ "name": self.name,
828
+ "description": self.description,
829
+ "scope": self.scope,
830
+ "parameters": [param.to_dict() for param in self.parameters] if self.parameters else None,
831
+ "accessScope": self.access_scope,
832
+ "publicName": self.public_name,
833
+ "icon": self.icon,
834
+ "openApi": self.open_api,
835
+ "openApiJson": self.open_api_json,
836
+ "reportEvents": self.report_events,
837
+ "id": self.id,
838
+ "isDraft": self.is_draft,
839
+ "messages": [msg.to_dict() for msg in self.messages] if self.messages else None,
840
+ "revision": self.revision,
841
+ "status": self.status
842
+ }
843
+ return {k: v for k, v in result.items() if v is not None}
844
+
845
+ def __str__(self):
846
+ return str(self.to_dict())
847
+
848
+
849
+ class ToolList(CustomBaseModel):
850
+ """
851
+ Represents a list of Tool objects retrieved from an API response.
852
+
853
+ :param tools: List[Tool] - The list of tools.
854
+ """
855
+ tools: List[Tool] = Field(..., alias="tools", description="The list of tools")
856
+
857
+ @field_validator("tools", mode="before")
858
+ @classmethod
859
+ def normalize_tools(cls, value):
860
+ if isinstance(value, list):
861
+ return [Tool.model_validate(item) if isinstance(item, dict) else item for item in value]
862
+ return value
863
+
864
+ def to_dict(self):
865
+ return {"tools": [tool.to_dict() for tool in self.tools]}
866
+
867
+ def __str__(self):
868
+ return str(self.to_dict())
869
+
870
+ def __getitem__(self, index: int) -> Tool:
871
+ if self.tools is None:
872
+ raise IndexError("ToolList is empty")
873
+ return self.tools[index]
874
+
875
+ def __len__(self) -> int:
876
+ return len(self.tools) if self.tools else 0
877
+
878
+ def __iter__(self):
879
+ """Make ToolList iterable over its tools."""
880
+ if self.tools is None:
881
+ return iter([])
882
+ return iter(self.tools)
883
+
884
+ def append(self, item: Tool) -> None:
885
+ """Append a Tool instance to the tools list."""
886
+ if self.tools is None:
887
+ self.tools = []
888
+ self.tools.append(item)
889
+
890
+
891
+ class LocalizedDescription(CustomBaseModel):
892
+ """
893
+ Represents a localized description for a reasoning strategy.
894
+
895
+ :param language: str - The language of the description (e.g., "english", "spanish").
896
+ :param description: str - The description text in the specified language.
897
+ """
898
+ language: str = Field(..., description="The language of the description")
899
+ description: str = Field(..., description="The description text in the specified language")
900
+
901
+ def to_dict(self):
902
+ return self.model_dump(by_alias=True, exclude_none=True)
903
+
904
+
905
+ class ReasoningStrategy(CustomBaseModel):
906
+ """
907
+ Represents a reasoning strategy configuration.
908
+
909
+ :param name: str - The name of the reasoning strategy.
910
+ :param system_prompt: str - The system prompt for the reasoning strategy.
911
+ :param access_scope: str - The access scope of the strategy (e.g., "private", "public").
912
+ :param type: str - The type of the reasoning strategy (e.g., "addendum").
913
+ :param localized_descriptions: List[LocalizedDescription] - List of localized descriptions.
914
+ :param id: Optional[str] - Unique identifier of the strategy, set by the API on creation.
915
+ """
916
+ name: str = Field(..., description="The name of the reasoning strategy")
917
+ system_prompt: Optional[str] = Field(None, alias="systemPrompt", description="The system prompt for the reasoning strategy")
918
+ access_scope: str = Field(..., alias="accessScope", description="The access scope of the strategy (e.g., 'private', 'public')")
919
+ type: str = Field(..., description="The type of the reasoning strategy (e.g., 'addendum')")
920
+ localized_descriptions: Optional[List[LocalizedDescription]] = Field(None, alias="localizedDescriptions", description="List of localized descriptions")
921
+ id: Optional[str] = Field(None, description="Unique identifier of the strategy, set by the API on creation")
922
+
923
+ @field_validator("localized_descriptions", mode="before")
924
+ @classmethod
925
+ def normalize_localized_descriptions(cls, value):
926
+ if isinstance(value, list):
927
+ return [LocalizedDescription.model_validate(item) if isinstance(item, dict) else item for item in value]
928
+ return value
929
+
930
+ def to_dict(self):
931
+ result = {
932
+ "name": self.name,
933
+ "systemPrompt": self.system_prompt,
934
+ "accessScope": self.access_scope,
935
+ "type": self.type,
936
+ "localizedDescriptions": [desc.to_dict() for desc in self.localized_descriptions] if isinstance(self.localized_descriptions, list) else None,
937
+ "id": self.id
938
+ }
939
+ return {k: v for k, v in result.items() if v is not None}
940
+
941
+
942
+ class ReasoningStrategyList(CustomBaseModel):
943
+ strategies: List[ReasoningStrategy] = Field(..., alias="strategies", description="The list of reasoning strategies")
944
+
945
+ @field_validator("strategies", mode="before")
946
+ @classmethod
947
+ def normalize_strategies(cls, value):
948
+ if isinstance(value, list):
949
+ return [ReasoningStrategy.model_validate(item) if isinstance(item, dict) else item for item in value]
950
+ return value
951
+
952
+ def to_dict(self):
953
+ return [strategy.to_dict() for strategy in self.strategies]
954
+
955
+ def __str__(self):
956
+ return str(self.to_dict())
957
+
958
+ def __getitem__(self, index: int) -> ReasoningStrategy:
959
+ if self.strategies is None:
960
+ raise IndexError("ReasoningStrategyList is empty")
961
+ return self.strategies[index]
962
+
963
+ def __len__(self) -> int:
964
+ return len(self.strategies) if self.strategies else 0
965
+
966
+ def __iter__(self):
967
+ """Make ReasoningStrategyList iterable over its strategies."""
968
+ if self.strategies is None:
969
+ return iter([])
970
+ return iter(self.strategies)
971
+
972
+ def append(self, item: ReasoningStrategy) -> None:
973
+ """Append a ReasoningStrategy instance to the strategies list."""
974
+ if self.strategies is None:
975
+ self.strategies = []
976
+ self.strategies.append(item)
977
+
978
+
979
+ class KnowledgeBase(CustomBaseModel):
980
+ id: Optional[str] = Field(None, description="Unique identifier of the knowledge base, set by API")
981
+ name: str = Field(..., description="Name of the knowledge base")
982
+ artifact_type_name: Optional[List[str]] = Field(None, alias="artifactTypeName", description="List of artifact type names")
983
+ artifacts: Optional[List[str]] = Field(None, description="List of artifact identifiers")
984
+ metadata: Optional[List[str]] = Field(None, description="List of metadata identifiers")
985
+ created_at: Optional[str] = Field(None, alias="createdAt", description="Timestamp when the knowledge base was created")
986
+
987
+ @field_validator("artifacts")
988
+ @classmethod
989
+ def validate_artifacts(cls, value: Optional[List[str]]) -> Optional[List[str]]:
990
+ if value is not None:
991
+ for artifact in value:
992
+ if not artifact.strip():
993
+ raise ValueError("Artifact identifiers cannot be empty")
994
+ return value
995
+
996
+ @field_validator("metadata")
997
+ @classmethod
998
+ def validate_metadata(cls, value: Optional[List[str]]) -> Optional[List[str]]:
999
+ if value is not None:
1000
+ for meta in value:
1001
+ if not meta.strip():
1002
+ raise ValueError("Metadata identifiers cannot be empty")
1003
+ return value
1004
+
1005
+ def to_dict(self):
1006
+ return self.model_dump(by_alias=True, exclude_none=True)
1007
+
1008
+
1009
+ class KnowledgeBaseList(CustomBaseModel):
1010
+ knowledge_bases: List[KnowledgeBase] = Field(..., alias="knowledgeBases")
1011
+
1012
+ @field_validator("knowledge_bases", mode="before")
1013
+ @classmethod
1014
+ def normalize_knowledge_bases(cls, value):
1015
+ if isinstance(value, list):
1016
+ return [KnowledgeBase.model_validate(item) if isinstance(item, dict) else item for item in value]
1017
+ return value
1018
+
1019
+ def to_dict(self):
1020
+ return [kb.to_dict() for kb in self.knowledge_bases]
1021
+
1022
+ def __getitem__(self, index: int) -> KnowledgeBase:
1023
+ if self.knowledge_bases is None:
1024
+ raise IndexError("KnowledgeBaseList is empty")
1025
+ return self.knowledge_bases[index]
1026
+
1027
+ def __len__(self) -> int:
1028
+ return len(self.knowledge_bases) if self.knowledge_bases else 0
1029
+
1030
+ def __iter__(self):
1031
+ """Make KnowledgeBaseList iterable over its knowledge bases."""
1032
+ if self.knowledge_bases is None:
1033
+ return iter([])
1034
+ return iter(self.knowledge_bases)
1035
+
1036
+ def append(self, item: KnowledgeBase) -> None:
1037
+ """Append a KnowledgeBase instance to the knowledge_bases list."""
1038
+ if self.knowledge_bases is None:
1039
+ self.knowledge_bases = []
1040
+ self.knowledge_bases.append(item)
1041
+
1042
+
1043
+ class AgenticActivity(CustomBaseModel):
1044
+ key: str = Field(..., description="Unique key for the activity")
1045
+ name: str = Field(..., description="Name of the activity")
1046
+ task_name: str = Field(..., alias="taskName", description="Name of the task")
1047
+ agent_name: str = Field(..., alias="agentName", description="Name of the agent")
1048
+ agent_revision_id: int = Field(..., alias="agentRevisionId", description="Revision ID of the agent")
1049
+ agent_id: Optional[str] = Field(None, alias="agentId", description="Unique identifier of the agent, set by API")
1050
+ task_id: Optional[str] = Field(None, alias="taskId", description="Unique identifier of the task, set by API")
1051
+ task_revision_id: Optional[int] = Field(None, alias="taskRevisionId", description="Revision ID of the task, set by API")
1052
+
1053
+ def to_dict(self):
1054
+ return self.model_dump(by_alias=True, exclude_none=True)
1055
+
1056
+
1057
+ class ArtifactSignal(CustomBaseModel):
1058
+ key: str = Field(..., description="Unique key for the artifact signal")
1059
+ name: str = Field(..., description="Name of the artifact signal")
1060
+ handling_type: str = Field(..., alias="handlingType", description="Handling type (e.g., 'C')")
1061
+ artifact_type_name: List[str] = Field(..., alias="artifactTypeName", description="List of artifact type names")
1062
+
1063
+ def to_dict(self):
1064
+ return self.model_dump(by_alias=True, exclude_none=True)
1065
+
1066
+
1067
+ class UserSignal(CustomBaseModel):
1068
+ key: str = Field(..., description="Unique key for the user signal")
1069
+ name: str = Field(..., description="Name of the user signal")
1070
+
1071
+ def to_dict(self):
1072
+ return self.model_dump(by_alias=True, exclude_none=True)
1073
+
1074
+
1075
+ class Event(CustomBaseModel):
1076
+ key: str = Field(..., description="Unique key for the event")
1077
+ name: str = Field(..., description="Name of the event")
1078
+
1079
+ def to_dict(self):
1080
+ return self.model_dump(by_alias=True, exclude_none=True)
1081
+
1082
+
1083
+ class SequenceFlow(CustomBaseModel):
1084
+ key: str = Field(..., description="Unique key for the sequence flow")
1085
+ source_key: str = Field(..., alias="sourceKey", description="Key of the source event/activity/signal")
1086
+ target_key: str = Field(..., alias="targetKey", description="Key of the target event/activity/signal")
1087
+
1088
+ def to_dict(self):
1089
+ return self.model_dump(by_alias=True, exclude_none=True)
1090
+
1091
+
1092
+ class Variable(CustomBaseModel):
1093
+ key: str = Field(..., description="Key of the variable")
1094
+ value: str = Field(..., description="Value of the variable")
1095
+
1096
+ def to_dict(self):
1097
+ return self.model_dump(by_alias=True, exclude_none=True)
1098
+
1099
+
1100
+ class VariableList(CustomBaseModel):
1101
+ variables: Optional[List[Variable]] = Field(None, description="List of variables")
1102
+
1103
+ @field_validator("variables", mode="before")
1104
+ @classmethod
1105
+ def normalize_variables(cls, value):
1106
+ if isinstance(value, list):
1107
+ return [Variable.model_validate(item) if isinstance(item, dict) else item for item in value]
1108
+ return value
1109
+
1110
+ def to_dict(self):
1111
+ return [var.to_dict() for var in self.variables] if self.variables else None
1112
+
1113
+ def __getitem__(self, index: int) -> Variable:
1114
+ if self.variables is None:
1115
+ raise IndexError("VariableList is empty")
1116
+ return self.variables[index]
1117
+
1118
+ def __len__(self) -> int:
1119
+ return len(self.variables) if self.variables else 0
1120
+
1121
+ def __iter__(self) -> Iterator[Variable]:
1122
+ """Make VariableList iterable over its variables."""
1123
+ if self.variables is None:
1124
+ return iter([])
1125
+ return iter(self.variables)
1126
+
1127
+ def append(self, item: Variable) -> None:
1128
+ """Append a Variable instance to the variables list."""
1129
+ if self.variables is None:
1130
+ self.variables = []
1131
+ self.variables.append(item)
1132
+
1133
+
1134
+ class AgenticProcess(CustomBaseModel):
1135
+ key: Optional[str] = Field(None, description="Unique key for the process")
1136
+ name: str = Field(..., description="Name of the process")
1137
+ description: Optional[str] = Field(None, description="Description of the process")
1138
+ kb: Optional[KnowledgeBase] = Field(None, description="Knowledge base configuration")
1139
+ agentic_activities: Optional[List[AgenticActivity]] = Field(None, alias="agenticActivities", description="List of agentic activities")
1140
+ artifact_signals: Optional[List[ArtifactSignal]] = Field(None, alias="artifactSignals", description="List of artifact signals")
1141
+ user_signals: Optional[List[UserSignal]] = Field(None, alias="userSignals", description="List of user signals")
1142
+ start_event: Optional[Event] = Field(None, alias="startEvent", description="Start event of the process")
1143
+ end_event: Optional[Event] = Field(None, alias="endEvent", description="End event of the process")
1144
+ sequence_flows: Optional[List[SequenceFlow]] = Field(None, alias="sequenceFlows", description="List of sequence flows")
1145
+ variables: Optional[VariableList] = Field(None, alias="variables", description="List of variables")
1146
+ id: Optional[str] = Field(None, description="Unique identifier of the process, set by API")
1147
+ status: Optional[str] = Field(None, alias="status", description="Status of the process (e.g., 'active')")
1148
+ version_id: Optional[int] = Field(None, alias="versionId", description="Version ID of the process")
1149
+ is_draft: Optional[bool] = Field(None, alias="isDraft", description="Whether the process is a draft")
1150
+ revision: Optional[int] = Field(None, description="Revision number of the process")
1151
+
1152
+ @field_validator("name")
1153
+ @classmethod
1154
+ def validate_name(cls, value: str) -> str:
1155
+ if not value.strip():
1156
+ raise ValueError("name cannot be blank")
1157
+ if ":" in value or "/" in value:
1158
+ raise ValueError("name cannot contain ':' or '/'")
1159
+ return value
1160
+
1161
+ @field_validator("kb", mode="before")
1162
+ @classmethod
1163
+ def normalize_kb(cls, value):
1164
+ if isinstance(value, dict):
1165
+ return KnowledgeBase.model_validate(value)
1166
+ return value
1167
+
1168
+ @field_validator("agentic_activities", mode="before")
1169
+ @classmethod
1170
+ def normalize_agentic_activities(cls, value):
1171
+ if isinstance(value, list):
1172
+ return [AgenticActivity.model_validate(item) if isinstance(item, dict) else item for item in value]
1173
+ return value
1174
+
1175
+ @field_validator("artifact_signals", mode="before")
1176
+ @classmethod
1177
+ def normalize_artifact_signals(cls, value):
1178
+ if isinstance(value, list):
1179
+ return [ArtifactSignal.model_validate(item) if isinstance(item, dict) else item for item in value]
1180
+ return value
1181
+
1182
+ @field_validator("user_signals", mode="before")
1183
+ @classmethod
1184
+ def normalize_user_signals(cls, value):
1185
+ if isinstance(value, list):
1186
+ return [UserSignal.model_validate(item) if isinstance(item, dict) else item for item in value]
1187
+ return value
1188
+
1189
+ @field_validator("start_event", mode="before")
1190
+ @classmethod
1191
+ def normalize_start_event(cls, value):
1192
+ if isinstance(value, dict):
1193
+ return Event.model_validate(value)
1194
+ return value
1195
+
1196
+ @field_validator("end_event", mode="before")
1197
+ @classmethod
1198
+ def normalize_end_event(cls, value):
1199
+ if isinstance(value, dict):
1200
+ return Event.model_validate(value)
1201
+ return value
1202
+
1203
+ @field_validator("sequence_flows", mode="before")
1204
+ @classmethod
1205
+ def normalize_sequence_flows(cls, value):
1206
+ if isinstance(value, list):
1207
+ return [SequenceFlow.model_validate(item) if isinstance(item, dict) else item for item in value]
1208
+ return value
1209
+
1210
+ @field_validator("variables", mode="before")
1211
+ @classmethod
1212
+ def normalize_variables(cls, value):
1213
+ """
1214
+ Normalizes the variables input to a VariableList instance.
1215
+
1216
+ :param value: Union[VariableList, List[Variable]] - The input value for variables.
1217
+ :return: VariableList - A VariableList instance containing the models.
1218
+ """
1219
+ if isinstance(value, VariableList):
1220
+ return value
1221
+ elif isinstance(value, (list, tuple)):
1222
+ return VariableList(variables=[Variable.model_validate(item) if isinstance(item, dict) else item for item in value])
1223
+ elif value is None:
1224
+ return VariableList(variables=[])
1225
+
1226
+ raise ValueError("variables must be a VariableList or a list of Variable instances")
1227
+
1228
+ def to_dict(self):
1229
+ """
1230
+ Serializes the AgenticProcess instance to a dictionary, explicitly mapping fields to their aliases
1231
+ and invoking to_dict for nested objects in lists.
1232
+
1233
+ :return: dict - A dictionary representation of the process with aliases, excluding None values.
1234
+ """
1235
+ result = {
1236
+ "key": self.key,
1237
+ "name": self.name,
1238
+ "description": self.description,
1239
+ "kb": self.kb.to_dict() if self.kb else None,
1240
+ "agenticActivities": [activity.to_dict() for activity in self.agentic_activities] if self.agentic_activities else None,
1241
+ "artifactSignals": [signal.to_dict() for signal in self.artifact_signals] if self.artifact_signals else None,
1242
+ "userSignals": [signal.to_dict() for signal in self.user_signals] if self.user_signals else None,
1243
+ "startEvent": self.start_event.to_dict() if self.start_event else None,
1244
+ "endEvent": self.end_event.to_dict() if self.end_event else None,
1245
+ "sequenceFlows": [flow.to_dict() for flow in self.sequence_flows] if self.sequence_flows else None,
1246
+ "variables": self.variables.to_dict() if self.variables else None,
1247
+ "id": self.id,
1248
+ "status": self.status,
1249
+ "versionId": self.version_id,
1250
+ "isDraft": self.is_draft,
1251
+ "revision": self.revision
1252
+ }
1253
+ return {k: v for k, v in result.items() if v is not None}
1254
+
1255
+
1256
+ class ArtifactType(CustomBaseModel):
1257
+ """
1258
+ Represents an artifact type configuration for a task.
1259
+
1260
+ :param name: str - Name of the artifact type.
1261
+ :param description: str - Description of the artifact type.
1262
+ :param is_required: bool - Whether the artifact is required.
1263
+ :param usage_type: str - Usage type of the artifact (e.g., 'input', 'output').
1264
+ :param artifact_variable_key: str - Variable key for the artifact in the task.
1265
+ """
1266
+ name: str = Field(..., alias="name", description="Name of the artifact type")
1267
+ description: Optional[str] = Field(None, alias="description", description="Description of the artifact type")
1268
+ is_required: Optional[bool] = Field(False, alias="isRequired", description="Whether the artifact is required")
1269
+ usage_type: str = Field(..., alias="usageType", description="Usage type of the artifact (e.g., 'input', 'output')")
1270
+ artifact_variable_key: Optional[str] = Field(None, alias="artifactVariableKey", description="Variable key for the artifact in the task")
1271
+
1272
+ def to_dict(self):
1273
+ """
1274
+ Serializes the ArtifactType instance to a dictionary.
1275
+
1276
+ :return: dict - A dictionary representation of the artifact type with aliases.
1277
+ """
1278
+ return self.model_dump(by_alias=True, exclude_none=True)
1279
+
1280
+
1281
+ class ArtifactTypeList(CustomBaseModel):
1282
+ """
1283
+ Represents a list of ArtifactType objects.
1284
+
1285
+ :param artifact_types: List[ArtifactType] - The list of artifact types.
1286
+ """
1287
+ artifact_types: Optional[List[ArtifactType]] = Field(None, description="List of artifact types")
1288
+
1289
+ @field_validator("artifact_types", mode="before")
1290
+ @classmethod
1291
+ def normalize_artifact_types(cls, value):
1292
+ if isinstance(value, list):
1293
+ return [ArtifactType.model_validate(item) if isinstance(item, dict) else item for item in value]
1294
+ return value
1295
+
1296
+ def to_dict(self):
1297
+ """
1298
+ Serializes the ArtifactTypeList instance to a list of dictionaries.
1299
+
1300
+ :return: List[dict] - A list of dictionary representations of the artifact types.
1301
+ """
1302
+ return [artifact.to_dict() for artifact in self.artifact_types] if self.artifact_types else None
1303
+
1304
+ def __getitem__(self, index: int) -> ArtifactType:
1305
+ if self.artifact_types is None:
1306
+ raise IndexError("ArtifactTypeList is empty")
1307
+ return self.artifact_types[index]
1308
+
1309
+ def __len__(self) -> int:
1310
+ return len(self.artifact_types) if self.artifact_types else 0
1311
+
1312
+ def __iter__(self) -> Iterator[ArtifactType]:
1313
+ """Make ArtifactTypeList iterable over its artifact_types."""
1314
+ if self.artifact_types is None:
1315
+ return iter([])
1316
+ return iter(self.artifact_types)
1317
+
1318
+ def append(self, item: ArtifactType) -> None:
1319
+ """Append an ArtifactType instance to the artifact_types list."""
1320
+ if self.artifact_types is None:
1321
+ self.artifact_types = []
1322
+ self.artifact_types.append(item)
1323
+
1324
+
1325
+ class Task(CustomBaseModel):
1326
+ """
1327
+ Represents a task configuration used for both input and output.
1328
+
1329
+ :param name: str - Required name of the task, must be unique within the project and exclude ':' or '/'.
1330
+ :param description: Optional[str] - Description of what the task does, for user understanding (not used by agents).
1331
+ :param title_template: Optional[str] - Template for naming task instances (e.g., 'specs for {{issue}}').
1332
+ :param id: Optional[str] - Unique identifier of the task, set by API or provided in insert mode for custom ID.
1333
+ :param prompt_data: Optional[Prompt] - Prompt configuration (same structure as AgentData prompt), combined with agent prompt during execution.
1334
+ :param artifact_types: Optional[List[dict]] - List of artifact types with 'name', 'description', 'isRequired', 'usageType', and 'artifactVariableKey'.
1335
+ :param is_draft: Optional[bool] - Whether the task is in draft mode.
1336
+ :param revision: Optional[int] - Revision number of the task.
1337
+ :param version: Optional[int] - Version number of the task.
1338
+ :param status: Optional[str] - Current status of the task (e.g., 'active').
1339
+ """
1340
+ name: str = Field(..., description="Name of the task")
1341
+ description: Optional[str] = Field(None, description="Description of the task")
1342
+ title_template: Optional[str] = Field(None, alias="titleTemplate", description="Title template for the task")
1343
+ id: Optional[str] = Field(None, description="Unique identifier of the task, set by API")
1344
+ prompt_data: Optional[Prompt] = Field(None, alias="promptData", description="Prompt configuration for the task, combined with agent prompt during execution")
1345
+ artifact_types: Optional[Union[List[Dict[str, Any]], List[ArtifactType], ArtifactTypeList]] = Field(None, alias="artifactTypes", description="List of artifact types for the task")
1346
+ is_draft: Optional[bool] = Field(None, alias="isDraft", description="Whether the task is a draft")
1347
+ revision: Optional[int] = Field(None, description="Revision number of the task")
1348
+ version: Optional[int] = Field(None, description="Version number of the task")
1349
+ status: Optional[str] = Field(None, description="Status of the task (e.g., 'active')")
1350
+
1351
+ @field_validator("name")
1352
+ @classmethod
1353
+ def validate_name(cls, value: str) -> str:
1354
+ """
1355
+ Ensures the task name does not contain forbidden characters ':' or '/'.
1356
+
1357
+ :param value: str - The name to validate.
1358
+ :return: str - The validated name.
1359
+ :raises ValueError: If the name contains ':' or '/'.
1360
+ """
1361
+ if not value.strip():
1362
+ raise ValueError("name cannot be blank")
1363
+ if ":" in value or "/" in value:
1364
+ raise ValueError("Task name cannot contain ':' or '/'")
1365
+ return value
1366
+
1367
+ @field_validator("prompt_data", mode="before")
1368
+ @classmethod
1369
+ def normalize_prompt_data(cls, value: Union[Prompt, Dict[str, Any], None]) -> Optional[Prompt]:
1370
+ """
1371
+ Normalizes the prompt_data input to a Prompt instance.
1372
+
1373
+ :param value: Union[Prompt, Dict[str, Any], None] - The input value for prompt_data.
1374
+ :return: Optional[Prompt] - A Prompt instance or None if the input is None.
1375
+ :raises ValueError: If the value is neither a Prompt, dict, nor None.
1376
+ """
1377
+ if isinstance(value, Prompt):
1378
+ return value
1379
+ elif isinstance(value, dict):
1380
+ return Prompt.model_validate(value)
1381
+ elif value is None:
1382
+ return None
1383
+ raise ValueError("prompt_data must be a Prompt instance, a dictionary, or None")
1384
+
1385
+ @field_validator("artifact_types", mode="before")
1386
+ @classmethod
1387
+ def normalize_artifact_types(cls, value: Union[List[Dict[str, Any]], List[ArtifactType], ArtifactTypeList, None]) -> Optional[ArtifactTypeList]:
1388
+ """
1389
+ Normalizes the artifact_types input to an ArtifactTypeList instance.
1390
+
1391
+ :param value: Union[List[Dict[str, Any]], List[ArtifactType], ArtifactTypeList, None] - The input value for artifact_types.
1392
+ :return: Optional[ArtifactTypeList] - An ArtifactTypeList instance or None if the input is None.
1393
+ :raises ValueError: If the value is not a valid input type.
1394
+ """
1395
+ if isinstance(value, ArtifactTypeList):
1396
+ return value
1397
+ elif isinstance(value, list):
1398
+ artifact_list = []
1399
+ for item in value:
1400
+ if isinstance(item, dict):
1401
+ artifact_list.append(ArtifactType.model_validate(item))
1402
+ elif isinstance(item, ArtifactType):
1403
+ artifact_list.append(item)
1404
+ else:
1405
+ raise ValueError("artifact_types list items must be dictionaries or ArtifactType instances")
1406
+ return ArtifactTypeList(artifact_types=artifact_list)
1407
+ elif value is None:
1408
+ return None
1409
+ raise ValueError("artifact_types must be an ArtifactTypeList, a list of dictionaries/ArtifactType, or None")
1410
+
1411
+ @model_validator(mode="after")
1412
+ def validate_artifact_types_constraints(self):
1413
+ if self.artifact_types and self.artifact_types.artifact_types:
1414
+ for artifact in self.artifact_types.artifact_types:
1415
+ if artifact.artifact_variable_key and len(artifact.artifact_variable_key) > 20:
1416
+ raise ValueError(
1417
+ f"artifactVariableKey '{artifact.artifact_variable_key}' must be 20 characters or less")
1418
+ if artifact.usage_type not in ["input", "output"]:
1419
+ raise ValueError(f"usageType must be 'input' or 'output', got '{artifact.usage_type}'")
1420
+ return self
1421
+
1422
+ def to_dict(self):
1423
+ """
1424
+ Serializes the Task instance to a dictionary, using aliases and excluding None values.
1425
+
1426
+ :return: dict - A dictionary representation of the task configuration.
1427
+ """
1428
+ result = {
1429
+ "name": self.name,
1430
+ "description": self.description,
1431
+ "titleTemplate": self.title_template,
1432
+ "id": self.id,
1433
+ "promptData": self.prompt_data.to_dict() if self.prompt_data else None,
1434
+ "artifactTypes": self.artifact_types.to_dict() if self.artifact_types else None,
1435
+ "isDraft": self.is_draft,
1436
+ "revision": self.revision,
1437
+ "version": self.version,
1438
+ "status": self.status
1439
+ }
1440
+ return {k: v for k, v in result.items() if v is not None}
1441
+
1442
+ def __str__(self):
1443
+ return str(self.to_dict())
1444
+
1445
+
1446
+ class AgenticProcessList(CustomBaseModel):
1447
+ processes: List[AgenticProcess] = Field(..., alias="processes", description="List of agentic processes")
1448
+
1449
+ @field_validator("processes", mode="before")
1450
+ @classmethod
1451
+ def normalize_processes(cls, value):
1452
+ if isinstance(value, list):
1453
+ return [AgenticProcess.model_validate(item) if isinstance(item, dict) else item for item in value]
1454
+ return value
1455
+
1456
+ def to_dict(self):
1457
+ return {"processes": [process.to_dict() for process in self.processes]}
1458
+
1459
+ def __getitem__(self, index: int) -> AgenticProcess:
1460
+ if self.processes is None:
1461
+ raise IndexError("AgenticProcessList is empty")
1462
+ return self.processes[index]
1463
+
1464
+ def __len__(self) -> int:
1465
+ return len(self.processes) if self.processes else 0
1466
+
1467
+ def __iter__(self):
1468
+ """Make AgenticProcessList iterable over its processes."""
1469
+ if self.processes is None:
1470
+ return iter([])
1471
+ return iter(self.processes)
1472
+
1473
+ def append(self, item: AgenticProcess) -> None:
1474
+ """Append an AgenticProcess instance to the processes list."""
1475
+ if self.processes is None:
1476
+ self.processes = []
1477
+ self.processes.append(item)
1478
+
1479
+
1480
+ class TaskList(CustomBaseModel):
1481
+ tasks: List[Task] = Field(..., alias="tasks", description="List of tasks")
1482
+
1483
+ @field_validator("tasks", mode="before")
1484
+ @classmethod
1485
+ def normalize_tasks(cls, value):
1486
+ if isinstance(value, list):
1487
+ return [Task.model_validate(item) if isinstance(item, dict) else item for item in value]
1488
+ return value
1489
+
1490
+ def to_dict(self):
1491
+ return [task.to_dict() for task in self.tasks]
1492
+
1493
+ def __getitem__(self, index: int) -> Task:
1494
+ if self.tasks is None:
1495
+ raise IndexError("TaskList is empty")
1496
+ return self.tasks[index]
1497
+
1498
+ def __len__(self) -> int:
1499
+ return len(self.tasks) if self.tasks else 0
1500
+
1501
+ def __iter__(self):
1502
+ """Make TaskList iterable over its tasks."""
1503
+ if self.tasks is None:
1504
+ return iter([])
1505
+ return iter(self.tasks)
1506
+
1507
+ def append(self, item: Task) -> None:
1508
+ """Append a Task instance to the tasks list."""
1509
+ if self.tasks is None:
1510
+ self.tasks = []
1511
+ self.tasks.append(item)
1512
+
1513
+
1514
+ class ProcessInstance(CustomBaseModel):
1515
+ id: Optional[str] = Field(None, alias="id", description="Unique identifier of the process instance, set by API")
1516
+ process: AgenticProcess = Field(..., alias="process", description="The process configuration")
1517
+ created_at: Optional[str] = Field(None, alias="createdAt", description="Timestamp when the instance was created")
1518
+ subject: str = Field(..., description="Subject of the instance")
1519
+ variables: Optional[Union[List[Variable] | VariableList]] = Field(None, alias="variables", description="List of instance variables")
1520
+ status: Optional[str] = Field(None, description="Status of the instance (e.g., 'active', 'completed')")
1521
+
1522
+ @field_validator("process", mode="before")
1523
+ @classmethod
1524
+ def normalize_process(cls, value):
1525
+ """
1526
+ Normalizes the process input to an AgenticProcess instance if it's a dictionary.
1527
+
1528
+ :param value: The input value for process (dict or AgenticProcess).
1529
+ :return: AgenticProcess - An AgenticProcess instance.
1530
+ :raises ValueError: If the value is neither a dict nor an AgenticProcess.
1531
+ """
1532
+ if isinstance(value, dict):
1533
+ return AgenticProcess.model_validate(value)
1534
+ elif isinstance(value, AgenticProcess):
1535
+ return value
1536
+ raise ValueError("process must be a dictionary or an AgenticProcess instance")
1537
+
1538
+ @field_validator("variables", mode="before")
1539
+ @classmethod
1540
+ def normalize_variables(cls, value):
1541
+ """
1542
+ Normalizes the variables input to a VariableList instance.
1543
+
1544
+ :param value: Union[VariableList, List[Variable]] - The input value for variables.
1545
+ :return: VariableList - A VariableList instance containing the models.
1546
+ """
1547
+ if isinstance(value, VariableList):
1548
+ return value
1549
+ elif isinstance(value, (list, tuple)):
1550
+ return VariableList(variables=[Variable.model_validate(item) if isinstance(item, dict) else item for item in value])
1551
+ elif value is None:
1552
+ return VariableList(variables=[])
1553
+
1554
+ raise ValueError("variables must be a VariableList or a list of Variable instances")
1555
+
1556
+ def to_dict(self):
1557
+ result = {
1558
+ "id": self.id,
1559
+ "process": self.process.to_dict() if self.process else None,
1560
+ "createdAt": self.created_at,
1561
+ "subject": self.subject,
1562
+ "variables": self.variables.to_dict() if self.variables else None,
1563
+ "status": self.status,
1564
+ }
1565
+ return {k: v for k, v in result.items() if v is not None}
1566
+
1567
+
1568
+ class ProcessInstanceList(CustomBaseModel):
1569
+ instances: List[ProcessInstance] = Field(..., alias="instances", description="List of process instances")
1570
+
1571
+ @field_validator("instances", mode="before")
1572
+ @classmethod
1573
+ def normalize_instances(cls, value):
1574
+ if isinstance(value, list):
1575
+ return [ProcessInstance.model_validate(item) if isinstance(item, dict) else item for item in value]
1576
+ return value
1577
+
1578
+ def to_dict(self):
1579
+ return [instance.to_dict() for instance in self.instances] if self.instances else None
1580
+
1581
+ def __getitem__(self, index: int) -> ProcessInstance:
1582
+ if self.instances is None:
1583
+ raise IndexError("ProcessInstanceList is empty")
1584
+ return self.instances[index]
1585
+
1586
+ def __len__(self) -> int:
1587
+ return len(self.instances) if self.instances else 0
1588
+
1589
+ def __iter__(self):
1590
+ """Make ProcessInstanceList iterable over its instances."""
1591
+ if self.instances is None:
1592
+ return iter([])
1593
+ return iter(self.instances)
1594
+
1595
+ def append(self, item: ProcessInstance) -> None:
1596
+ """Append a ProcessInstance instance to the instances list."""
1597
+ if self.instances is None:
1598
+ self.instances = []
1599
+ self.instances.append(item)
1600
+
1601
+
1602
+ class JobParameter(CustomBaseModel):
1603
+ """
1604
+ Represents a parameter for a job.
1605
+
1606
+ :param Name: str - The name of the parameter.
1607
+ :param Value: str - The value of the parameter.
1608
+ """
1609
+ Name: str = Field(..., alias="Name", description="The name of the parameter")
1610
+ Value: str = Field(..., alias="Value", description="The value of the parameter")
1611
+
1612
+ @field_validator("Name")
1613
+ @classmethod
1614
+ def validate_name(cls, value: str) -> str:
1615
+ if not value.strip():
1616
+ raise ValueError("Parameter name cannot be blank")
1617
+ return value
1618
+
1619
+ def to_dict(self):
1620
+ return self.model_dump(by_alias=True, exclude_none=True)
1621
+
1622
+ def __str__(self):
1623
+ return str(self.to_dict())
1624
+
1625
+
1626
+ class Job(CustomBaseModel):
1627
+ """
1628
+ Represents a single job configuration returned by the API.
1629
+
1630
+ :param caption: str - Description of the job's status and completion time.
1631
+ :param name: str - Name of the job (e.g., 'execute_workitem_jobrunner', 'publish_artifact').
1632
+ :param parameters: List[JobParameter] - List of parameters for the job.
1633
+ :param request: str - Timestamp when the job was requested.
1634
+ :param token: str - Unique token identifier for the job.
1635
+ :param topic: str - Topic associated with the job (e.g., 'Default', 'Event').
1636
+ :param info: Optional[str] - Additional information, typically for failed jobs.
1637
+ """
1638
+ caption: str = Field(..., alias="caption", description="Description of the job's status and completion time")
1639
+ name: str = Field(..., alias="name", description="Name of the job")
1640
+ parameters: Optional[List[JobParameter]] = Field([], alias="parameters", description="List of parameters for the job")
1641
+ request: str = Field(..., alias="request", description="Timestamp when the job was requested")
1642
+ token: str = Field(..., alias="token", description="Unique token identifier for the job")
1643
+ topic: str = Field(..., alias="topic", description="Topic associated with the job")
1644
+ info: Optional[str] = Field(None, alias="info", description="Additional information, typically for failed jobs")
1645
+
1646
+ @field_validator("name")
1647
+ @classmethod
1648
+ def validate_name(cls, value: str) -> str:
1649
+ if not value.strip():
1650
+ raise ValueError("Job name cannot be blank")
1651
+ return value
1652
+
1653
+ @field_validator("token")
1654
+ @classmethod
1655
+ def validate_token(cls, value: str) -> str:
1656
+ if not value.strip():
1657
+ raise ValueError("Token cannot be blank")
1658
+ return value
1659
+
1660
+ @field_validator("parameters", mode="before")
1661
+ @classmethod
1662
+ def normalize_parameters(cls, value):
1663
+ if isinstance(value, list):
1664
+ return [JobParameter.model_validate(item) if isinstance(item, dict) else item for item in value]
1665
+ return value
1666
+
1667
+ def to_dict(self):
1668
+ result = {
1669
+ "caption": self.caption,
1670
+ "name": self.name,
1671
+ "parameters": [param.to_dict() for param in self.parameters] if self.parameters else [],
1672
+ "request": self.request,
1673
+ "token": self.token,
1674
+ "topic": self.topic,
1675
+ "info": self.info
1676
+ }
1677
+ return {k: v for k, v in result.items() if v is not None}
1678
+
1679
+ def __str__(self):
1680
+ return str(self.to_dict())
1681
+
1682
+
1683
+ class JobList(CustomBaseModel):
1684
+ """
1685
+ Represents a list of jobs returned by the API.
1686
+
1687
+ :param jobs: List[Job] - List of job configurations.
1688
+ """
1689
+ jobs: List[Job] = Field(..., alias="jobs", description="List of job configurations")
1690
+
1691
+ @field_validator("jobs", mode="before")
1692
+ @classmethod
1693
+ def normalize_jobs(cls, value):
1694
+ if isinstance(value, list):
1695
+ return [Job.model_validate(item) if isinstance(item, dict) else item for item in value]
1696
+ return value
1697
+
1698
+ def to_dict(self):
1699
+ return [job.to_dict() for job in self.jobs]
1700
+
1701
+ def __getitem__(self, index: int) -> Job:
1702
+ if self.jobs is None:
1703
+ raise IndexError("JobList is empty")
1704
+ return self.jobs[index]
1705
+
1706
+ def __len__(self) -> int:
1707
+ return len(self.jobs) if self.jobs else 0
1708
+
1709
+ def __iter__(self):
1710
+ """Make JobList iterable over its jobs."""
1711
+ if self.jobs is None:
1712
+ return iter([])
1713
+ return iter(self.jobs)
1714
+
1715
+ def append(self, item: Job) -> None:
1716
+ """Append a Job instance to the jobs list."""
1717
+ if self.jobs is None:
1718
+ self.jobs = []
1719
+ self.jobs.append(item)