stackgen-sdk 0.4.0rc7__tar.gz → 0.4.0rc9__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 (259) hide show
  1. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/PKG-INFO +1 -1
  2. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/_version.py +2 -2
  3. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/__init__.py +12 -0
  4. stackgen_sdk-0.4.0rc9/src/stackgen/aiden/subscribe.py +289 -0
  5. stackgen_sdk-0.4.0rc9/src/stackgen/aiden/subscribe_frames.py +50 -0
  6. stackgen_sdk-0.4.0rc9/src/stackgen/aiden/transient.py +73 -0
  7. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/webhook_ops.py +17 -5
  8. stackgen_sdk-0.4.0rc7/src/stackgen/aiden/subscribe.py +0 -174
  9. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/.gitignore +0 -0
  10. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/README.md +0 -0
  11. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/pyproject.toml +0 -0
  12. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/__init__.py +0 -0
  13. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/_http.py +0 -0
  14. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/ask.py +0 -0
  15. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/audit.py +0 -0
  16. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/models.py +0 -0
  17. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/namespace.py +0 -0
  18. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/resources.py +0 -0
  19. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/run_status.py +0 -0
  20. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/runs.py +0 -0
  21. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/sessions.py +0 -0
  22. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/steer.py +0 -0
  23. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/webhook.py +0 -0
  24. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/workflow_builder.py +0 -0
  25. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/workflow_publish.py +0 -0
  26. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/cli.py +0 -0
  27. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/client.py +0 -0
  28. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/config.py +0 -0
  29. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/errors.py +0 -0
  30. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/.openapi-generator/FILES +0 -0
  31. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/.openapi-generator/VERSION +0 -0
  32. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/.openapi-generator-ignore +0 -0
  33. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/__init__.py +0 -0
  34. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api/__init__.py +0 -0
  35. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api/aiden_api.py +0 -0
  36. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api/sre_api.py +0 -0
  37. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api_client.py +0 -0
  38. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api_response.py +0 -0
  39. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/configuration.py +0 -0
  40. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/exceptions.py +0 -0
  41. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/__init__.py +0 -0
  42. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/activate_break_glass_request.py +0 -0
  43. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_app_mcp_binding.py +0 -0
  44. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_health_check.py +0 -0
  45. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_health_response.py +0 -0
  46. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_info.py +0 -0
  47. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_lifecycle_status.py +0 -0
  48. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_model_config.py +0 -0
  49. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_schedule.py +0 -0
  50. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_status.py +0 -0
  51. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_analysis_status.py +0 -0
  52. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_attention.py +0 -0
  53. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_categorization_summary.py +0 -0
  54. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_role.py +0 -0
  55. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_sort_by.py +0 -0
  56. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_status.py +0 -0
  57. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_summary.py +0 -0
  58. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_sync_run_status.py +0 -0
  59. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_v1.py +0 -0
  60. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/approval_item.py +0 -0
  61. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/artifact_info.py +0 -0
  62. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_execution_mode.py +0 -0
  63. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_request.py +0 -0
  64. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_route_decision.py +0 -0
  65. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_route_response.py +0 -0
  66. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_start_response.py +0 -0
  67. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/attach_policy_request.py +0 -0
  68. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/audit_event.py +0 -0
  69. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/audit_event_list_response.py +0 -0
  70. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/audit_facets.py +0 -0
  71. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/auto_approve_tool_rule.py +0 -0
  72. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_config.py +0 -0
  73. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_snapshot.py +0 -0
  74. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_tier.py +0 -0
  75. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_tier_reason.py +0 -0
  76. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/break_glass_state.py +0 -0
  77. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/candidate_type.py +0 -0
  78. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_channel_selector.py +0 -0
  79. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription.py +0 -0
  80. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription_list_response.py +0 -0
  81. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription_target_type.py +0 -0
  82. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription_trigger_type.py +0 -0
  83. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/combining_algorithm.py +0 -0
  84. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/combining_algorithm_request.py +0 -0
  85. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/container_image.py +0 -0
  86. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/cost_band.py +0 -0
  87. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_chat_subscription_request.py +0 -0
  88. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_document_request.py +0 -0
  89. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_knowledge_base_request.py +0 -0
  90. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_policy_request.py +0 -0
  91. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_remote_runner_request.py +0 -0
  92. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_remote_runner_response.py +0 -0
  93. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_schedule_request.py +0 -0
  94. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_skill_companion_file.py +0 -0
  95. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_skill_request.py +0 -0
  96. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_webhook_request.py +0 -0
  97. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/dag_edge.py +0 -0
  98. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/dag_node.py +0 -0
  99. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/diary_compression.py +0 -0
  100. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/diary_config.py +0 -0
  101. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/discovered_tool.py +0 -0
  102. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/document_ingest_status.py +0 -0
  103. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/document_ingest_workflow_status.py +0 -0
  104. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/document_processing_status.py +0 -0
  105. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/duration_band.py +0 -0
  106. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/entity_ref.py +0 -0
  107. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/error_response.py +0 -0
  108. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/eval_config.py +0 -0
  109. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/evaluate_policy_request.py +0 -0
  110. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/evaluate_policy_response.py +0 -0
  111. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_list_item.py +0 -0
  112. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_meta.py +0 -0
  113. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_structured_output.py +0 -0
  114. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_tool_call.py +0 -0
  115. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_tool_call_list.py +0 -0
  116. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/fork_session_request.py +0 -0
  117. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/git_config.py +0 -0
  118. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/guild_integration.py +0 -0
  119. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/guild_json_error.py +0 -0
  120. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/guild_platform_config.py +0 -0
  121. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/hal_guard_config.py +0 -0
  122. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/health_check_status.py +0 -0
  123. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/hitl_config.py +0 -0
  124. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ingested_document.py +0 -0
  125. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ingested_document1.py +0 -0
  126. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_availability_reason.py +0 -0
  127. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_availability_status.py +0 -0
  128. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_mcp_auth_promotion.py +0 -0
  129. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_remote_runner.py +0 -0
  130. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_scope.py +0 -0
  131. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_sidecar_launch.py +0 -0
  132. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_test_result.py +0 -0
  133. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_type_info.py +0 -0
  134. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigate_alert_request.py +0 -0
  135. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigate_response.py +0 -0
  136. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation.py +0 -0
  137. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_evidence.py +0 -0
  138. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_evidence_kind.py +0 -0
  139. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_evidence_source.py +0 -0
  140. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_hypothesis.py +0 -0
  141. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_plain_summary.py +0 -0
  142. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_prior_incident.py +0 -0
  143. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_recommended_next_step.py +0 -0
  144. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_ref.py +0 -0
  145. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_status.py +0 -0
  146. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_structured_hypothesis_entry.py +0 -0
  147. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_structured_limitation_entry.py +0 -0
  148. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_structured_rca.py +0 -0
  149. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_triage_metadata.py +0 -0
  150. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_base.py +0 -0
  151. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_config.py +0 -0
  152. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_item.py +0 -0
  153. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_item_backend.py +0 -0
  154. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_item_operation.py +0 -0
  155. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_type.py +0 -0
  156. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_alerts_response.py +0 -0
  157. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_investigations_response.py +0 -0
  158. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_remote_runner_tasks_response.py +0 -0
  159. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_remote_runners_response.py +0 -0
  160. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/llm_provider_type.py +0 -0
  161. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config.py +0 -0
  162. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_circuit_breaker.py +0 -0
  163. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_concurrency.py +0 -0
  164. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_context_mode.py +0 -0
  165. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_context_mode_per_tool_value.py +0 -0
  166. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_metrics.py +0 -0
  167. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_rate_limit.py +0 -0
  168. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_retry.py +0 -0
  169. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_sanitize.py +0 -0
  170. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_timeout.py +0 -0
  171. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_tracing.py +0 -0
  172. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_validation.py +0 -0
  173. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/model_pricing.py +0 -0
  174. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/model_provider_config.py +0 -0
  175. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/navigation_mode.py +0 -0
  176. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/pagination.py +0 -0
  177. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/persona_variant_config.py +0 -0
  178. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/pii_redaction_config.py +0 -0
  179. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/pii_regex_rule.py +0 -0
  180. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy.py +0 -0
  181. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input.py +0 -0
  182. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_agent.py +0 -0
  183. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_approver.py +0 -0
  184. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_environment.py +0 -0
  185. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_principal.py +0 -0
  186. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_project_membership.py +0 -0
  187. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_requester.py +0 -0
  188. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_tool.py +0 -0
  189. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_outcome.py +0 -0
  190. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_type.py +0 -0
  191. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/qualified_candidate.py +0 -0
  192. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/rca_config.py +0 -0
  193. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/reasoning_effort_setting.py +0 -0
  194. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/register_agent_request.py +0 -0
  195. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/registered_model.py +0 -0
  196. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/remote_runner_info.py +0 -0
  197. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/remote_runner_task_info.py +0 -0
  198. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/resolve_approval_request.py +0 -0
  199. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/run_workflow_request.py +0 -0
  200. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/run_workflow_response.py +0 -0
  201. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/runbook_config.py +0 -0
  202. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/runner_capability.py +0 -0
  203. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/runner_status.py +0 -0
  204. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/scan_finding.py +0 -0
  205. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_history.py +0 -0
  206. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_run_list_response.py +0 -0
  207. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_run_status.py +0 -0
  208. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_source.py +0 -0
  209. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_target_type.py +0 -0
  210. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session.py +0 -0
  211. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_activity_status.py +0 -0
  212. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_export.py +0 -0
  213. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_export_part.py +0 -0
  214. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_export_part_kind.py +0 -0
  215. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_list_response.py +0 -0
  216. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_responder_kind.py +0 -0
  217. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_summary.py +0 -0
  218. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/sidecar_health_probes.py +0 -0
  219. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/signal_severity.py +0 -0
  220. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/skill.py +0 -0
  221. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/skill_file.py +0 -0
  222. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/skill_summary.py +0 -0
  223. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/stage_binding.py +0 -0
  224. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/stage_expectation.py +0 -0
  225. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/start_ask_guild200_response.py +0 -0
  226. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/start_chat_json_body.py +0 -0
  227. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/start_chat_response.py +0 -0
  228. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/subagent_spawn_contract.py +0 -0
  229. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/sync_response.py +0 -0
  230. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/task_error_category.py +0 -0
  231. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/task_status.py +0 -0
  232. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/terminate_session_response.py +0 -0
  233. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/toggle_chat_subscription_request.py +0 -0
  234. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/trace_dag_response.py +0 -0
  235. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/trigger_schedule202_response.py +0 -0
  236. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/trigger_webhook202_response.py +0 -0
  237. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/update_agent_request.py +0 -0
  238. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/update_chat_subscription_request.py +0 -0
  239. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/upsert_integration_request.py +0 -0
  240. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/version_status.py +0 -0
  241. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook.py +0 -0
  242. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook_run.py +0 -0
  243. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook_run_detail.py +0 -0
  244. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook_run_list_response.py +0 -0
  245. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow.py +0 -0
  246. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_metadata.py +0 -0
  247. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_output_contract.py +0 -0
  248. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_run_expectations.py +0 -0
  249. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_stage.py +0 -0
  250. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_tool_middleware.py +0 -0
  251. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_tool_middleware_circuit_breaker.py +0 -0
  252. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_tool_middleware_concurrency.py +0 -0
  253. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_trigger.py +0 -0
  254. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_trigger_type.py +0 -0
  255. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/rest.py +0 -0
  256. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/sre/__init__.py +0 -0
  257. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/sre/namespace.py +0 -0
  258. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/vault/__init__.py +0 -0
  259. {stackgen_sdk-0.4.0rc7 → stackgen_sdk-0.4.0rc9}/src/stackgen/vault/namespace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: stackgen-sdk
