gumloop 0.5.3__tar.gz → 0.5.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. {gumloop-0.5.3 → gumloop-0.5.4}/PKG-INFO +1 -1
  2. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/_version.py +1 -1
  3. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/agents.py +231 -6
  4. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/types.py +333 -8
  5. {gumloop-0.5.3 → gumloop-0.5.4}/tests/integration/test_live.py +11 -7
  6. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_agents.py +290 -2
  7. {gumloop-0.5.3 → gumloop-0.5.4}/.env.example +0 -0
  8. {gumloop-0.5.3 → gumloop-0.5.4}/.github/workflows/ci.yml +0 -0
  9. {gumloop-0.5.3 → gumloop-0.5.4}/.github/workflows/release.yml +0 -0
  10. {gumloop-0.5.3 → gumloop-0.5.4}/.gitignore +0 -0
  11. {gumloop-0.5.3 → gumloop-0.5.4}/.pre-commit-config.yaml +0 -0
  12. {gumloop-0.5.3 → gumloop-0.5.4}/.python-version +0 -0
  13. {gumloop-0.5.3 → gumloop-0.5.4}/LICENSE +0 -0
  14. {gumloop-0.5.3 → gumloop-0.5.4}/README.md +0 -0
  15. {gumloop-0.5.3 → gumloop-0.5.4}/pyproject.toml +0 -0
  16. {gumloop-0.5.3 → gumloop-0.5.4}/scripts/check +0 -0
  17. {gumloop-0.5.3 → gumloop-0.5.4}/scripts/fmt +0 -0
  18. {gumloop-0.5.3 → gumloop-0.5.4}/scripts/import-logins.sh +0 -0
  19. {gumloop-0.5.3 → gumloop-0.5.4}/scripts/install.sh +0 -0
  20. {gumloop-0.5.3 → gumloop-0.5.4}/scripts/sdk_examples.py +0 -0
  21. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/__init__.py +0 -0
  22. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/_auth.py +0 -0
  23. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/_client.py +0 -0
  24. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/_gumcp_transport.py +0 -0
  25. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/_http.py +0 -0
  26. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/brain_sync.py +0 -0
  27. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/browser_logins/__init__.py +0 -0
  28. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/browser_logins/chromium_cookies.py +0 -0
  29. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/browser_logins/discovery.py +0 -0
  30. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/browser_logins/extract.py +0 -0
  31. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/browser_logins/filter.py +0 -0
  32. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/browser_logins/firefox_cookies.py +0 -0
  33. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/__init__.py +0 -0
  34. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/__init__.py +0 -0
  35. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/_args_input.py +0 -0
  36. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/_downloads.py +0 -0
  37. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/_sync_output.py +0 -0
  38. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/agents.py +0 -0
  39. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/artifacts.py +0 -0
  40. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/auth.py +0 -0
  41. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/brain.py +0 -0
  42. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/browser.py +0 -0
  43. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/chat.py +0 -0
  44. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/evaluations.py +0 -0
  45. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/mcp.py +0 -0
  46. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/models.py +0 -0
  47. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/plugin.py +0 -0
  48. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/sessions.py +0 -0
  49. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/skills.py +0 -0
  50. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/sync.py +0 -0
  51. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/commands/update.py +0 -0
  52. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/console.py +0 -0
  53. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/context.py +0 -0
  54. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/credentials.py +0 -0
  55. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/errors.py +0 -0
  56. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/main.py +0 -0
  57. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/oauth.py +0 -0
  58. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/plugin_assets/gumloop/plugin.json +0 -0
  59. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/plugin_assets/gumloop/skills/gumloop-cli/SKILL.md +0 -0
  60. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/cli/plugin_assets/gumloop/skills/gumloop-cli/references/commands.md +0 -0
  61. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/errors.py +0 -0
  62. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/oauth.py +0 -0
  63. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/py.typed +0 -0
  64. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/__init__.py +0 -0
  65. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/artifacts.py +0 -0
  66. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/brain.py +0 -0
  67. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/browser_profiles.py +0 -0
  68. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/chat.py +0 -0
  69. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/decisions.py +0 -0
  70. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/evaluations.py +0 -0
  71. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/mcp.py +0 -0
  72. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/organizations.py +0 -0
  73. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/sessions.py +0 -0
  74. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/skills.py +0 -0
  75. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/sync.py +0 -0
  76. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/resources/teams.py +0 -0
  77. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/spec/__init__.py +0 -0
  78. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/spec/_compat.py +0 -0
  79. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/spec/_decisions.py +0 -0
  80. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/spec/_extensions.py +0 -0
  81. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/__init__.py +0 -0
  82. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/archive.py +0 -0
  83. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/bundle.py +0 -0
  84. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/bundle_validation.py +0 -0
  85. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/errors.py +0 -0
  86. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/hashing.py +0 -0
  87. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/installed.py +0 -0
  88. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/local_state.py +0 -0
  89. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/lock.py +0 -0
  90. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/markers.py +0 -0
  91. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/reconcile.py +0 -0
  92. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/reporting.py +0 -0
  93. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/results.py +0 -0
  94. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/run.py +0 -0
  95. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/scheduler.py +0 -0
  96. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/target_files.py +0 -0
  97. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/targets.py +0 -0
  98. {gumloop-0.5.3 → gumloop-0.5.4}/src/gumloop/sync/wire.py +0 -0
  99. {gumloop-0.5.3 → gumloop-0.5.4}/tests/__init__.py +0 -0
  100. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/__init__.py +0 -0
  101. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/conftest.py +0 -0
  102. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/sync_scenario_helpers.py +0 -0
  103. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/sync_test_fakes.py +0 -0
  104. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_agents.py +0 -0
  105. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_args_input.py +0 -0
  106. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_artifacts.py +0 -0
  107. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_brain.py +0 -0
  108. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_brain_sync.py +0 -0
  109. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_browser_logins.py +0 -0
  110. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_chat.py +0 -0
  111. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_context.py +0 -0
  112. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_credentials.py +0 -0
  113. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_evaluations.py +0 -0
  114. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_home_isolation.py +0 -0
  115. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_login.py +0 -0
  116. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_main.py +0 -0
  117. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_mcp.py +0 -0
  118. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_models.py +0 -0
  119. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_plugin.py +0 -0
  120. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sessions.py +0 -0
  121. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_skills.py +0 -0
  122. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_bundle.py +0 -0
  123. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_command.py +0 -0
  124. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_command_safety.py +0 -0
  125. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_contract_fixtures.py +0 -0
  126. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_enrollment.py +0 -0
  127. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_fixture_corpus.py +0 -0
  128. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_hashing.py +0 -0
  129. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_installed.py +0 -0
  130. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_reconciliation_safety.py +0 -0
  131. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_scheduler_macos.py +0 -0
  132. {gumloop-0.5.3 → gumloop-0.5.4}/tests/cli/test_sync_targets.py +0 -0
  133. {gumloop-0.5.3 → gumloop-0.5.4}/tests/conftest.py +0 -0
  134. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/README.md +0 -0
  135. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/generated-bundle-transfer-limit.json +0 -0
  136. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-absolute-path.zip +0 -0
  137. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-bytes-per-file-limit.zip +0 -0
  138. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-device.zip +0 -0
  139. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-duplicate-entry.zip +0 -0
  140. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-fifo.zip +0 -0
  141. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-files-per-skill-limit.zip +0 -0
  142. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-nul-name.zip +0 -0
  143. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-parent-traversal.zip +0 -0
  144. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-reserved-marker.zip +0 -0
  145. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-socket.zip +0 -0
  146. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-symlink.zip +0 -0
  147. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-total-uncompressed-limit.zip +0 -0
  148. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/invalid-windows-drive-prefix.zip +0 -0
  149. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/valid-single-skill-stored.zip +0 -0
  150. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/archives/valid-single-skill.zip +0 -0
  151. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/bundles/newer-than-plan.zip +0 -0
  152. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/bundles/normal.zip +0 -0
  153. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/catalog.json +0 -0
  154. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/corpus.sha256 +0 -0
  155. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/hashes/content-v1.json +0 -0
  156. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/hashes/manifest-v1.json +0 -0
  157. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/manifests/invalid-duplicate-identity.json +0 -0
  158. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/manifests/invalid-duplicate-install-name.json +0 -0
  159. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/manifests/invalid-manifest-hash.json +0 -0
  160. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/manifests/newer-than-plan.json +0 -0
  161. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/manifests/normal-bundle.json +0 -0
  162. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/responses/below-pro.json +0 -0
  163. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/responses/cli-upgrade-required.json +0 -0
  164. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/responses/lost-membership.json +0 -0
  165. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/responses/normal-empty-plan.json +0 -0
  166. {gumloop-0.5.3 → gumloop-0.5.4}/tests/fixtures/skill_sync/v1/responses/normal-plan.json +0 -0
  167. {gumloop-0.5.3 → gumloop-0.5.4}/tests/integration/conftest.py +0 -0
  168. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/__init__.py +0 -0
  169. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/conftest.py +0 -0
  170. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/helpers.py +0 -0
  171. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_artifacts.py +0 -0
  172. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_brain.py +0 -0
  173. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_chat.py +0 -0
  174. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_client.py +0 -0
  175. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_decisions.py +0 -0
  176. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_errors.py +0 -0
  177. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_evaluations.py +0 -0
  178. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_gumcp_transport.py +0 -0
  179. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_mcp.py +0 -0
  180. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_models.py +0 -0
  181. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_oauth.py +0 -0
  182. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_organizations.py +0 -0
  183. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_sessions.py +0 -0
  184. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_skills.py +0 -0
  185. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_sync.py +0 -0
  186. {gumloop-0.5.3 → gumloop-0.5.4}/tests/sdk/test_teams.py +0 -0
  187. {gumloop-0.5.3 → gumloop-0.5.4}/tests/skill_sync_fixtures.py +0 -0
  188. {gumloop-0.5.3 → gumloop-0.5.4}/tests/test_client.py +0 -0
  189. {gumloop-0.5.3 → gumloop-0.5.4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: gumloop
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: Python client for the Gumloop API
5
5
  Project-URL: Homepage, https://github.com/gumloop/gumloop-py
6
6
  Project-URL: Bug Tracker, https://github.com/gumloop/gumloop-py/issues
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.5.3"
3
+ __version__ = "0.5.4"
@@ -7,15 +7,29 @@ from typing import Any
7
7
 
8
8
  from gumloop._http import AsyncHttpClient
9
9
  from gumloop._http import HttpClient
10
+ from gumloop.types import AgentAbilitiesResponse
11
+ from gumloop.types import AgentAbilitiesUpdateRequest
12
+ from gumloop.types import AgentAppRulesResponse
10
13
  from gumloop.types import AgentCreateRequest
14
+ from gumloop.types import AgentDeleteResponse
11
15
  from gumloop.types import AgentEvaluationMetricsResponse
12
16
  from gumloop.types import AgentEvaluationOptionsResponse
17
+ from gumloop.types import AgentKnowledgeSourceDetachResponse
18
+ from gumloop.types import AgentKnowledgeSourceResponse
19
+ from gumloop.types import AgentKnowledgeSourcesResponse
13
20
  from gumloop.types import AgentListResponse
14
21
  from gumloop.types import AgentMcpServerDetachResponse
15
22
  from gumloop.types import AgentMcpServerResponse
16
23
  from gumloop.types import AgentMcpServersResponse
17
24
  from gumloop.types import AgentResponse
18
25
  from gumloop.types import AgentSkillsResponse
26
+ from gumloop.types import AgentSubagentsResponse
27
+ from gumloop.types import AgentTriggerCreateRequest
28
+ from gumloop.types import AgentTriggerDeleteResponse
29
+ from gumloop.types import AgentTriggerResponse
30
+ from gumloop.types import AgentTriggersResponse
31
+ from gumloop.types import AgentTriggerUpdateRequest
32
+ from gumloop.types import AgentTriggerWebhookUrlResponse
19
33
  from gumloop.types import AgentUpdateRequest
20
34
  from gumloop.types import AgentVersionResponse
21
35
  from gumloop.types import AgentVersionsResponse
@@ -25,6 +39,7 @@ from gumloop.types import EvaluationResultListResponse
25
39
  from gumloop.types import EvaluationResultResponse
26
40
  from gumloop.types import EvaluationRunRequest
27
41
  from gumloop.types import EvaluationRunResponse
42
+ from gumloop.types import KnowledgeSourceScope
28
43
  from gumloop.types import ModelListResponse
29
44
  from gumloop.types import ModelRouteRequest
30
45
  from gumloop.types import ModelRouteResponse
@@ -35,6 +50,14 @@ def _skill_id_list(skill_ids: str | Sequence[str]) -> list[str]:
35
50
  return [skill_ids] if isinstance(skill_ids, str) else list(skill_ids)
36
51
 
37
52
 
53
+ def _knowledge_scope_body(config: KnowledgeSourceScope | Mapping[str, Any] | None) -> dict[str, Any]:
54
+ # The key is always sent: null means the whole source.
55
+ if config is None:
56
+ return {"config": None}
57
+ scope = config if isinstance(config, KnowledgeSourceScope) else KnowledgeSourceScope.model_validate(config)
58
+ return {"config": scope.model_dump(exclude_unset=True)}
59
+
60
+
38
61
  class Agents:
39
62
  def __init__(self, client: HttpClient) -> None:
40
63
  self._client = client
@@ -99,9 +122,11 @@ class Agents:
99
122
  request: AgentUpdateRequest | Mapping[str, Any] | None = None,
100
123
  **kwargs: Any,
101
124
  ) -> AgentResponse:
