stackgen-sdk 0.4.0rc8__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.
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/PKG-INFO +1 -1
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/_version.py +2 -2
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/__init__.py +12 -0
- stackgen_sdk-0.4.0rc9/src/stackgen/aiden/subscribe.py +289 -0
- stackgen_sdk-0.4.0rc9/src/stackgen/aiden/subscribe_frames.py +50 -0
- stackgen_sdk-0.4.0rc9/src/stackgen/aiden/transient.py +73 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/webhook_ops.py +17 -5
- stackgen_sdk-0.4.0rc8/src/stackgen/aiden/subscribe.py +0 -174
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/.gitignore +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/README.md +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/pyproject.toml +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/__init__.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/_http.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/ask.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/audit.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/models.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/namespace.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/resources.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/run_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/runs.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/sessions.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/steer.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/webhook.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/workflow_builder.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/aiden/workflow_publish.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/cli.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/client.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/errors.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/.openapi-generator/FILES +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/.openapi-generator/VERSION +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/.openapi-generator-ignore +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/__init__.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api/__init__.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api/aiden_api.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api/sre_api.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api_client.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/api_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/configuration.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/exceptions.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/__init__.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/activate_break_glass_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_app_mcp_binding.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_health_check.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_health_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_info.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_lifecycle_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_model_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_schedule.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/agent_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_analysis_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_attention.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_categorization_summary.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_role.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_sort_by.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_summary.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_sync_run_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/alert_v1.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/approval_item.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/artifact_info.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_execution_mode.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_route_decision.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_route_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ask_guild_start_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/attach_policy_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/audit_event.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/audit_event_list_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/audit_facets.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/auto_approve_tool_rule.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_snapshot.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_tier.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/autonomy_budget_tier_reason.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/break_glass_state.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/candidate_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_channel_selector.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription_list_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription_target_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/chat_subscription_trigger_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/combining_algorithm.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/combining_algorithm_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/container_image.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/cost_band.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_chat_subscription_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_document_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_knowledge_base_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_policy_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_remote_runner_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_remote_runner_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_schedule_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_skill_companion_file.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_skill_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/create_webhook_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/dag_edge.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/dag_node.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/diary_compression.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/diary_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/discovered_tool.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/document_ingest_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/document_ingest_workflow_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/document_processing_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/duration_band.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/entity_ref.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/error_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/eval_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/evaluate_policy_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/evaluate_policy_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_list_item.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_meta.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_structured_output.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_tool_call.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/execution_tool_call_list.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/fork_session_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/git_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/guild_integration.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/guild_json_error.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/guild_platform_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/hal_guard_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/health_check_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/hitl_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ingested_document.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/ingested_document1.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_availability_reason.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_availability_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_mcp_auth_promotion.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_remote_runner.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_scope.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_sidecar_launch.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_test_result.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/integration_type_info.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigate_alert_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigate_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_evidence.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_evidence_kind.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_evidence_source.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_hypothesis.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_plain_summary.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_prior_incident.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_recommended_next_step.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_ref.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_structured_hypothesis_entry.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_structured_limitation_entry.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_structured_rca.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/investigation_triage_metadata.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_base.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_item.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_item_backend.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_item_operation.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/knowledge_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_alerts_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_investigations_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_remote_runner_tasks_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/list_remote_runners_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/llm_provider_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_circuit_breaker.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_concurrency.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_context_mode.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_context_mode_per_tool_value.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_metrics.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_rate_limit.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_retry.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_sanitize.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_timeout.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_tracing.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/middleware_config_validation.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/model_pricing.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/model_provider_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/navigation_mode.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/pagination.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/persona_variant_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/pii_redaction_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/pii_regex_rule.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_agent.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_approver.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_environment.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_principal.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_project_membership.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_requester.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_input_tool.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_evaluation_outcome.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/policy_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/qualified_candidate.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/rca_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/reasoning_effort_setting.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/register_agent_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/registered_model.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/remote_runner_info.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/remote_runner_task_info.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/resolve_approval_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/run_workflow_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/run_workflow_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/runbook_config.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/runner_capability.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/runner_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/scan_finding.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_history.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_run_list_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_run_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_source.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/schedule_target_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_activity_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_export.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_export_part.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_export_part_kind.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_list_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_responder_kind.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/session_summary.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/sidecar_health_probes.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/signal_severity.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/skill.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/skill_file.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/skill_summary.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/stage_binding.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/stage_expectation.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/start_ask_guild200_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/start_chat_json_body.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/start_chat_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/subagent_spawn_contract.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/sync_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/task_error_category.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/task_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/terminate_session_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/toggle_chat_subscription_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/trace_dag_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/trigger_schedule202_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/trigger_webhook202_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/update_agent_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/update_chat_subscription_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/upsert_integration_request.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/version_status.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook_run.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook_run_detail.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/webhook_run_list_response.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_metadata.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_output_contract.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_run_expectations.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_stage.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_tool_middleware.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_tool_middleware_circuit_breaker.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_tool_middleware_concurrency.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_trigger.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/models/workflow_trigger_type.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/generated/rest.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/sre/__init__.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/sre/namespace.py +0 -0
- {stackgen_sdk-0.4.0rc8 → stackgen_sdk-0.4.0rc9}/src/stackgen/vault/__init__.py +0 -0
- {stackgen_sdk-0.4.0rc8 → 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.
|
|
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.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 4, 0, '
|
|
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
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
)
|
|
File without changes
|
|
File without changes
|