3
- Version: 0.4.0rc7
3
+ Version: 0.4.0rc9
4
4
  Summary: StackGen SDK — Aiden, SRE, and Vault from one client
5
5
  Project-URL: Homepage, https://appcd-dev.github.io/stackgen-sdk/
6
6
  Project-URL: Documentation, https://appcd-dev.github.io/stackgen-sdk/
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.4.0rc7'
22
- __version_tuple__ = version_tuple = (0, 4, 0, 'rc7')
21
+ __version__ = version = '0.4.0rc9'
22
+ __version_tuple__ = version_tuple = (0, 4, 0, 'rc9')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -6,6 +6,13 @@ from stackgen.aiden.namespace import AidenNamespace
6
6
  from stackgen.aiden.resources import PolicyConflictRule
7
7
  from stackgen.aiden.run_status import ExecutionStatus, RunPhase, RunStatus
8
8
  from stackgen.aiden.steer import is_steer_response
9
+ from stackgen.aiden.transient import (
10
+ IDEMPOTENT_MUTATION_ATTEMPTS,
11
+ SUBSCRIBE_RECONNECT_MAX,
12
+ is_transient_failure,
13
+ is_transient_status,
14
+ retry_idempotent_op,
15
+ )
9
16
  from stackgen.aiden.webhook import WebhookReportResult
