devops-bot-sdk 1.7.5__tar.gz → 1.7.6__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 (270) hide show
  1. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/PKG-INFO +1 -1
  2. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
  3. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/__init__.py +2 -2
  4. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/client.py +1 -1
  5. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/helpdesk_kb.md +5 -0
  6. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/api.py +62 -8
  7. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/app.js +41 -8
  8. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/styles.css +4 -0
  9. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_listing.py +88 -0
  10. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/README.md +0 -0
  11. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
  12. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
  13. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
  14. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/devops_bot_sdk.egg-info/requires.txt +0 -0
  15. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/devops_bot_sdk.egg-info/top_level.txt +0 -0
  16. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/pyproject.toml +0 -0
  17. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/__init__.py +0 -0
  18. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/classifier.py +0 -0
  19. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/collectors/__init__.py +0 -0
  20. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/collectors/common.py +0 -0
  21. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/collectors/linux_auditd.py +0 -0
  22. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/collectors/macos_eslogger.py +0 -0
  23. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/collectors/windows_eventlog.py +0 -0
  24. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/models.py +0 -0
  25. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/os_setup.py +0 -0
  26. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/recorder.py +0 -0
  27. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/redact.py +0 -0
  28. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/settings.py +0 -0
  29. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/shipper.py +0 -0
  30. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/activity/spool.py +0 -0
  31. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agent_sharing.py +0 -0
  32. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agentd.py +0 -0
  33. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/__init__.py +0 -0
  34. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/activity.py +0 -0
  35. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/builder.py +0 -0
  36. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/chat.py +0 -0
  37. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/connectors.py +0 -0
  38. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/engines/__init__.py +0 -0
  39. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/engines/claude_code.py +0 -0
  40. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/engines/http.py +0 -0
  41. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/engines/mcp.py +0 -0
  42. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/engines/n8n.py +0 -0
  43. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/engines/shell.py +0 -0
  44. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/integrations.py +0 -0
  45. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/inventory.py +0 -0
  46. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/library/__init__.py +0 -0
  47. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/manifest.py +0 -0
  48. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/prompt_studio.py +0 -0
  49. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/prompt_template.py +0 -0
  50. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/prompt_vars.py +0 -0
  51. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/run_log.py +0 -0
  52. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/schedules.py +0 -0
  53. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/secrets.py +0 -0
  54. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/ticket_run.py +0 -0
  55. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/usage.py +0 -0
  56. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/agents/varstore.py +0 -0
  57. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/browser_profile.py +0 -0
  58. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/claude_usage.py +0 -0
  59. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/cli.py +0 -0
  60. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/collectors/__init__.py +0 -0
  61. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/collectors/files.py +0 -0
  62. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/collectors/process.py +0 -0
  63. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/collectors/screenshot.py +0 -0
  64. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/config.py +0 -0
  65. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/crucial.py +0 -0
  66. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/custom_agents.py +0 -0
  67. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/deferred_tickets.py +0 -0
  68. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/departments.py +0 -0
  69. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/design_verify/__init__.py +0 -0
  70. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/design_verify/assets.py +0 -0
  71. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/design_verify/bootstrap.py +0 -0
  72. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/design_verify/browser.py +0 -0
  73. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/design_verify/compare.py +0 -0
  74. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/design_verify/loop.py +0 -0
  75. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/estimator.py +0 -0
  76. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/exceptions.py +0 -0
  77. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/fallback_handoff.py +0 -0
  78. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/firewall.py +0 -0
  79. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/formats.py +0 -0
  80. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/git_ops.py +0 -0
  81. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/github_fetch.py +0 -0
  82. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/github_ingest.py +0 -0
  83. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/graph_recon.py +0 -0
  84. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/graphify.py +0 -0
  85. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/help_actions.py +0 -0
  86. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/helpdesk.py +0 -0
  87. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/hooks/__init__.py +0 -0
  88. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/hooks/crucial_guard.py +0 -0
  89. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/intake.py +0 -0
  90. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ipc/__init__.py +0 -0
  91. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ipc/electron_bridge.py +0 -0
  92. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ipc/handlers.py +0 -0
  93. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/journal.py +0 -0
  94. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/local_exec.py +0 -0
  95. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/log_colors.py +0 -0
  96. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/memory_guard.py +0 -0
  97. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/model_policy.py +0 -0
  98. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/models/__init__.py +0 -0
  99. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/models/envelope.py +0 -0
  100. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/models/requests.py +0 -0
  101. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/models/responses.py +0 -0
  102. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/models/snapshots.py +0 -0
  103. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/phase_timer.py +0 -0
  104. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/plan_run.py +0 -0
  105. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/platform_compat.py +0 -0
  106. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/prd_progress.py +0 -0
  107. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/proof_readers.py +0 -0
  108. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/providers.py +0 -0
  109. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/py.typed +0 -0
  110. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/resume.py +0 -0
  111. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/router.py +0 -0
  112. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/run_auto.py +0 -0
  113. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/schedule_tickets.py +0 -0
  114. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/scheduler.py +0 -0
  115. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/self_report.py +0 -0
  116. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/self_report_local.py +0 -0
  117. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/sse.py +0 -0
  118. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/swagger.py +0 -0
  119. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/task_file.py +0 -0
  120. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/task_types.py +0 -0
  121. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/test.py +0 -0
  122. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/test_pipeline.py +0 -0
  123. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ticket_board.py +0 -0
  124. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ticket_fields.py +0 -0
  125. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/tickets.py +0 -0
  126. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/tiers/__init__.py +0 -0
  127. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/tiers/mini_agent.py +0 -0
  128. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/__init__.py +0 -0
  129. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/dashboard.py +0 -0
  130. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/health.py +0 -0
  131. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/ip_allowlist.py +0 -0
  132. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/jobs.py +0 -0
  133. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/models.py +0 -0
  134. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/runner.py +0 -0
  135. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/security.py +0 -0
  136. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/server.py +0 -0
  137. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/service.py +0 -0
  138. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/session.py +0 -0
  139. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/setup_manager.py +0 -0
  140. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/agents.html +0 -0
  141. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/chat.html +0 -0
  142. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/custom-agents.html +0 -0
  143. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/default-agents.html +0 -0
  144. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/help.html +0 -0
  145. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/index.html +0 -0
  146. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/report.html +0 -0
  147. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/runs.html +0 -0
  148. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/schedules.html +0 -0
  149. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/setup.html +0 -0
  150. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/static/tickets.html +0 -0
  151. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/ui/swagger.py +0 -0
  152. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/updater.py +0 -0
  153. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/url_access.py +0 -0
  154. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/vps_health.py +0 -0
  155. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/vps_identity.py +0 -0
  156. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/sdk/write_hook.py +0 -0
  157. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/setup.cfg +0 -0
  158. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_activity_claude_runs.py +0 -0
  159. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_activity_collectors.py +0 -0
  160. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_activity_core.py +0 -0
  161. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_activity_live_tracking.py +0 -0
  162. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_activity_macos.py +0 -0
  163. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_activity_os_setup.py +0 -0
  164. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_activity_pipeline.py +0 -0
  165. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_activity.py +0 -0
  166. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_activity_tracking.py +0 -0
  167. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_chat_features.py +0 -0
  168. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_crud_cli.py +0 -0
  169. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_prompt_async.py +0 -0
  170. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_prompt_models.py +0 -0
  171. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_run_ticket.py +0 -0
  172. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_schedules.py +0 -0
  173. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_sharing.py +0 -0
  174. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agent_workspace_settings.py +0 -0
  175. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_agents_connectors_builder.py +0 -0
  176. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_allowed_tools_config.py +0 -0
  177. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_approval_park.py +0 -0
  178. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_auto_agent_dispatch.py +0 -0
  179. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_auto_ticket_queue.py +0 -0
  180. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_browser_profile.py +0 -0
  181. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_cheap_tier.py +0 -0
  182. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_claude_usage_gate.py +0 -0
  183. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_client_jira_projects.py +0 -0
  184. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_config_token_diagnostics.py +0 -0
  185. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_configure_token_owner.py +0 -0
  186. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_console_encoding.py +0 -0
  187. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_crash_recovery.py +0 -0
  188. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_create_safe_retry.py +0 -0
  189. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_deferred_tickets.py +0 -0
  190. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_departments.py +0 -0
  191. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_done_transition.py +0 -0
  192. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_epic_decompose_run.py +0 -0
  193. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_epic_inherited_agent_id.py +0 -0
  194. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_epic_session_isolation.py +0 -0
  195. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_estimator.py +0 -0
  196. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_fallback_cli.py +0 -0
  197. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_fallback_cli_upgrade.py +0 -0
  198. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_firewall_open_on_update.py +0 -0
  199. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_formats.py +0 -0
  200. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_git_action.py +0 -0
  201. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_github_fetch.py +0 -0
  202. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_github_ingest.py +0 -0
  203. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_graph_recon.py +0 -0
  204. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_graphify_build.py +0 -0
  205. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_graphify_hook_install.py +0 -0
  206. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_health.py +0 -0
  207. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_help_actions.py +0 -0
  208. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_help_attachments.py +0 -0
  209. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_help_questions.py +0 -0
  210. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_helpdesk.py +0 -0
  211. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_infographic_data.py +0 -0
  212. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_intake_job_outcome.py +0 -0
  213. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_intake_plan_review.py +0 -0
  214. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_journal.py +0 -0
  215. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_limit_fallback_handoff.py +0 -0
  216. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_local_exec_provider.py +0 -0
  217. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_log_colors_backlog.py +0 -0
  218. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_mcp_route_contract.py +0 -0
  219. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_memory_guard.py +0 -0
  220. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_model_policy.py +0 -0
  221. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_panel_help.py +0 -0
  222. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_panel_ticket_schedules.py +0 -0
  223. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_parallel_tickets.py +0 -0
  224. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_phase_timer.py +0 -0
  225. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_plan_new_command.py +0 -0
  226. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_plan_run_activity.py +0 -0
  227. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_pr_identity.py +0 -0
  228. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_prd_artifact.py +0 -0
  229. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_project_path_resolution.py +0 -0
  230. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_proof_readers.py +0 -0
  231. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_providers.py +0 -0
  232. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_recon_session_isolation.py +0 -0
  233. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_resume.py +0 -0
  234. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_router.py +0 -0
  235. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_run_auto_agent_only.py +0 -0
  236. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_run_outputs.py +0 -0
  237. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_run_verdict_is_honest.py +0 -0
  238. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_schedule_api.py +0 -0
  239. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_schedule_outputs_and_plans.py +0 -0
  240. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_schedule_tickets.py +0 -0
  241. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_scheduler.py +0 -0
  242. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_scheduler_transient_retry.py +0 -0
  243. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_self_report.py +0 -0
  244. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_service_token_warning.py +0 -0
  245. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_stale_panel_restart.py +0 -0
  246. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_swagger_command.py +0 -0
  247. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_task_file_and_plan_run.py +0 -0
  248. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_task_file_format_doc.py +0 -0
  249. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ticket_board.py +0 -0
  250. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ticket_cli.py +0 -0
  251. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ticket_fields.py +0 -0
  252. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ticket_run_resolve_by_id.py +0 -0
  253. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ticket_schedule_and_agent.py +0 -0
  254. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ticket_speed_fixes.py +0 -0
  255. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_tier_flag_parity.py +0 -0
  256. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ui_gate.py +0 -0
  257. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_ui_lifespan.py +0 -0
  258. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_update_timer.py +0 -0
  259. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_updater_extras.py +0 -0
  260. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_updater_ignores_cwd.py +0 -0
  261. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_updater_pep668.py +0 -0
  262. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_updater_reports_the_truth.py +0 -0
  263. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_url_access.py +0 -0
  264. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_vps_health.py +0 -0
  265. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_vps_only_reporting.py +0 -0
  266. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_windows_loop_identity.py +0 -0
  267. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_windows_panel_task.py +0 -0
  268. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_windows_stop_and_pidfile.py +0 -0
  269. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_windows_task_paths.py +0 -0
  270. {devops_bot_sdk-1.7.5 → devops_bot_sdk-1.7.6}/tests/test_write_hook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.7.5
