devops-bot-sdk 1.6.25__tar.gz → 1.6.28__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 (159) hide show
  1. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/PKG-INFO +3 -1
  2. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/devops_bot_sdk.egg-info/PKG-INFO +3 -1
  3. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/devops_bot_sdk.egg-info/SOURCES.txt +6 -0
  4. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/devops_bot_sdk.egg-info/requires.txt +2 -0
  5. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/pyproject.toml +5 -0
  6. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/__init__.py +2 -2
  7. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/activity.py +47 -14
  8. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/cli.py +278 -1
  9. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/client.py +230 -1
  10. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/exceptions.py +17 -0
  11. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/models/responses.py +73 -0
  12. devops_bot_sdk-1.6.28/sdk/proof_readers.py +420 -0
  13. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/run_auto.py +89 -1
  14. devops_bot_sdk-1.6.28/sdk/self_report.py +768 -0
  15. devops_bot_sdk-1.6.28/sdk/self_report_local.py +631 -0
  16. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/api.py +240 -1
  17. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/models.py +29 -0
  18. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/app.js +202 -1
  19. devops_bot_sdk-1.6.28/sdk/ui/static/report.html +97 -0
  20. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/styles.css +30 -0
  21. devops_bot_sdk-1.6.28/tests/test_proof_readers.py +263 -0
  22. devops_bot_sdk-1.6.28/tests/test_self_report.py +1060 -0
  23. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/README.md +0 -0
  24. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
  25. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
  26. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/devops_bot_sdk.egg-info/top_level.txt +0 -0
  27. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agentd.py +0 -0
  28. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/__init__.py +0 -0
  29. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/builder.py +0 -0
  30. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/chat.py +0 -0
  31. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/connectors.py +0 -0
  32. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/engines/__init__.py +0 -0
  33. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/engines/claude_code.py +0 -0
  34. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/engines/http.py +0 -0
  35. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/engines/mcp.py +0 -0
  36. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/engines/n8n.py +0 -0
  37. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/engines/shell.py +0 -0
  38. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/integrations.py +0 -0
  39. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/inventory.py +0 -0
  40. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/library/__init__.py +0 -0
  41. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/manifest.py +0 -0
  42. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/prompt_studio.py +0 -0
  43. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/prompt_template.py +0 -0
  44. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/prompt_vars.py +0 -0
  45. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/run_log.py +0 -0
  46. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/schedules.py +0 -0
  47. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/secrets.py +0 -0
  48. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/ticket_run.py +0 -0
  49. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/usage.py +0 -0
  50. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/agents/varstore.py +0 -0
  51. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/collectors/__init__.py +0 -0
  52. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/collectors/files.py +0 -0
  53. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/collectors/process.py +0 -0
  54. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/collectors/screenshot.py +0 -0
  55. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/config.py +0 -0
  56. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/crucial.py +0 -0
  57. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/departments.py +0 -0
  58. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/design_verify/__init__.py +0 -0
  59. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/design_verify/assets.py +0 -0
  60. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/design_verify/bootstrap.py +0 -0
  61. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/design_verify/browser.py +0 -0
  62. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/design_verify/compare.py +0 -0
  63. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/design_verify/loop.py +0 -0
  64. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/formats.py +0 -0
  65. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/git_ops.py +0 -0
  66. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/github_ingest.py +0 -0
  67. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/graph_recon.py +0 -0
  68. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/graphify.py +0 -0
  69. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/hooks/__init__.py +0 -0
  70. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/hooks/crucial_guard.py +0 -0
  71. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/intake.py +0 -0
  72. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ipc/__init__.py +0 -0
  73. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ipc/electron_bridge.py +0 -0
  74. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ipc/handlers.py +0 -0
  75. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/local_exec.py +0 -0
  76. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/models/__init__.py +0 -0
  77. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/models/envelope.py +0 -0
  78. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/models/requests.py +0 -0
  79. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/models/snapshots.py +0 -0
  80. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/phase_timer.py +0 -0
  81. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/plan_run.py +0 -0
  82. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/platform_compat.py +0 -0
  83. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/py.typed +0 -0
  84. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/scheduler.py +0 -0
  85. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/sse.py +0 -0
  86. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/task_file.py +0 -0
  87. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/test.py +0 -0
  88. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/test_pipeline.py +0 -0
  89. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ticket_fields.py +0 -0
  90. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/__init__.py +0 -0
  91. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/dashboard.py +0 -0
  92. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/health.py +0 -0
  93. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/ip_allowlist.py +0 -0
  94. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/jobs.py +0 -0
  95. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/runner.py +0 -0
  96. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/security.py +0 -0
  97. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/server.py +0 -0
  98. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/service.py +0 -0
  99. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/session.py +0 -0
  100. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/setup_manager.py +0 -0
  101. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/agents.html +0 -0
  102. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/chat.html +0 -0
  103. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/custom-agents.html +0 -0
  104. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/default-agents.html +0 -0
  105. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/index.html +0 -0
  106. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/login.html +0 -0
  107. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/runs.html +0 -0
  108. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/schedules.html +0 -0
  109. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/setup.html +0 -0
  110. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/ui/static/tickets.html +0 -0
  111. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/updater.py +0 -0
  112. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/sdk/vps_health.py +0 -0
  113. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/setup.cfg +0 -0
  114. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_activity.py +0 -0
  115. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_activity_tracking.py +0 -0
  116. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_chat_features.py +0 -0
  117. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_listing.py +0 -0
  118. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_prompt_async.py +0 -0
  119. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_prompt_models.py +0 -0
  120. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_run_ticket.py +0 -0
  121. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_schedules.py +0 -0
  122. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agent_workspace_settings.py +0 -0
  123. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_agents_connectors_builder.py +0 -0
  124. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_allowed_tools_config.py +0 -0
  125. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_auto_agent_dispatch.py +0 -0
  126. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_client_jira_projects.py +0 -0
  127. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_config_token_diagnostics.py +0 -0
  128. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_configure_token_owner.py +0 -0
  129. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_console_encoding.py +0 -0
  130. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_departments.py +0 -0
  131. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_epic_decompose_run.py +0 -0
  132. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_epic_inherited_agent_id.py +0 -0
  133. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_epic_session_isolation.py +0 -0
  134. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_formats.py +0 -0
  135. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_git_action.py +0 -0
  136. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_github_ingest.py +0 -0
  137. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_graph_recon.py +0 -0
  138. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_graphify_build.py +0 -0
  139. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_graphify_hook_install.py +0 -0
  140. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_health.py +0 -0
  141. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_intake_plan_review.py +0 -0
  142. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_otp_login.py +0 -0
  143. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_phase_timer.py +0 -0
  144. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_plan_new_command.py +0 -0
  145. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_plan_run_activity.py +0 -0
  146. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_recon_session_isolation.py +0 -0
  147. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_run_auto_agent_only.py +0 -0
  148. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_run_outputs.py +0 -0
  149. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_schedule_api.py +0 -0
  150. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_scheduler.py +0 -0
  151. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_service_token_warning.py +0 -0
  152. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_task_file_and_plan_run.py +0 -0
  153. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_task_file_format_doc.py +0 -0
  154. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_ticket_fields.py +0 -0
  155. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_ticket_run_resolve_by_id.py +0 -0
  156. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_ticket_speed_fixes.py +0 -0
  157. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_update_timer.py +0 -0
  158. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_updater_extras.py +0 -0
  159. {devops_bot_sdk-1.6.25 → devops_bot_sdk-1.6.28}/tests/test_vps_health.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.6.25