10
17
  from stackgen.aiden.workflow_builder import (
11
18
  AgentDefinition,
@@ -24,11 +31,13 @@ __all__ = [
24
31
  "AskArtifactResult",
25
32
  "AuditExportResult",
26
33
  "ExecutionStatus",
34
+ "IDEMPOTENT_MUTATION_ATTEMPTS",
27
35
  "PolicyConflictRule",
28
36
  "PublishWorkflowResult",
29
37
  "RunPhase",
30
38
  "RunStatus",
31
39
  "StageDefinition",
40
+ "SUBSCRIBE_RECONNECT_MAX",
32
41
  "WebhookReportResult",
33
42
  "WorkflowBuilder",
34
43
  "WorkflowDefinition",
@@ -36,4 +45,7 @@ __all__ = [
36
45
  "create_stage",
37
46
  "create_workflow",
38
47
  "is_steer_response",
48
+ "is_transient_failure",
49
+ "is_transient_status",
50
+ "retry_idempotent_op",
39
51
  ]
@@ -0,0 +1,289 @@
1
+ """Wait for an execution subscribe stream, then confirm the record settled.
2
+
3
+ Journey (one caller deadline):
4
+
5
+ 1. Open GET …/executions/{trace_id}/subscribe (SSE).
6
+ 2. Read frames until a successful terminal, or the connection drops.
7
+ 3. On drop or a transient open failure, reconnect up to
8
+ :data:`~stackgen.aiden.transient.SUBSCRIBE_RECONNECT_MAX` times.
9
+ 4. Confirm via GET …/executions/{trace_id} (retries transient GETs).
10
+
11
+ Fail-fast: non-retryable 4xx on open; failed/error/cancelled on confirm.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import time
17
+ from dataclasses import dataclass
18
+ from urllib.error import HTTPError, URLError
19
+ from urllib.request import Request, urlopen
20
+
21
+ from stackgen import _http
22
+ from stackgen.aiden.run_status import ExecutionStatus
23
+ from stackgen.aiden.subscribe_frames import consume_subscribe_frames
24
+ from stackgen.aiden.transient import (
25
+ SUBSCRIBE_RECONNECT_MAX,
26
+ is_transient_status,
27
+ transient_status_label,
28
+ )
29
+
30
+ # Re-export for callers/tests that import from this module.
31
+ __all__ = ["ExecutionSubscribe", "SUBSCRIBE_RECONNECT_MAX", "SubscribeCompleteResult"]
32
+ from stackgen.config import StackgenConfig
33
+ from stackgen.errors import HttpError, TimeoutError as SdkTimeoutError
34
+
35
+
36
+ @dataclass
37
+ class SubscribeCompleteResult:
38
+ ok: bool
39
+ event_count: int
40
+ raw_snippet: str
41
+
42
+
43
+ class ExecutionSubscribe:
44
+ def __init__(self, config: StackgenConfig) -> None:
45
+ self._config = config
46
+
47
+ def wait_for_complete(
48
+ self, trace_id: str, *, timeout_ms: int = 10 * 60 * 1000
49
+ ) -> SubscribeCompleteResult:
50
+ started = time.monotonic()
51
+
52
+ def remaining_ms() -> int:
53
+ return timeout_ms - int((time.monotonic() - started) * 1000)
54
+
55
+ event_count = 0
56
+ chunks: list[str] = []
57
+ reconnects = 0
58
+ last_open_failure = ""
59
+
60
+ while remaining_ms() > 100:
61
+ opened = self._open_stream(trace_id, remaining_ms())
62
+ if opened["kind"] == "http":
63
+ label = transient_status_label(opened["status"])
64
+ last_open_failure = label
65
+ if (
66
+ not is_transient_status(opened["status"])
67
+ or reconnects >= SUBSCRIBE_RECONNECT_MAX
68
+ ):
69
+ return self._fail_open(event_count, reconnects, label)
70
+ reconnects += 1
71
+ time.sleep(min(1.0, max(0.0, remaining_ms() / 1000 - 0.1)))
72
+ continue
73
+ if opened["kind"] == "network":
74
+ label = transient_status_label(network=True)
75
+ last_open_failure = label
76
+ if reconnects >= SUBSCRIBE_RECONNECT_MAX:
77
+ return self._fail_open(event_count, reconnects, label)
78
+ reconnects += 1
79
+ time.sleep(min(1.0, max(0.0, remaining_ms() / 1000 - 0.1)))
80
+ continue
81
+ if opened["kind"] == "timeout":
82
+ raise SdkTimeoutError(
83
+ "subscribeExecution", int(timeout_ms / 1000)
84
+ )
85
+
86
+ last_open_failure = ""
87
+ pass_result = self._read_stream(opened["response"])
88
+ event_count += pass_result["event_count"]
89
+ chunks.extend(pass_result["chunks"])
90
+ if pass_result["completed"]:
91
+ return self._after_stream_success(
92
+ trace_id, event_count, chunks, remaining_ms()
93
+ )
94
+ if pass_result["dropped"] and reconnects < SUBSCRIBE_RECONNECT_MAX:
95
+ reconnects += 1
96
+ continue
97
+ break
98
+
99
+ return self._fail_stream(event_count, chunks, reconnects, last_open_failure)
100
+
101
+ def _subscribe_url(self, trace_id: str) -> str:
102
+ return (
103
+ f"{self._config.aiden_url()}/api/v1/executions/{trace_id}/subscribe"
104
+ + _http.query(self._config.org_id)
105
+ )
106
+
107
+ def _open_stream(self, trace_id: str, remaining_ms: int) -> dict:
108
+ req = Request(
109
+ self._subscribe_url(trace_id),
110
+ headers={
111
+ "Authorization": f"Bearer {self._config.api_token}",
112
+ "Accept": "text/event-stream",
113
+ },
114
+ method="GET",
115
+ )
116
+ try:
117
+ resp = urlopen(req, timeout=remaining_ms / 1000) # noqa: S310
118
+ return {"kind": "opened", "response": resp}
119
+ except SdkTimeoutError:
120
+ raise
121
+ except TimeoutError as err:
122
+ raise SdkTimeoutError(
123
+ "subscribeExecution", int(remaining_ms / 1000) or 1
124
+ ) from err
125
+ except HTTPError as err:
126
+ if err.fp:
127
+ err.fp.read()
128
+ return {"kind": "http", "status": err.code}
129
+ except URLError:
130
+ return {"kind": "network"}
131
+
132
+ def _read_stream(self, resp: object) -> dict:
133
+ chunks: list[str] = []
134
+ event_count = 0
135
+ completed = False
136
+ dropped = False
137
+ buffer = ""
138
+ try:
139
+ while True:
140
+ line = resp.readline() # type: ignore[attr-defined]
141
+ if not line:
142
+ dropped = not completed
143
+ break
144
+ buffer += line.decode("utf-8", errors="replace")
145
+ if "\n\n" not in buffer:
146
+ continue
147
+ frames = buffer.split("\n\n")
148
+ buffer = frames.pop()
149
+
150
+ def on_frame(frame: str) -> None:
151
+ nonlocal event_count
152
+ event_count += 1
153
+ chunks.append(frame[:500])
154
+
155
+ done_now, _ = consume_subscribe_frames(frames, on_frame)
156
+ if done_now:
157
+ completed = True
158
+ break
159
+ finally:
160
+ close = getattr(resp, "close", None)
161
+ if callable(close):
162
+ close()
163
+ return {
164
+ "completed": completed,
165
+ "event_count": event_count,
166
+ "chunks": chunks,
167
+ "dropped": dropped,
168
+ }
169
+
170
+ def _after_stream_success(
171
+ self,
172
+ trace_id: str,
173
+ event_count: int,
174
+ chunks: list[str],
175
+ remaining_ms: int,
176
+ ) -> SubscribeCompleteResult:
177
+ stream_snippet = "\n---\n".join(chunks[-5:])
178
+ if remaining_ms <= 100:
179
+ return SubscribeCompleteResult(
180
+ ok=False,
181
+ event_count=event_count,
182
+ raw_snippet="execution status=deadline",
183
+ )
184
+ confirmed = self._confirm_execution_settled(trace_id, remaining_ms)
185
+ if not confirmed.ok:
186
+ return SubscribeCompleteResult(
187
+ ok=False,
188
+ event_count=event_count,
189
+ raw_snippet=confirmed.raw_snippet,
190
+ )
191
+ return SubscribeCompleteResult(
192
+ ok=True,
193
+ event_count=event_count,
194
+ raw_snippet=stream_snippet or "successful run terminal",
195
+ )
196
+
197
+ def _fail_open(
198
+ self, event_count: int, reconnects: int, status_label: str
199
+ ) -> SubscribeCompleteResult:
200
+ snippet = (
201
+ f"subscribe reconnect {reconnects} status={status_label}"
202
+ if reconnects > 0
203
+ else f"subscribe status={status_label}"
204
+ )
205
+ return SubscribeCompleteResult(
206
+ ok=False, event_count=event_count, raw_snippet=snippet
207
+ )
208
+
209
+ def _fail_stream(
210
+ self,
211
+ event_count: int,
212
+ chunks: list[str],
213
+ reconnects: int,
214
+ last_open_failure: str,
215
+ ) -> SubscribeCompleteResult:
216
+ if last_open_failure:
217
+ return self._fail_open(event_count, reconnects, last_open_failure)
218
+ stream_snippet = "\n---\n".join(chunks[-5:])
219
+ return SubscribeCompleteResult(
220
+ ok=False,
221
+ event_count=event_count,
222
+ raw_snippet=(
223
+ f"subscribe EOF without successful terminal after {reconnects} reconnect(s)"
224
+ if reconnects > 0
225
+ else stream_snippet or "subscribe EOF without successful terminal"
226
+ ),
227
+ )
228
+
229
+ def _confirm_execution_settled(
230
+ self, trace_id: str, timeout_ms: int
231
+ ) -> SubscribeCompleteResult:
232
+ deadline = time.monotonic() + timeout_ms / 1000
233
+ url = (
234
+ f"{self._config.aiden_url()}/api/v1/executions/{trace_id}"
235
+ f"{_http.query(self._config.org_id)}"
236
+ )
237
+ poll_interval = self._config.poll_interval_seconds
238
+ last_transient = ""
239
+ while time.monotonic() < deadline:
240
+ try:
241
+ data = _http.request(url, self._config.api_token, retries=1)
242
+ if not isinstance(data, dict):
243
+ last_transient = "execution status=invalid_payload"
244
+ else:
245
+ last_transient = ""
246
+ execution = data.get("execution") or {}
247
+ status = ExecutionStatus.parse(
248
+ _http.text(execution.get("status"))
249
+ )
250
+ settled = execution.get("trace_settled")
251
+ ready = (
252
+ status is not None
253
+ and status.is_terminal()
254
+ and settled is not False
255
+ )
256
+ if ready:
257
+ if status in {
258
+ ExecutionStatus.ERROR,
259
+ ExecutionStatus.FAILED,
260
+ ExecutionStatus.CANCELLED,
261
+ }:
262
+ return SubscribeCompleteResult(
263
+ ok=False,
264
+ event_count=0,
265
+ raw_snippet=f"execution status={status.value}",
266
+ )
267
+ return SubscribeCompleteResult(
268
+ ok=True,
269
+ event_count=0,
270
+ raw_snippet="successful run terminal",
271
+ )
272
+ except HttpError as err:
273
+ if not _http.is_transient_http_error(err):
274
+ code = err.status_code if err.status_code is not None else "error"
275
+ return SubscribeCompleteResult(
276
+ ok=False,
277
+ event_count=0,
278
+ raw_snippet=f"execution status={code}",
279
+ )
280
+ last_transient = f"execution {_http.http_status_snippet(err)}"
281
+ remaining = deadline - time.monotonic()
282
+ if remaining <= 0.1:
283
+ break
284
+ time.sleep(min(poll_interval, remaining - 0.1))
285
+ return SubscribeCompleteResult(
286
+ ok=False,
287
+ event_count=0,
288
+ raw_snippet=last_transient or f"subscribe aborted after {timeout_ms}ms",
289
+ )
@@ -0,0 +1,50 @@
1
+ """Domain interpretation of Aiden execution subscribe SSE frames.
2
+
3
+ The wire format is CloudEvents / AG-UI text frames. This module only answers:
4
+ "did this frame say the execution finished successfully?" — no I/O.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Callable
10
+ from typing import Literal
11
+
12
+ SubscribeFrameKind = Literal["success", "error", "continue"]
13
+
14
+
15
+ def classify_subscribe_frame(frame: str) -> SubscribeFrameKind:
16
+ """Classify one SSE event payload (text between blank lines).
17
+
18
+ Success: ``execution_complete``, or ``subscribe_end`` without an error marker.
19
+ """
20
+ lower = frame.lower()
21
+ if not lower.strip():
22
+ return "continue"
23
+ if '"type":"error"' in lower or "event: error" in lower:
24
+ return "error"
25
+ if "execution_complete" in lower:
26
+ return "success"
27
+ if "subscribe_end" in lower and "error" not in lower:
28
+ return "success"
29
+ return "continue"
30
+
31
+
32
+ def consume_subscribe_frames(
33
+ frames: list[str],
34
+ on_frame: Callable[[str], None] | None = None,
35
+ ) -> tuple[bool, bool]:
36
+ """Accumulate frames; return ``(completed, saw_error)``."""
37
+ completed = False
38
+ saw_error = False
39
+ for frame in frames:
40
+ if not frame.strip():
41
+ continue
42
+ if on_frame is not None:
43
+ on_frame(frame)
44
+ kind = classify_subscribe_frame(frame)
45
+ if kind == "success":
46
+ completed = True
47
+ break
48
+ if kind == "error":
49
+ saw_error = True
50
+ return completed, saw_error
@@ -0,0 +1,73 @@
1
+ """Platform-blip policy for Aiden waits.
2
+
3
+ Domain rules (not HTTP mechanics):
4
+
5
+ - A *transient* failure is one the platform may self-heal during a short
6
+ rollout or gateway drop: HTTP 429, any 5xx, or a lost connection.
7
+ - Non-retryable 4xx and real execution terminals stay fail-fast.
8
+ - Only *idempotent* mutations may use :func:`retry_idempotent_op`. Today that
9
+ is ``terminate_session`` (Guild persists cancel intent; empty sessions return
10
+ 200). Webhook/workflow starts are *not* idempotent — do not retry them here.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import time
16
+ from collections.abc import Callable
17
+ from typing import TypeVar
18
+
19
+ from stackgen import _http
20
+
21
+ T = TypeVar("T")
22
+
23
+ # How many times a subscribe stream may reopen after EOF or a blip fetch.
24
+ SUBSCRIBE_RECONNECT_MAX = 3
25
+
26
+ # Bounded attempts for an idempotent mutation (terminate).
27
+ IDEMPOTENT_MUTATION_ATTEMPTS = 3
28
+
29
+ # Backoff base (seconds) between idempotent mutation attempts: 0.5, 1.0, …
30
+ IDEMPOTENT_MUTATION_BACKOFF_SECONDS = 0.5
31
+
32
+
33
+ def is_transient_status(status: int) -> bool:
34
+ """True when an HTTP status is a self-healing platform blip."""
35
+ return _http.is_retryable_http_status(status)
36
+
37
+
38
+ def is_transient_failure(err: BaseException) -> bool:
39
+ """True when an error is a self-healing blip (status or transport)."""
40
+ return _http.is_transient_http_error(err)
41
+
42
+
43
+ def transient_status_label(status: int | None = None, *, network: bool = False) -> str:
44
+ """Human label for failure snippets (``500``, ``network_error``)."""
45
+ if network or status is None:
46
+ return "network_error"
47
+ return str(status)
48
+
49
+
50
+ def retry_idempotent_op(
51
+ op: Callable[[], T],
52
+ *,
53
+ attempts: int = IDEMPOTENT_MUTATION_ATTEMPTS,
54
+ backoff_seconds: float = IDEMPOTENT_MUTATION_BACKOFF_SECONDS,
55
+ sleep: Callable[[float], None] | None = None,
56
+ ) -> T:
57
+ """Run an idempotent operation with bounded retries on transient failures.
58
+
59
+ Fail fast on non-transient errors. Callers must only pass ops that are safe
60
+ to repeat (e.g. terminate_session).
61
+ """
62
+ sleeper = sleep or time.sleep
63
+ last_err: BaseException | None = None
64
+ for attempt in range(1, attempts + 1):
65
+ try:
66
+ return op()
67
+ except Exception as err:
68
+ last_err = err
69
+ if not is_transient_failure(err) or attempt >= attempts:
70
+ raise
71
+ sleeper(backoff_seconds * attempt)
72
+ assert last_err is not None
73
+ raise last_err
@@ -9,6 +9,7 @@ from typing import Any
9
9
 
10
10
  from stackgen import _http
11
11
  from stackgen.aiden.runs import WebhookRunPoller
12
+ from stackgen.aiden.transient import retry_idempotent_op
12
13
  from stackgen.config import StackgenConfig
13
14
  from stackgen.errors import StackgenError
14
15
 
@@ -157,7 +158,12 @@ class WebhookOps:
157
158
  return data
158
159
 
159
160
  def terminate_session(self, session_id: str, *, reason: str | None = None) -> dict[str, Any]:
160
- """POST /guild/api/v1/sessions/{sessionId}/terminate."""
161
+ """Cancel running work for a session (POST …/sessions/{id}/terminate).
162
+
163
+ Idempotent on the Guild API, so transient platform blips are retried via
164
+ :func:`~stackgen.aiden.transient.retry_idempotent_op`. Do not treat
165
+ webhook/workflow starts the same way.
166
+ """
161
167
  query: dict[str, Any] = {}
162
168
  if self._config.org_id:
163
169
  query["orgId"] = self._config.org_id
@@ -167,10 +173,16 @@ class WebhookOps:
167
173
  f"{self._config.aiden_url()}/api/v1/sessions/{session_id}/terminate"
168
174
  f"{_query_string(query)}"
169
175
  )
170
- data = _http.request(url, self._config.api_token, method="POST")
171
- if not isinstance(data, dict):
172
- raise StackgenError(f"unexpected terminate session payload: {data!r}")
173
- return data
176
+
177
+ def once() -> dict[str, Any]:
178
+ data = _http.request(
179
+ url, self._config.api_token, method="POST", retries=1
180
+ )
181
+ if not isinstance(data, dict):
182
+ raise StackgenError(f"unexpected terminate session payload: {data!r}")
183
+ return data
184
+
185
+ return retry_idempotent_op(once)
174
186
 
175
187
  def start_workflow_run(
176
188
  self,
@@ -1,174 +0,0 @@
1
- """SSE subscribeExecution helper."""
2
-
3
- from __future__ import annotations
4
-
5
- import time
6
- from dataclasses import dataclass
7
- from urllib.error import HTTPError, URLError
8
- from urllib.request import Request, urlopen
9
-
10
- from stackgen import _http
11
- from stackgen.aiden.run_status import ExecutionStatus
12
- from stackgen.config import StackgenConfig
13
- from stackgen.errors import HttpError, TimeoutError as SdkTimeoutError
14
-
15
-
16
- @dataclass
17
- class SubscribeCompleteResult:
18
- ok: bool
19
- event_count: int
20
- raw_snippet: str
21
-
22
-
23
- class ExecutionSubscribe:
24
- def __init__(self, config: StackgenConfig) -> None:
25
- self._config = config
26
-
27
- def wait_for_complete(
28
- self, trace_id: str, *, timeout_ms: int = 10 * 60 * 1000
29
- ) -> SubscribeCompleteResult:
30
- started = time.monotonic()
31
- url = (
32
- f"{self._config.aiden_url()}/api/v1/executions/{trace_id}/subscribe"
33
- + _http.query(self._config.org_id)
34
- )
35
- req = Request(
36
- url,
37
- headers={
38
- "Authorization": f"Bearer {self._config.api_token}",
39
- "Accept": "text/event-stream",
40
- },
41
- method="GET",
42
- )
43
- chunks: list[str] = []
44
- event_count = 0
45
- ok = False
46
- try:
47
- with urlopen(req, timeout=timeout_ms / 1000) as resp: # noqa: S310
48
- buffer = ""
49
- while True:
50
- line = resp.readline()
51
- if not line:
52
- break
53
- buffer += line.decode("utf-8", errors="replace")
54
- if "\n\n" not in buffer:
55
- continue
56
- frames = buffer.split("\n\n")
57
- buffer = frames.pop()
58
- for frame in frames:
59
- if not frame.strip():
60
- continue
61
- event_count += 1
62
- chunks.append(frame[:500])
63
- lower = frame.lower()
64
- if "execution_complete" in lower:
65
- ok = True
66
- break
67
- if "subscribe_end" in lower and "error" not in lower:
68
- ok = True
69
- if ok:
70
- break
71
- except SdkTimeoutError:
72
- raise
73
- except TimeoutError as err:
74
- raise SdkTimeoutError("subscribeExecution", int(timeout_ms / 1000)) from err
75
- except HTTPError as err:
76
- detail = err.read().decode("utf-8", errors="replace") if err.fp else ""
77
- raise HttpError(
78
- f"subscribeExecution -> HTTP {err.code}: {detail}",
79
- status_code=err.code,
80
- ) from err
81
- except URLError as err:
82
- raise HttpError(f"subscribeExecution -> {err}") from err
83
-
84
- stream_snippet = "\n---\n".join(chunks[-5:])
85
- if not ok:
86
- return SubscribeCompleteResult(
87
- ok=False,
88
- event_count=event_count,
89
- raw_snippet=stream_snippet,
90
- )
91
-
92
- remaining_ms = timeout_ms - int((time.monotonic() - started) * 1000)
93
- if remaining_ms <= 100:
94
- return SubscribeCompleteResult(
95
- ok=False,
96
- event_count=event_count,
97
- raw_snippet="execution status=deadline",
98
- )
99
-
100
- confirmed = self._confirm_execution_settled(trace_id, remaining_ms)
101
- if not confirmed.ok:
102
- return SubscribeCompleteResult(
103
- ok=False,
104
- event_count=event_count,
105
- raw_snippet=confirmed.raw_snippet,
106
- )
107
- return SubscribeCompleteResult(
108
- ok=True,
109
- event_count=event_count,
110
- raw_snippet=stream_snippet or "successful run terminal",
111
- )
112
-
113
- def _confirm_execution_settled(
114
- self, trace_id: str, timeout_ms: int
115
- ) -> SubscribeCompleteResult:
116
- """Poll GET /executions/{traceId} until settled inside the remaining deadline."""
117
- deadline = time.monotonic() + timeout_ms / 1000
118
- url = (
119
- f"{self._config.aiden_url()}/api/v1/executions/{trace_id}"
120
- f"{_http.query(self._config.org_id)}"
121
- )
122
- poll_interval = self._config.poll_interval_seconds
123
- last_transient = ""
124
- while time.monotonic() < deadline:
125
- try:
126
- data = _http.request(url, self._config.api_token, retries=1)
127
- if not isinstance(data, dict):
128
- last_transient = "execution status=invalid_payload"
129
- else:
130
- last_transient = ""
131
- execution = data.get("execution") or {}
132
- status = ExecutionStatus.parse(
133
- _http.text(execution.get("status"))
134
- )
135
- settled = execution.get("trace_settled")
136
- ready = (
137
- status is not None
138
- and status.is_terminal()
139
- and settled is not False
140
- )
141
- if ready:
142
- if status in {
143
- ExecutionStatus.ERROR,
144
- ExecutionStatus.FAILED,
145
- ExecutionStatus.CANCELLED,
146
- }:
147
- return SubscribeCompleteResult(
148
- ok=False,
149
- event_count=0,
150
- raw_snippet=f"execution status={status.value}",
151
- )
152
- return SubscribeCompleteResult(
153
- ok=True,
154
- event_count=0,
155
- raw_snippet="successful run terminal",
156
- )
157
- except HttpError as err:
158
- if not _http.is_transient_http_error(err):
159
- code = err.status_code if err.status_code is not None else "error"
160
- return SubscribeCompleteResult(
161
- ok=False,
162
- event_count=0,
163
- raw_snippet=f"execution status={code}",
164
- )
165
- last_transient = f"execution {_http.http_status_snippet(err)}"
166
- remaining = deadline - time.monotonic()
167
- if remaining <= 0.1:
168
- break
169
- time.sleep(min(poll_interval, remaining - 0.1))
170
- return SubscribeCompleteResult(
171
- ok=False,
172
- event_count=0,
173
- raw_snippet=last_transient or f"subscribe aborted after {timeout_ms}ms",
174
- )