102
- """``tools`` replaces the entire list when provided (legacy bulk path); prefer
103
- attach_mcp_server/detach_mcp_server for individual MCP servers and
104
- attach_skills/detach_skills for skills."""
125
+ """Settings live under ``metadata`` and merge section by section. Pass ``version``
126
+ from a previous read to refuse the update if the agent changed since
127
+ (``agent_version_conflict``). ``tools`` replaces the whole list when provided;
128
+ prefer update_abilities, attach_mcp_server/detach_mcp_server and
129
+ attach_skills/detach_skills."""
105
130
  return AgentResponse.model_validate(
106
131
  self._client.patch(f"agents/{agent_id}", json=AgentUpdateRequest.build(request, **kwargs))
107
132
  )
@@ -139,6 +164,111 @@ class Agents:
139
164
  def list_mcp_servers(self, agent_id: str) -> AgentMcpServersResponse:
140
165
  return AgentMcpServersResponse.model_validate(self._client.get(f"agents/{agent_id}/mcp-servers"))
141
166
 
167
+ def delete(self, agent_id: str) -> AgentDeleteResponse:
168
+ """Delete a custom agent. Platform agents (``gumball``, ``analytics``) are refused."""
169
+ return AgentDeleteResponse.model_validate(self._client.delete(f"agents/{agent_id}"))
170
+
171
+ def update_abilities(
172
+ self,
173
+ agent_id: str,
174
+ request: AgentAbilitiesUpdateRequest | Mapping[str, Any] | None = None,
175
+ **abilities: Any,
176
+ ) -> AgentAbilitiesResponse:
177
+ """Turn native abilities on or off and set their options, e.g.
178
+ ``update_abilities(agent_id, web_search={"enabled": True, "provider": "exa"},
179
+ ask_question={"enabled": False})``. Only the abilities you send change."""
180
+ return AgentAbilitiesResponse.model_validate(
181
+ self._client.patch(
182
+ f"agents/{agent_id}/abilities",
183
+ json=AgentAbilitiesUpdateRequest.build(request, **abilities),
184
+ )
185
+ )
186
+
187
+ def list_knowledge_sources(self, agent_id: str) -> AgentKnowledgeSourcesResponse:
188
+ return AgentKnowledgeSourcesResponse.model_validate(self._client.get(f"agents/{agent_id}/knowledge-sources"))
189
+
190
+ def attach_knowledge_source(
191
+ self,
192
+ agent_id: str,
193
+ connector_id: str,
194
+ *,
195
+ config: KnowledgeSourceScope | Mapping[str, Any] | None = None,
196
+ ) -> AgentKnowledgeSourceResponse:
197
+ """Attach a Brain source, or change its scope if already attached (idempotent upsert).
198
+ ``config=None`` attaches the whole source."""
199
+ return AgentKnowledgeSourceResponse.model_validate(
200
+ self._client.put(
201
+ f"agents/{agent_id}/knowledge-sources/{connector_id}",
202
+ json=_knowledge_scope_body(config),
203
+ )
204
+ )
205
+
206
+ def detach_knowledge_source(self, agent_id: str, connector_id: str) -> AgentKnowledgeSourceDetachResponse:
207
+ """Detach a Brain source. Idempotent: safe to retry."""
208
+ return AgentKnowledgeSourceDetachResponse.model_validate(
209
+ self._client.delete(f"agents/{agent_id}/knowledge-sources/{connector_id}")
210
+ )
211
+
212
+ def attach_subagent(self, agent_id: str, subagent_id: str) -> AgentSubagentsResponse:
213
+ """Allow the agent to delegate to ``subagent_id``. Idempotent; the subagent must live in the same workspace."""
214
+ return AgentSubagentsResponse.model_validate(self._client.put(f"agents/{agent_id}/subagents/{subagent_id}"))
215
+
216
+ def detach_subagent(self, agent_id: str, subagent_id: str) -> AgentSubagentsResponse:
217
+ return AgentSubagentsResponse.model_validate(self._client.delete(f"agents/{agent_id}/subagents/{subagent_id}"))
218
+
219
+ def list_triggers(
220
+ self,
221
+ agent_id: str,
222
+ *,
223
+ page_size: int | None = None,
224
+ cursor: str | None = None,
225
+ ) -> AgentTriggersResponse:
226
+ return AgentTriggersResponse.model_validate(
227
+ self._client.get(f"agents/{agent_id}/triggers", params={"page_size": page_size, "cursor": cursor})
228
+ )
229
+
230
+ def create_trigger(
231
+ self,
232
+ agent_id: str,
233
+ request: AgentTriggerCreateRequest | Mapping[str, Any] | None = None,
234
+ **kwargs: Any,
235
+ ) -> AgentTriggerResponse:
236
+ """Create a ``schedule`` (``cron_expression`` or ``run_at``) or ``webhook`` trigger.
237
+ A webhook's URL is returned here and from ``get_trigger_webhook_url``, never in lists."""
238
+ return AgentTriggerResponse.model_validate(
239
+ self._client.post(f"agents/{agent_id}/triggers", json=AgentTriggerCreateRequest.build(request, **kwargs))
240
+ )
241
+
242
+ def update_trigger(
243
+ self,
244
+ agent_id: str,
245
+ trigger_id: str,
246
+ request: AgentTriggerUpdateRequest | Mapping[str, Any] | None = None,
247
+ **kwargs: Any,
248
+ ) -> AgentTriggerResponse:
249
+ """Edit, enable or disable a schedule or webhook trigger. Only the fields you send change."""
250
+ return AgentTriggerResponse.model_validate(
251
+ self._client.patch(
252
+ f"agents/{agent_id}/triggers/{trigger_id}",
253
+ json=AgentTriggerUpdateRequest.build(request, **kwargs),
254
+ )
255
+ )
256
+
257
+ def delete_trigger(self, agent_id: str, trigger_id: str) -> AgentTriggerDeleteResponse:
258
+ return AgentTriggerDeleteResponse.model_validate(
259
+ self._client.delete(f"agents/{agent_id}/triggers/{trigger_id}")
260
+ )
261
+
262
+ def get_trigger_webhook_url(self, agent_id: str, trigger_id: str) -> AgentTriggerWebhookUrlResponse:
263
+ """The webhook URL embeds its secret; fetch it on demand rather than storing it."""
264
+ return AgentTriggerWebhookUrlResponse.model_validate(
265
+ self._client.get(f"agents/{agent_id}/triggers/{trigger_id}/webhook-url")
266
+ )
267
+
268
+ def list_app_rules(self, agent_id: str) -> AgentAppRulesResponse:
269
+ """Rules the agent has authored for its connectors. Read only."""
270
+ return AgentAppRulesResponse.model_validate(self._client.get(f"agents/{agent_id}/app-rules"))
271
+
142
272
  def get_evaluation_options(self) -> AgentEvaluationOptionsResponse:
143
273
  return AgentEvaluationOptionsResponse.model_validate(self._client.get("agents/evaluation-options"))
144
274
 
@@ -295,9 +425,11 @@ class AsyncAgents:
295
425
  request: AgentUpdateRequest | Mapping[str, Any] | None = None,
296
426
  **kwargs: Any,
297
427
  ) -> AgentResponse:
298
- """``tools`` replaces the entire list when provided (legacy bulk path); prefer
299
- attach_mcp_server/detach_mcp_server for individual MCP servers and
300
- attach_skills/detach_skills for skills."""
428
+ """Settings live under ``metadata`` and merge section by section. Pass ``version``
429
+ from a previous read to refuse the update if the agent changed since
430
+ (``agent_version_conflict``). ``tools`` replaces the whole list when provided;
431
+ prefer update_abilities, attach_mcp_server/detach_mcp_server and
432
+ attach_skills/detach_skills."""
301
433
  data = await self._client.patch(f"agents/{agent_id}", json=AgentUpdateRequest.build(request, **kwargs))
302
434
  return AgentResponse.model_validate(data)
303
435
 
@@ -332,6 +464,99 @@ class AsyncAgents:
332
464
  data = await self._client.get(f"agents/{agent_id}/mcp-servers")
333
465
  return AgentMcpServersResponse.model_validate(data)