3
+ Version: 1.6.28
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
@@ -21,11 +21,13 @@ Provides-Extra: ui
21
21
  Requires-Dist: fastapi>=0.110; extra == "ui"
22
22
  Requires-Dist: uvicorn>=0.29; extra == "ui"
23
23
  Requires-Dist: psutil>=5.9; extra == "ui"
24
+ Requires-Dist: python-multipart>=0.0.9; extra == "ui"
24
25
  Provides-Extra: all
25
26
  Requires-Dist: Pillow>=10.0; extra == "all"
26
27
  Requires-Dist: psutil>=5.9; extra == "all"
27
28
  Requires-Dist: fastapi>=0.110; extra == "all"
28
29
  Requires-Dist: uvicorn>=0.29; extra == "all"
30
+ Requires-Dist: python-multipart>=0.0.9; extra == "all"
29
31
 
30
32
  # DevOpsBot SDK
31
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.6.25
3
+ Version: 1.6.28
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
@@ -21,11 +21,13 @@ Provides-Extra: ui
21
21
  Requires-Dist: fastapi>=0.110; extra == "ui"
22
22
  Requires-Dist: uvicorn>=0.29; extra == "ui"
23
23
  Requires-Dist: psutil>=5.9; extra == "ui"
24
+ Requires-Dist: python-multipart>=0.0.9; extra == "ui"
24
25
  Provides-Extra: all