3
+ Version: 1.7.6
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.7.5
3
+ Version: 1.7.6
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -1,6 +1,6 @@
1
1
  """AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
2
2
 
3
- Version: 1.7.5
3
+ Version: 1.7.6
4
4
 
5
5
  Public surface:
6
6
  BackendClient.from_config() — create client from ~/.agentos/config.toml
@@ -34,7 +34,7 @@ Rules:
34
34
  - All data egress through submit_webhook only
35
35
  """
36
36
 
37
- __version__ = "1.7.5" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
37
+ __version__ = "1.7.6" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
38
38
  __author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
39
39
 
40
40
  from sdk.client import BackendClient
@@ -2758,7 +2758,7 @@ class BackendClient:
2758
2758
  url = self._url("/api/v1/agents/shared")
2759
2759
  async with httpx.AsyncClient(timeout=15.0) as client:
2760
2760
  resp = await client.get(url, headers=self._headers)
2761
- if resp.status_code == 404:
2761
+ if resp.status_code in (404, 405): # 405: an older backend's /agents/{name} catch-all
2762
2762
  raise BackendFeatureMissing("Agent sharing", url)
2763
2763
  _check_status(resp.status_code, self._base_url)
2764
2764
  return resp.json().get("agents", [])
@@ -104,6 +104,11 @@ stuck In Progress after a crash → `restore-stranded-tickets` (⚠ moves ticket
104
104
  pending invite per recipient on the AI backend (devops-bot-ai, Mongo `agent_shares`); it reaches them only
105
105
  after they `agentos agent accept ID` (or Accept on the Custom Agents page). Accepted
106
106
  shares are runnable (`sdk/agents/chat.resolve_agent` reads `GET /api/v1/agents/shared`).
107
+ Accepted shares appear on Custom Agents next to your own (`GET /api/ui/agents` and
108
+ `/api/ui/agents/custom` add them with `source="shared"`, `shared_by`, `via`,
109
+ `share_id`): Run dropdown, installed cards and a "Shared with you" platform group,
110
+ with Run / Remove only. Their inputs come from the backend row (`/api/ui/agents/vars`
111
+ falls back to `resolve_agent`).
107
112
  The panel's Share dialog (Custom Agents → Share) has Person / Team / Department tabs;
108
113
  each lists from `GET /api/v1/agents/share-targets?kind=…` (users, teams, departments
109
114
  in the platform's SQL — names, never ids) and sends the picks as `user:<id>` /
@@ -466,6 +466,37 @@ async def product_agents(product_id: str = Query(...)) -> dict:
466
466
  return {"response": [], "product_id": product_id, "error": str(exc)}
467
467
 
468
468
 
469
+ async def _shared_agent_rows(client) -> tuple[list[dict], str]:
470
+ """Agents others shared with you that you ACCEPTED, as ``(rows, error)``.
471
+
472
+ Each row is the backend agent row plus ``source="shared"``, ``shared_by`` (a
473
+ NAME), ``share_id`` (for Remove) and ``via`` ("team X" / "department X").
474
+ A backend without sharing has none — that is not an error to show."""
475
+ from sdk.exceptions import BackendFeatureMissing
476
+
477
+ fetch = getattr(client, "list_shared_agents", None)
478
+ if fetch is None:
479
+ return [], ""
480
+ try:
481
+ rows = await fetch()
482
+ except BackendFeatureMissing:
483
+ return [], ""
484
+ except Exception as exc: # noqa: BLE001
485
+ return [], f"Couldn't load agents shared with you: {exc}"
486
+ out = []
487
+ for r in rows or []:
488
+ if not isinstance(r, dict) or not r.get("name"):
489
+ continue
490
+ by = r.get("shared_by") or {}
491
+ via = r.get("via_team") or {}
492
+ out.append({**r, "source": "shared",
493
+ "shared_by": (by.get("name") or by.get("email") or "") if isinstance(by, dict) else str(by),
494
+ "share_id": r.get("share_id") or "",
495
+ "via": (f"{'department' if via.get('kind') == 'department' else 'team'} {via['name']}"
496
+ if isinstance(via, dict) and via.get("name") else "")})
497
+ return out, ""
498
+
499
+
469
500
  @router.get("/agents", dependencies=[_auth])
470
501
  async def agents() -> dict:
471
502
  """The caller's own custom agents (``relation_type='User'``) from the backend.
@@ -480,14 +511,21 @@ async def agents() -> dict:
480
511
  from sdk.client import BackendClient
481
512
  from sdk.exceptions import BackendFeatureMissing
482
513
 
514
+ client = BackendClient.from_config()
515
+ # Accepted shares sit next to your own (source="shared"), so the Custom Agents
516
+ # page lists and runs them too; your own agent wins a name clash.
517
+ shared, shared_error = await _shared_agent_rows(client)
483
518
  try:
484
- rows = await BackendClient.from_config().list_custom_agents()
519
+ rows = await client.list_custom_agents()
485
520
  except BackendFeatureMissing:
486
- return {"agents": [], "error": ("Custom agents aren't available on this "
487
- "backend — it may be running an older version.")}
521
+ return {"agents": shared, "shared_error": shared_error,
522
+ "error": ("Custom agents aren't available on this "
523
+ "backend — it may be running an older version.")}
488
524
  except Exception as exc: # noqa: BLE001 — degrade to empty, surface the reason
489
- return {"agents": [], "error": str(exc)}
490
- return {"agents": rows, "error": ""}
525
+ return {"agents": shared, "error": str(exc), "shared_error": shared_error}
526
+ own = {r.get("name") for r in rows}
527
+ return {"agents": rows + [s for s in shared if s["name"] not in own], "error": "",
528
+ "shared_error": shared_error}
491
529
 
492
530
 
493
531
  def _flat_agent(row: dict, source: str, *, chattable: bool, department_id: str = "") -> dict:
@@ -640,6 +678,14 @@ async def agent_vars(name: str = Query(...)) -> dict:
640
678
  from sdk.agents import varstore as agent_varstore
641
679
 
642
680
  manifest = next((m for m in load_agents() if m.name == name), None)
681
+ if manifest is None:
682
+ # Platform agents (yours, department, shared with you) live on the backend,
683
+ # not in ~/.agentos/agents — read their prompt there so the inputs render.
684
+ try:
685
+ from sdk.agents.chat import resolve_agent
686
+ manifest = await resolve_agent(name)
687
+ except Exception: # noqa: BLE001 — unknown / unreachable: no inputs to show
688
+ manifest = None
643
689
  names = extract_variables(manifest.prompt) if manifest else []
644
690
  values = agent_varstore.load_vars(name)
645
691
  return {"name": name, "variables": names,
@@ -1816,11 +1862,19 @@ async def custom_agents_list() -> dict:
1816
1862
  backend, which decides what is yours."""
1817
1863
  from sdk import custom_agents
1818
1864
 
1819
- scopes, err = await custom_agents.list_agents(_ticket_client())
1865
+ client = _ticket_client()
1866
+ scopes, err = await custom_agents.list_agents(client)
1820
1867
  if scopes is None:
1821
1868
  raise HTTPException(status_code=502, detail=err)
1822
- return {scope: [custom_agents.editable_view(r) for r in rows]
1823
- for scope, rows in scopes.items()}
1869
+ out = {scope: [custom_agents.editable_view(r) for r in rows]
1870
+ for scope, rows in scopes.items()}
1871
+ # Accepted shares: read-only here (Run / Remove), never Edit or Delete.
1872
+ shared, shared_error = await _shared_agent_rows(client)
1873
+ out["shared"] = [{"id": s.get("id"), "name": s["name"], "status": s.get("status"),
1874
+ "shared_by": s["shared_by"], "via": s["via"], "share_id": s["share_id"]}
1875
+ for s in shared]
1876
+ out["shared_error"] = shared_error
1877
+ return out
1824
1878
 
1825
1879
 
1826
1880
  @router.post("/agents/custom", dependencies=[_auth])
@@ -457,8 +457,10 @@
457
457
  async function act(path, method, okMsg) {
458
458
  try { await api(path, { method }); toast(okMsg, "ok"); }
459
459
  catch (e) { toast(e.message, "err"); }
460
- loadShared();
460
+ // Accept / Remove changes which agents you have: the lists above reload too.
461
+ document.dispatchEvent(new CustomEvent("agentos:shares-changed"));
461
462
  }
463
+ document.addEventListener("agentos:shares-changed", () => loadShared());
462
464
  async function loadShared() {
463
465
  const box = $("sh-list");
464
466
  document.querySelectorAll("[data-shtab]").forEach(b => b.classList.toggle("primary", b.dataset.shtab === tab));
@@ -488,7 +490,7 @@
488
490
  return `<tr><td><div class="nm">${esc(x.agent_name)}</div>${x.message ? `<div class="sub">“${esc(x.message)}”</div>` : ""}</td>
489
491
  <td>${esc(who || "?")}${via}</td><td>${pill(x.status)}</td><td class="sub mono">${esc(when)}</td><td class="acts">${acts}</td></tr>`;
490
492
  }).join("") + `</tbody></table>`;
491
- box.querySelectorAll("[data-acc]").forEach(b => b.onclick = () => act(`/api/ui/agents/shares/${b.dataset.acc}/accept`, "POST", "Accepted — it is now in your agents"));
493
+ box.querySelectorAll("[data-acc]").forEach(b => b.onclick = () => act(`/api/ui/agents/shares/${b.dataset.acc}/accept`, "POST", "Accepted — it's now in your custom agents"));
492
494
  box.querySelectorAll("[data-dec]").forEach(b => b.onclick = () => act(`/api/ui/agents/shares/${b.dataset.dec}/decline`, "POST", "Declined"));
493
495
  box.querySelectorAll("[data-rm]").forEach(b => b.onclick = () => {
494
496
  if (!confirm(tab === "incoming" ? "Remove this shared agent from your list?" : "Revoke this share? They lose access.")) return;
@@ -1094,17 +1096,27 @@
1094
1096
  return;
1095
1097
  }
1096
1098
  caMeta = {}; rows.forEach(a => { caMeta[a.name] = a; });
1099
+ const own = rows.filter(a => a.source !== "shared"), shared = rows.filter(a => a.source === "shared");
1097
1100
  const kaSel = $("key-agent");
1098
1101
  if (kaSel) {
1099
- kaSel.innerHTML = rows.length
1100
- ? rows.map(a => `<option value="${esc(a.name)}">${esc(a.name)}</option>`).join("")
1101
- : `<option value="">(no agents yet)</option>`;
1102
+ const opt = (a) => `<option value="${esc(a.name)}">${esc(a.name)}${a.shared_by ? " — from " + esc(a.shared_by) : ""}</option>`;
1103
+ kaSel.innerHTML = !rows.length ? `<option value="">(no agents yet)</option>`
1104
+ : !shared.length ? own.map(opt).join("")
1105
+ : (own.length ? `<optgroup label="Your agents">${own.map(opt).join("")}</optgroup>` : "")
1106
+ + `<optgroup label="Shared with you">${shared.map(opt).join("")}</optgroup>`;
1102
1107
  onAgentSelect();
1103
1108
  }
1104
1109
  // Custom agents: full control for everyone (view / Edit-content / enable /
1105
- // disable / delete) — RBAC applies only to department agents.
1110
+ // disable / delete) — RBAC applies only to department agents. Agents shared
1111
+ // with you (accepted) are someone else's: Run and Remove only.
1106
1112
  $("local-agents").innerHTML = rows.length ? rows.map(a => {
1107
1113
  const enc = encodeURIComponent(a.name);
1114
+ if (a.source === "shared") {
1115
+ const from = `<span class="pill shared">shared</span> <span class="muted" style="font-size:12.5px">from <b>${esc(a.shared_by || "?")}</b>${a.via ? " · via " + esc(a.via) : ""}</span>`;
1116
+ return agentCardHTML(a, `${from}<span class="spacer" style="flex:1"></span>
1117
+ <a class="btn primary" href="/agents.html?agent=${enc}">Run</a>
1118
+ ${a.share_id ? `<button class="btn ghost danger" data-unshare="${esc(a.share_id)}" data-name="${esc(a.name)}">Remove</button>` : ""}`);
1119
+ }
1108
1120
  const actions = [
1109
1121
  `<a class="btn primary" href="/agents.html?agent=${enc}">Run</a>`,
1110
1122
  `<button class="btn" data-edit="${esc(a.name)}">Edit</button>`,
@@ -1117,6 +1129,7 @@
1117
1129
  : "<div class='empty'>No custom agents assigned to you yet. Create one under <b>Your platform agents</b> below, or in the web app.</div>";
1118
1130
 
1119
1131
  wireContentToggles($("local-agents"));
1132
+ $("local-agents").querySelectorAll("[data-unshare]").forEach(b => b.onclick = () => removeShared(b.dataset.unshare, b.dataset.name));
1120
1133
  $("local-agents").querySelectorAll("[data-enable]").forEach(b => b.onclick = () => setStatus(b.dataset.enable, "active"));
1121
1134
  $("local-agents").querySelectorAll("[data-disable]").forEach(b => b.onclick = () => setStatus(b.dataset.disable, "disabled"));
1122
1135
  $("local-agents").querySelectorAll("[data-del]").forEach(b => b.onclick = async () => {
@@ -1187,6 +1200,17 @@
1187
1200
  if ($("key-add-toggle")) $("key-add-toggle").textContent = "+ Add API key";
1188
1201
  }
1189
1202
 
1203
+ // Drop an agent someone shared with you (they can share it again later).
1204
+ async function removeShared(shareId, name) {
1205
+ if (!confirm(`Remove “${name}” from your agents? The owner can share it with you again.`)) return;
1206
+ try {
1207
+ await api(`/api/ui/agents/shares/${encodeURIComponent(shareId)}`, { method: "DELETE" });
1208
+ toast("Removed " + name, "ok");
1209
+ } catch (e) { toast("Remove failed: " + (e.message || ""), "err"); }
1210
+ document.dispatchEvent(new CustomEvent("agentos:shares-changed"));
1211
+ }
1212
+ document.addEventListener("agentos:shares-changed", () => { loadLocalAgents(); cfLoad(); });
1213
+
1190
1214
  function onAgentSelect() {
1191
1215
  const m = caMeta[$("key-agent") && $("key-agent").value];
1192
1216
  if ($("ca-about")) $("ca-about").textContent = m ? (m.description || "No description provided.") : "Pick an agent.";
@@ -1481,10 +1505,19 @@
1481
1505
  <button class="btn danger cf-del" data-id="${esc(a.id)}" data-name="${esc(a.name)}">Delete</button>`
1482
1506
  : `<span class="muted" style="font-size:12px">read-only</span>`}
1483
1507
  </div>`;
1484
- const personal = d.personal || [], dept = d.department || [];
1485
- box.innerHTML = (personal.length || dept.length)
1508
+ const personal = d.personal || [], dept = d.department || [], shared = d.shared || [];
1509
+ const sharedRow = (a) => `<div class="cf-item">
1510
+ <span class="n">${esc(a.name)}</span>
1511
+ <span class="pill shared">shared</span>
1512
+ <span class="muted" style="font-size:12.5px">from <b>${esc(a.shared_by || "?")}</b>${a.via ? " · via " + esc(a.via) : ""}</span>
1513
+ <a class="btn" href="/agents.html?agent=${encodeURIComponent(a.name)}">Run</a>
1514
+ ${a.share_id ? `<button class="btn ghost danger cf-unshare" data-id="${esc(a.share_id)}" data-name="${esc(a.name)}">Remove</button>` : ""}
1515
+ </div>`;
1516
+ box.innerHTML = (personal.length || dept.length || shared.length)
1486
1517
  ? personal.map(a => row(a, true)).join("") + dept.map(a => row(a, false)).join("")
1518
+ + (shared.length ? `<div class="cf-group">Shared with you</div>` + shared.map(sharedRow).join("") : "")
1487
1519
  : `<div class="empty">No platform agents yet — press <b>New agent</b>.</div>`;
1520
+ box.querySelectorAll(".cf-unshare").forEach(b => b.onclick = () => removeShared(b.dataset.id, b.dataset.name));
1488
1521
  box.querySelectorAll(".cf-edit").forEach(b => b.onclick = () => cfOpen(b.dataset.id));
1489
1522
  box.querySelectorAll(".cf-del").forEach(b => b.onclick = () => cfDelete(b.dataset.id, b.dataset.name));
1490
1523
  } catch (e) {
@@ -857,3 +857,7 @@ select:focus, input[type=number]:focus, input[type=time]:focus, input[type=datet
857
857
  .hp-ask-row { display: grid; gap: 6px; font-size: 14px; }
858
858
  .hp-ask-row input { width: 100%; }
859
859
  .hp-asks-send { justify-self: start; }
860
+
861
+ /* Agents shared with you, on the Custom Agents page */
862
+ .pill.shared { background: color-mix(in srgb, var(--violet, #7c3aed) 14%, transparent); color: var(--violet, #7c3aed); }
863
+ .cf-group { font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); padding: 14px 0 4px; }
@@ -168,3 +168,91 @@ class TestUiAgentsAll:
168
168
  with patch("sdk.client.BackendClient.from_config", return_value=client):
169
169
  out = await api.agents_all(department_id="d-1")
170
170
  assert [(a["name"], a["source"]) for a in out["agents"]] == [("Shared", "custom")]
171
+
172
+
173
+ def _shared_row(name, *, by="Javaid Iqbal", via=None, share_id="sh-1"):
174
+ return {**_row(name, variables=("repo",)), "relation_id": "someone-else", "source": "shared",
175
+ "share_id": share_id, "shared_by": {"id": "u-j", "name": by, "email": "j@x"},
176
+ "via_team": via}
177
+
178
+
179
+ class TestSharedAgentsOnCustomAgentsPage:
180
+ """Accepted shares appear on Custom Agents next to your own — by NAME, read-only."""
181
+
182
+ @pytest.mark.asyncio
183
+ async def test_installed_list_includes_accepted_shares(self):
184
+ from sdk.ui import api
185
+
186
+ client = SimpleNamespace(
187
+ list_custom_agents=AsyncMock(return_value=[_row("mine"), _row("clash")]),
188
+ list_shared_agents=AsyncMock(return_value=[
189
+ _shared_row("release-notes", via={"id": "d1", "name": "Machine Learning", "kind": "department"}),
190
+ _shared_row("clash")]),
191
+ )
192
+ with patch("sdk.client.BackendClient.from_config", return_value=client):
193
+ out = await api.agents()
194
+ names = [(a["name"], a.get("source")) for a in out["agents"]]
195
+ assert names == [("mine", None), ("clash", None), ("release-notes", "shared")]
196
+ shared = out["agents"][-1]
197
+ assert shared["shared_by"] == "Javaid Iqbal" and shared["share_id"] == "sh-1"
198
+ assert shared["via"] == "department Machine Learning"
199
+ assert out["shared_error"] == ""
200
+
201
+ @pytest.mark.asyncio
202
+ async def test_backend_without_sharing_is_not_an_error(self):
203
+ from sdk.exceptions import BackendFeatureMissing
204
+ from sdk.ui import api
205
+
206
+ client = SimpleNamespace(
207
+ list_custom_agents=AsyncMock(return_value=[_row("mine")]),
208
+ list_shared_agents=AsyncMock(side_effect=BackendFeatureMissing("Agent sharing", "u")),
209
+ )
210
+ with patch("sdk.client.BackendClient.from_config", return_value=client):
211
+ out = await api.agents()
212
+ assert [a["name"] for a in out["agents"]] == ["mine"] and out["shared_error"] == ""
213
+
214
+ @pytest.mark.asyncio
215
+ async def test_platform_list_has_a_shared_group(self):
216
+ from sdk.ui import api
217
+
218
+ client = SimpleNamespace(
219
+ list_gateway_agents_by_scope=AsyncMock(return_value={"personal": [], "department": []}),
220
+ list_shared_agents=AsyncMock(return_value=[_shared_row("release-notes", via={"id": "t", "name": "AI Team"})]),
221
+ )
222
+ with patch("sdk.client.BackendClient.from_config", return_value=client):
223
+ out = await api.custom_agents_list()
224
+ assert out["shared"] == [{"id": "id-release-notes", "name": "release-notes", "status": "active",
225
+ "shared_by": "Javaid Iqbal", "via": "team AI Team", "share_id": "sh-1"}]
226
+
227
+ @pytest.mark.asyncio
228
+ async def test_inputs_of_a_platform_or_shared_agent_render(self):
229
+ from sdk.ui import api
230
+
231
+ client = SimpleNamespace(
232
+ list_custom_agents=AsyncMock(return_value=[]),
233
+ list_department_agents=AsyncMock(return_value=[]),
234
+ list_shared_agents=AsyncMock(return_value=[
235
+ {**_shared_row("release-notes"),
236
+ "prompt": {"system_prompt": "Write notes for {{repo}} since {{tag}}.",
237
+ "variables": [{"name": "repo"}, {"name": "tag"}]}}]),
238
+ )
239
+ with patch("sdk.client.BackendClient.from_config", return_value=client), \
240
+ patch("sdk.agents.manifest.load_agents", return_value=[]), \
241
+ patch("sdk.agents.chat._find_agent", return_value=None):
242
+ out = await api.agent_vars(name="release-notes")
243
+ assert out["variables"] == ["repo", "tag"]
244
+
245
+ @pytest.mark.asyncio
246
+ async def test_405_from_an_old_backend_means_not_deployed(self):
247
+ from sdk.client import BackendClient
248
+ from sdk.exceptions import BackendFeatureMissing
249
+
250
+ client = BackendClient.__new__(BackendClient)
251
+ client._base_url, client._headers = "https://b", {}
252
+ client._url = lambda p: "https://b" + p
253
+ resp = SimpleNamespace(status_code=405, json=lambda: {})
254
+ http = AsyncMock()
255
+ http.__aenter__.return_value.get = AsyncMock(return_value=resp)
256
+ with patch("sdk.client.httpx.AsyncClient", return_value=http):
257
+ with pytest.raises(BackendFeatureMissing):
258
+ await client.list_shared_agents()
File without changes