334
466
 
467
+ async def delete(self, agent_id: str) -> AgentDeleteResponse:
468
+ """Delete a custom agent. Platform agents (``gumball``, ``analytics``) are refused."""
469
+ return AgentDeleteResponse.model_validate(await self._client.delete(f"agents/{agent_id}"))
470
+
471
+ async def update_abilities(
472
+ self,
473
+ agent_id: str,
474
+ request: AgentAbilitiesUpdateRequest | Mapping[str, Any] | None = None,
475
+ **abilities: Any,
476
+ ) -> AgentAbilitiesResponse:
477
+ """Turn native abilities on or off and set their options. Only the abilities you send change."""
478
+ data = await self._client.patch(
479
+ f"agents/{agent_id}/abilities", json=AgentAbilitiesUpdateRequest.build(request, **abilities)
480
+ )
481
+ return AgentAbilitiesResponse.model_validate(data)
482
+
483
+ async def list_knowledge_sources(self, agent_id: str) -> AgentKnowledgeSourcesResponse:
484
+ data = await self._client.get(f"agents/{agent_id}/knowledge-sources")
485
+ return AgentKnowledgeSourcesResponse.model_validate(data)
486
+
487
+ async def attach_knowledge_source(
488
+ self,
489
+ agent_id: str,
490
+ connector_id: str,
491
+ *,
492
+ config: KnowledgeSourceScope | Mapping[str, Any] | None = None,
493
+ ) -> AgentKnowledgeSourceResponse:
494
+ """Attach a Brain source, or change its scope if already attached (idempotent upsert).
495
+ ``config=None`` attaches the whole source."""
496
+ data = await self._client.put(
497
+ f"agents/{agent_id}/knowledge-sources/{connector_id}", json=_knowledge_scope_body(config)
498
+ )
499
+ return AgentKnowledgeSourceResponse.model_validate(data)
500
+
501
+ async def detach_knowledge_source(self, agent_id: str, connector_id: str) -> AgentKnowledgeSourceDetachResponse:
502
+ data = await self._client.delete(f"agents/{agent_id}/knowledge-sources/{connector_id}")
503
+ return AgentKnowledgeSourceDetachResponse.model_validate(data)
504
+
505
+ async def attach_subagent(self, agent_id: str, subagent_id: str) -> AgentSubagentsResponse:
506
+ data = await self._client.put(f"agents/{agent_id}/subagents/{subagent_id}")
507
+ return AgentSubagentsResponse.model_validate(data)
508
+
509
+ async def detach_subagent(self, agent_id: str, subagent_id: str) -> AgentSubagentsResponse:
510
+ data = await self._client.delete(f"agents/{agent_id}/subagents/{subagent_id}")
511
+ return AgentSubagentsResponse.model_validate(data)
512
+
513
+ async def list_triggers(
514
+ self,
515
+ agent_id: str,
516
+ *,
517
+ page_size: int | None = None,
518
+ cursor: str | None = None,
519
+ ) -> AgentTriggersResponse:
520
+ data = await self._client.get(f"agents/{agent_id}/triggers", params={"page_size": page_size, "cursor": cursor})
521
+ return AgentTriggersResponse.model_validate(data)
522
+
523
+ async def create_trigger(
524
+ self,
525
+ agent_id: str,
526
+ request: AgentTriggerCreateRequest | Mapping[str, Any] | None = None,
527
+ **kwargs: Any,
528
+ ) -> AgentTriggerResponse:
529
+ """Create a ``schedule`` (``cron_expression`` or ``run_at``) or ``webhook`` trigger.
530
+ A webhook's URL is returned here and from ``get_trigger_webhook_url``, never in lists."""
531
+ data = await self._client.post(
532
+ f"agents/{agent_id}/triggers", json=AgentTriggerCreateRequest.build(request, **kwargs)
533
+ )
534
+ return AgentTriggerResponse.model_validate(data)
535
+
536
+ async def update_trigger(
537
+ self,
538
+ agent_id: str,
539
+ trigger_id: str,
540
+ request: AgentTriggerUpdateRequest | Mapping[str, Any] | None = None,
541
+ **kwargs: Any,
542
+ ) -> AgentTriggerResponse:
543
+ data = await self._client.patch(
544
+ f"agents/{agent_id}/triggers/{trigger_id}", json=AgentTriggerUpdateRequest.build(request, **kwargs)
545
+ )
546
+ return AgentTriggerResponse.model_validate(data)
547
+
548
+ async def delete_trigger(self, agent_id: str, trigger_id: str) -> AgentTriggerDeleteResponse:
549
+ data = await self._client.delete(f"agents/{agent_id}/triggers/{trigger_id}")
550
+ return AgentTriggerDeleteResponse.model_validate(data)
551
+
552
+ async def get_trigger_webhook_url(self, agent_id: str, trigger_id: str) -> AgentTriggerWebhookUrlResponse:
553
+ data = await self._client.get(f"agents/{agent_id}/triggers/{trigger_id}/webhook-url")
554
+ return AgentTriggerWebhookUrlResponse.model_validate(data)
555
+
556
+ async def list_app_rules(self, agent_id: str) -> AgentAppRulesResponse:
557
+ data = await self._client.get(f"agents/{agent_id}/app-rules")
558
+ return AgentAppRulesResponse.model_validate(data)
559
+
335
560
  async def get_evaluation_options(self) -> AgentEvaluationOptionsResponse:
336
561
  data = await self._client.get("agents/evaluation-options")
337
562
  return AgentEvaluationOptionsResponse.model_validate(data)