25
26
  Requires-Dist: Pillow>=10.0; extra == "all"
26
27
  Requires-Dist: psutil>=5.9; extra == "all"
27
28
  Requires-Dist: fastapi>=0.110; extra == "all"
28
29
  Requires-Dist: uvicorn>=0.29; extra == "all"
30
+ Requires-Dist: python-multipart>=0.0.9; extra == "all"
29
31
 
30
32
  # DevOpsBot SDK
31
33
 
@@ -24,9 +24,12 @@ sdk/local_exec.py
24
24
  sdk/phase_timer.py
25
25
  sdk/plan_run.py
26
26
  sdk/platform_compat.py
27
+ sdk/proof_readers.py
27
28
  sdk/py.typed
28
29
  sdk/run_auto.py
29
30
  sdk/scheduler.py
31
+ sdk/self_report.py
32
+ sdk/self_report_local.py
30
33
  sdk/sse.py
31
34
  sdk/task_file.py
32
35
  sdk/test.py
@@ -98,6 +101,7 @@ sdk/ui/static/custom-agents.html
98
101
  sdk/ui/static/default-agents.html
99
102
  sdk/ui/static/index.html
100
103
  sdk/ui/static/login.html
104
+ sdk/ui/static/report.html
101
105
  sdk/ui/static/runs.html
102
106
  sdk/ui/static/schedules.html
103
107
  sdk/ui/static/setup.html
@@ -135,11 +139,13 @@ tests/test_otp_login.py
135
139
  tests/test_phase_timer.py
136
140
  tests/test_plan_new_command.py
137
141
  tests/test_plan_run_activity.py
142
+ tests/test_proof_readers.py
138
143
  tests/test_recon_session_isolation.py
139
144
  tests/test_run_auto_agent_only.py
140
145
  tests/test_run_outputs.py
141
146
  tests/test_schedule_api.py
142
147
  tests/test_scheduler.py
148
+ tests/test_self_report.py
143
149
  tests/test_service_token_warning.py
144
150
  tests/test_task_file_and_plan_run.py
145
151
  tests/test_task_file_format_doc.py
@@ -9,6 +9,7 @@ Pillow>=10.0
9
9
  psutil>=5.9
10
10
  fastapi>=0.110
11
11
  uvicorn>=0.29
12
+ python-multipart>=0.0.9
12
13
 
13
14
  [process]
14
15
  psutil>=5.9
@@ -20,3 +21,4 @@ Pillow>=10.0
20
21
  fastapi>=0.110
21
22
  uvicorn>=0.29
22
23
  psutil>=5.9
24
+ python-multipart>=0.0.9
@@ -36,12 +36,17 @@ ui = [
36
36
  # bootstrap installs `[ui]` only, so without it here every
37
37
  # VPS reports "resources.available: False" and the health
38
38
  # cron can only send status + IP.
39
+ "python-multipart>=0.0.9", # POST /api/ui/reports/self — the ONE multipart route in
40
+ # the panel (self-report proofs are file uploads). Starlette
41
+ # raises at request time without it, so it belongs in [ui]
42
+ # alongside fastapi rather than in an optional extra.
39
43
  ]
40
44
  all = [
41
45
  "Pillow>=10.0",
42
46
  "psutil>=5.9",
43
47
  "fastapi>=0.110",
44
48
  "uvicorn>=0.29",
49
+ "python-multipart>=0.0.9",
45
50
  ]
46
51
 
47
52
  [project.scripts]
@@ -1,6 +1,6 @@
1
1
  """AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
2
2
 
3
- Version: 1.6.25
3
+ Version: 1.6.28
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.6.25" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
37
+ __version__ = "1.6.28" # 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
@@ -124,6 +124,46 @@ def _lines_block(lines: list[str]) -> str:
124
124
  return "\n".join(reversed(out))
125
125
 
126
126
 
127
+ def mirror_to_auto_log_line(text: str, *, pointer: str = "") -> bool:
128
+ """Append ONE already-composed summary line to ``~/.agentos/auto.log``.
129
+
130
+ The append-with-opt-out core of :func:`mirror_to_auto_log`, split out so a
131
+ caller that is not an agent run can use it. `agentos-auto logs [-f]` tails
132
+ that file and nothing else, so anything a person should be able to watch
133
+ live has to land here — including a self-report submission, which has no
134
+ agent, no `agent_dir()` and no `describe()` verb to render.
135
+
136
+ `text` is written verbatim under the shared ` • [<stamp>] ` prefix so every
137
+ line in the file reads the same way. `pointer` adds the indented `↳` line
138
+ the agent path uses for a transcript path; pass an empty string for none.
139
+
140
+ Honours ``AGENTOS_NO_AGENT_LOG_MIRROR=1`` and never raises: a log line must
141
+ never break the work that produced it. Returns True when a line was written.
142
+ """
143
+ line = str(text or "").strip()
144
+ if not line:
145
+ return False
146
+ if os.getenv("AGENTOS_NO_AGENT_LOG_MIRROR"):
147
+ return False
148
+ try:
149
+ from sdk.run_auto import _LOG_FILE
150
+ except Exception: # noqa: BLE001 — never break a caller over a log line
151
+ return False
152
+
153
+ stamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%SZ")
154
+ out = f" • [{stamp}] {line}"
155
+ if pointer:
156
+ out += f"\n ↳ {pointer}"
157
+ try:
158
+ _LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
159
+ with _LOG_FILE.open("a", encoding="utf-8") as fh:
160
+ fh.write(out + "\n")
161
+ return True
162
+ except Exception as exc: # noqa: BLE001
163
+ logger.debug("auto.log mirror failed err=%s", exc)
164
+ return False
165
+
166
+
127
167
  def mirror_to_auto_log(name: str, kind: str, result: dict | None,
128
168
  duration_s: float = 0.0, *, detail: str = "",
129
169
  task_id: str = "") -> bool:
@@ -141,18 +181,20 @@ def mirror_to_auto_log(name: str, kind: str, result: dict | None,
141
181
  the pointer below is how you get from one to the other. Best-effort and
142
182
  silent on failure: a log line must never break a run. Set
143
183
  ``AGENTOS_NO_AGENT_LOG_MIRROR=1`` to turn it off.
184
+
185
+ The append itself lives in :func:`mirror_to_auto_log_line`; what stays here
186
+ is the AGENT-shaped part — the `describe()` verb, the ticket suffix and the
187
+ `agent_dir()` transcript pointer — none of which a non-agent caller wants.
144
188
  """
145
189
  if os.getenv("AGENTOS_NO_AGENT_LOG_MIRROR"):
146
190
  return False
147
191
  try:
148
192
  from sdk.agents.run_log import agent_dir
149
- from sdk.run_auto import _LOG_FILE
150
193
  except Exception: # noqa: BLE001 — never break a run over a log line
151
194
  return False
152
195
 
153
196
  res = result or {}
154
- stamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%SZ")
155
- line = f" • [{stamp}] {describe(name, kind, res, duration_s, detail)}"
197
+ line = describe(name, kind, res, duration_s, detail)
156
198
  # agentd passes the ticket BOTH as `detail` ("task T1") and as `task_id`, so an
157
199
  # unconditional suffix renders "… — task T1 · task T1".
158
200
  if task_id and f"task {task_id}" not in line:
@@ -161,17 +203,8 @@ def mirror_to_auto_log(name: str, kind: str, result: dict | None,
161
203
  where = agent_dir(name)
162
204
  except Exception: # noqa: BLE001
163
205
  where = None
164
- if where:
165
- line += f"\n ↳ transcript: {where}"
166
-
167
- try:
168
- _LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
169
- with _LOG_FILE.open("a", encoding="utf-8") as fh:
170
- fh.write(line + "\n")
171
- return True
172
- except Exception as exc: # noqa: BLE001
173
- logger.debug("auto.log mirror failed agent=%s err=%s", name, exc)
174
- return False
206
+ return mirror_to_auto_log_line(
207
+ line, pointer=f"transcript: {where}" if where else "")
175
208
 
176
209
 
177
210
  async def emit(name: str, kind: str, result: dict | None, duration_s: float = 0.0,
@@ -58,6 +58,22 @@ Command surface:
58
58
  agentos integration rm <name>
59
59
  Remove a registered integration.
60
60
 
61
+ agentos report submit [--date YYYY-MM-DD] (--text "…" | --file PATH)
62
+ [--project NAME] [--proof PATH|URL]… [--no-wait]
63
+ Report work that never reached Jira or GitHub, attach proofs (local
64
+ files and/or http(s) URLs), and have the submission SCORED against
65
+ them. Prints the submission id, the score and the verdict. The same
66
+ mechanism the control panel's Report work page uses — see
67
+ sdk/self_report.py.
68
+ agentos report list [--limit N]
69
+ Recent submissions, newest first: date, score, verdict, id.
70
+ agentos report formats
71
+ Every proof format the SDK can read on this machine, and what happens
72
+ to the ones it cannot.
73
+ agentos report show <ID>
74
+ One submission in full — its text, its proofs and the evaluator's
75
+ per-criterion reasoning.
76
+
61
77
  agentos agentd start [--foreground]
62
78
  Start the local agent daemon (background by default).
63
79
  agentos agentd status
@@ -123,12 +139,16 @@ def main() -> None:
123
139
  _github_command(rest)
124
140
  return
125
141
 
142
+ if noun == "report":
143
+ _report_command(rest)
144
+ return
145
+
126
146
  _print_usage()
127
147
  sys.exit(1)
128
148
 
129
149
 
130
150
  def _print_usage() -> None:
131
- print("usage: agentos <configure|chat|agent|integration|default-agents|agentd|github> ...")
151
+ print("usage: agentos <configure|chat|agent|integration|default-agents|agentd|github|report> ...")
132
152
  print()
133
153
  print(" agentos configure [--rotate]")
134
154
  print(" agentos chat [--product-id ID] [--pv-id ID] [--no-autorun] # requirements → ticket")
@@ -138,6 +158,7 @@ def _print_usage() -> None:
138
158
  print(" agentos default-agents list [--department-id UUID] # read-only; agents are created in the web app")
139
159
  print(" agentos agentd <start [--foreground]|status>")
140
160
  print(" agentos github <ingest [--days N]|status> # PR ingestion; --days N backfills N days")
161
+ print(" agentos report <submit|list|show ID> # report work Jira/GitHub never saw")
141
162
 
142
163
 
143
164
  # ── agent ────────────────────────────────────────────────────────────────
@@ -703,5 +724,261 @@ def _github_command(args: list[str]) -> None:
703
724
  sys.exit(1)
704
725
 
705
726
 
727
+ # ── report ───────────────────────────────────────────────────────────────
728
+
729
+ def _report_usage() -> None:
730
+ print("usage: agentos report submit [--date YYYY-MM-DD] (--text \"…\" | --file PATH)")
731
+ print(" [--project NAME] [--proof PATH|URL]… [--no-wait]")
732
+ print(" agentos report list [--limit N]")
733
+ print(" agentos report show <ID>")
734
+ print(" agentos report formats # what a proof can be")
735
+ print()
736
+ print(" Report work that never reached Jira or GitHub, attach proofs, and have the")
737
+ print(" submission scored against them. It then appears in your daily and overall")
738
+ print(" reports and in the reporting chat.")
739
+ print()
740
+ print(" --date the day the work happened (default: today; never the future)")
741
+ print(" --text the report body; --file reads it from a file instead")
742
+ print(" --proof repeatable — a local file path OR an http(s) URL")
743
+ print(" --no-wait submit and exit without waiting for the verdict")
744
+
745
+
746
+ def _report_flag(args: list[str], name: str) -> list[str]:
747
+ """Every ``--name VALUE`` in args, in order. Repeatable flags collect.
748
+
749
+ Same hand-rolled shape as `run_auto._flag_values` — this CLI has no
750
+ argparse subparsers by design (see the module docstring).
751
+ """
752
+ out: list[str] = []
753
+ for i, a in enumerate(args):
754
+ if a == name and i + 1 < len(args):
755
+ out.append(args[i + 1])
756
+ elif a.startswith(name + "="):
757
+ out.append(a.split("=", 1)[1])
758
+ return out
759
+
760
+
761
+ def _report_command(args: list[str]) -> None:
762
+ """``agentos report submit|list|show`` — the CLI half of self-reporting.
763
+
764
+ Every verb resolves the backend client the same way and fails the same way
765
+ when the box has no ``co_`` token: the shared "not configured" message
766
+ ``agentos configure`` prints, and exit 1 — never a traceback.
767
+ """
768
+ from sdk.exceptions import TokenNotConfigured
769
+ from sdk.self_report import _SUBMIT_ERRORS, SelfReportError
770
+
771
+ verb = args[0] if args else None
772
+ rest = args[1:]
773
+
774
+ try:
775
+ if verb == "submit":
776
+ _report_submit(rest)
777
+ return
778
+ if verb == "list":
779
+ limits = _report_flag(rest, "--limit")
780
+ _report_list(int(limits[0]) if limits and limits[0].isdigit() else 25)
781
+ return
782
+ if verb == "show" and rest and not rest[0].startswith("-"):
783
+ _report_show(rest[0])
784
+ return
785
+ if verb == "formats":
786
+ _report_formats()
787
+ return
788
+ except TokenNotConfigured as exc:
789
+ # The same failure every other verb gives on an unconfigured machine —
790
+ # `sdk.config` composes a cause-specific message; we only add the prefix.
791
+ print(f"error: {exc}")
792
+ sys.exit(1)
793
+ except SelfReportError as exc:
794
+ print(f"error: {exc}")
795
+ sys.exit(1)
796
+ except _SUBMIT_ERRORS as exc:
797
+ # The backend answered and the answer was no. Its own words — a 404 says
798
+ # the deployment has no self-report routes, which is not a token problem
799
+ # and must not be printed as one.
800
+ print(f"error: {exc}")
801
+ sys.exit(1)
802
+
803
+ _report_usage()
804
+ sys.exit(1)
805
+
806
+
807
+ def _report_submit(args: list[str]) -> None:
808
+ """Submit one report, then print the id, the score and the verdict."""
809
+ from sdk import self_report
810
+
811
+ texts = _report_flag(args, "--text")
812
+ files = _report_flag(args, "--file")
813
+ if not texts and not files:
814
+ # A usage line and a non-zero exit — not an empty submission.
815
+ print("error: say what you did — pass --text \"…\" or --file report.md")
816
+ _report_usage()
817
+ sys.exit(1)
818
+
819
+ body = texts[0] if texts else ""
820
+ if files:
821
+ src = Path(files[0]).expanduser()
822
+ if not src.is_file():
823
+ print(f"error: no such file: {src}")
824
+ sys.exit(1)
825
+ try:
826
+ # --file supplies the body; a --text alongside it is a header line.
827
+ file_body = src.read_text(encoding="utf-8", errors="replace").strip()
828
+ except OSError as exc:
829
+ print(f"error: cannot read {src}: {exc}")
830
+ sys.exit(1)
831
+ body = f"{body}\n\n{file_body}".strip() if body else file_body
832
+
833
+ dates = _report_flag(args, "--date")
834
+ projects = _report_flag(args, "--project")
835
+ proofs, rejected = self_report.collect_proofs(_report_flag(args, "--proof"))
836
+ for r in rejected:
837
+ print(f"⚠ proof skipped — {r.get('name', '')}: {r.get('reason', '')}")
838
+
839
+ result = asyncio.run(self_report.submit_and_evaluate(
840
+ date=dates[0] if dates else "",
841
+ text=body,
842
+ project=projects[0] if projects else "",
843
+ proofs=proofs,
844
+ rejected=rejected,
845
+ wait="--no-wait" not in args,
846
+ ))
847
+
848
+ status = str(result.get("status") or "")
849
+ if status == "failed":
850
+ print(f"error: {result.get('error') or 'the submission was not stored.'}")
851
+ sys.exit(1)
852
+
853
+ print(f"submission : {result.get('id') or '(no id returned)'}")
854
+ print(f"date : {result.get('date', '')}"
855
+ + (f" project: {result['project']}" if result.get("project") else ""))
856
+ print(f"proofs : {len(result.get('proofs') or [])} accepted"
857
+ + (f", {len(result.get('rejected') or [])} skipped" if result.get("rejected") else ""))
858
+ if result.get("stored") == "gateway":
859
+ # Say which half holds it. "Recorded" and "recorded in the durable store"
860
+ # are different promises, and only the person filing it can decide whether
861
+ # the difference matters to them.
862
+ print("stored : locally + the activity feed the daily/overall reports read")
863
+ print(" (the platform's self-report store is not deployed on this "
864
+ "backend; scored on this machine)")
865
+ if status == "evaluated":
866
+ print(f"score : {result.get('score', 0)}/100")
867
+ print(f"verdict : {result.get('verdict') or 'unknown'}")
868
+ elif status == "evaluation_failed":
869
+ print("score : —")
870
+ print("verdict : evaluation failed — the submission is stored and can be "
871
+ "re-evaluated")
872
+ else:
873
+ print(f"status : {status or 'accepted'} — not evaluated yet; "
874
+ f"`agentos report show {result.get('id', '')}` for the verdict")
875
+ # Exit 0 whenever the submission was STORED. A failed evaluation is a
876
+ # backend-side outcome the person cannot act on, and it is recorded, not lost.
877
+
878
+
879
+ def _report_formats() -> None:
880
+ """What the SDK can read from a proof without the backend.
881
+
882
+ Worth its own verb: a person choosing what to attach needs to know that a
883
+ screen recording is usable and a .7z is not BEFORE they file, not after the
884
+ score comes back lower than the work deserved.
885
+ """
886
+ from sdk import proof_readers
887
+
888
+ print("Proof files the SDK reads on this machine:\n")
889
+ for group, exts in proof_readers.supported().items():
890
+ joined = " ".join(exts)
891
+ print(f" {group}")
892
+ for i in range(0, len(joined), 68):
893
+ print(f" {joined[i:i + 68]}")
894
+ print()
895
+ if proof_readers.have_ffmpeg():
896
+ print(" ffmpeg is installed — video proofs are sampled into still frames the")
897
+ print(" scorer can look at.")
898
+ else:
899
+ print(" ffmpeg is NOT installed — a video proof is recorded and described, but")
900
+ print(" its content cannot be inspected. Install ffmpeg to change that.")
901
+ print(" Audio cannot be transcribed locally; it is recorded and described.")
902
+ print(" URL proofs are fetched here. A GitHub PR or issue is read through the API")
903
+ print(" with your linked token, so proofs in private repos are readable.")
904
+
905
+
906
+ def _report_list(limit: int) -> None:
907
+ """Recent submissions, newest first — date, score, verdict, id."""
908
+ from sdk import self_report
909
+
910
+ rows = asyncio.run(self_report.list_reports(limit))
911
+ if not rows:
912
+ print("no submissions yet — `agentos report submit --text \"…\"` records one.")
913
+ return
914
+ print(f"{'DATE':<12}{'SCORE':<8}{'VERDICT':<26}{'ID':<26}WHAT")
915
+ for r in rows:
916
+ ev = r.get("evaluation") or {}
917
+ score = f"{ev.get('score')}/100" if r.get("status") == "evaluated" else "—"
918
+ verdict = (ev.get("verdict") or r.get("status") or "")[:25]
919
+ what = " ".join(str(r.get("text") or "").split())[:46]
920
+ rid = str(r.get("id", "")) + (" *" if r.get("stored") == "gateway" else "")
921
+ print(f"{str(r.get('date', '')):<12}{score:<8}{verdict:<26}{rid:<26}{what}")
922
+ if any(r.get("stored") == "gateway" for r in rows):
923
+ print("\n* recorded on this machine and in the activity feed — the platform's "
924
+ "self-report store was not deployed when it was filed.")
925
+
926
+
927
+ def _report_show(report_id: str) -> None:
928
+ """One submission in full — its text, its proofs, and the per-criterion reasoning."""
929
+ from sdk import self_report
930
+
931
+ sub = asyncio.run(self_report.show_report(report_id))
932
+ if not sub:
933
+ print(f"error: no submission {report_id} (or it is not yours).")
934
+ sys.exit(1)
935
+
936
+ ev = sub.get("evaluation") or {}
937
+ print(f"submission : {sub.get('id', report_id)}")
938
+ print(f"date : {sub.get('date', '')}")
939
+ if sub.get("project"):
940
+ print(f"project : {sub['project']}")
941
+ print(f"status : {sub.get('status', '')}")
942
+ if sub.get("status") == "evaluated":
943
+ print(f"score : {ev.get('score', 0)}/100")
944
+ print(f"verdict : {ev.get('verdict', '')}")
945
+ print()
946
+ print("what I did")
947
+ for line in str(sub.get("text") or "").splitlines() or [""]:
948
+ print(f" {line}")
949
+
950
+ proofs = sub.get("proofs") or []
951
+ print()
952
+ print(f"proofs ({len(proofs)})")
953
+ if not proofs:
954
+ print(" (none — an unproven report is recorded, never silently dropped)")
955
+ for p in proofs:
956
+ head = f" · {p.get('name') or p.get('url') or 'proof'}"
957
+ judged = p.get("judgement") or "not judged"
958
+ print(f"{head} [{judged}]")
959
+ if p.get("url"):
960
+ print(f" url : {p['url']}")
961
+ if p.get("size_bytes"):
962
+ print(f" size : {p['size_bytes']} bytes {p.get('content_type', '')}")
963
+ if p.get("reason"):
964
+ print(f" why : {p['reason']}")
965
+
966
+ findings = ev.get("findings") or []
967
+ print()
968
+ print(f"evaluator findings ({len(findings)})")
969
+ if ev.get("summary"):
970
+ print(f" {ev['summary']}")
971
+ for f in findings:
972
+ print(f" · [{f.get('verdict', '')}] {f.get('criterion', '')}")
973
+ if f.get("detail"):
974
+ print(f" {f['detail']}")
975
+ if not findings and sub.get("status") == "evaluation_failed":
976
+ print(" the evaluator returned unparseable output — the raw response is retained "
977
+ "server-side for diagnosis, and the submission can be re-evaluated.")
978
+
979
+ for r in (sub.get("rejected") or []):
980
+ print(f"⚠ proof not accepted — {r.get('name', '')}: {r.get('reason', '')}")
981
+
982
+
706
983
  if __name__ == "__main__":
707
984
  main()