stackgen-sdk 0.1.6__tar.gz → 0.1.7__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.1.6 → stackgen_sdk-0.1.7}/PKG-INFO +1 -1
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/_version.py +2 -2
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/__init__.py +4 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/ask.py +9 -6
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/namespace.py +73 -2
- stackgen_sdk-0.1.7/src/stackgen/aiden/run_status.py +202 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/webhook_ops.py +30 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/.gitignore +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/README.md +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/pyproject.toml +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/__init__.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/_http.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/runs.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/sessions.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/webhook.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/workflow_builder.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/aiden/workflow_publish.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/cli.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/client.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/config.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/errors.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/.openapi-generator/FILES +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/.openapi-generator/VERSION +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/.openapi-generator-ignore +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/__init__.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/api/__init__.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/api/aiden_api.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/api/sre_api.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/api_client.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/api_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/configuration.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/exceptions.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/__init__.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/agent_status.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_analysis_status.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_attention.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_categorization_summary.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_role.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_sort_by.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_status.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_summary.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_sync_run_status.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_v1.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/artifact_info.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/ask_guild_request.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/ask_guild_start_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/candidate_type.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/dag_edge.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/dag_node.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/entity_ref.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/error_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/execution_list_item.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/execution_meta.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/execution_structured_output.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigate_alert_request.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigate_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_evidence.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_evidence_kind.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_evidence_source.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_hypothesis.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_plain_summary.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_prior_incident.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_recommended_next_step.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_ref.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_status.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_structured_hypothesis_entry.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_structured_limitation_entry.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_structured_rca.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_triage_metadata.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/json_error.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/list_alerts_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/list_investigations_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/pagination.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/prior_session_policy.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/qualified_candidate.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/register_agent_request.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/register_agent_request_auto_approve_tools_inner.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/register_agent_request_hitl.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/schedule_run_status.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/schedule_target_type.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_export.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_export_part.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_export_part_kind.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_list_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_responder_kind.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_summary.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/signal_severity.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/stage_binding_write.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/sync_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/terminate_session_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/trace_dag_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/trigger_webhook202_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/webhook_run.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/webhook_run_detail.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/webhook_run_list_response.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/workflow.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/workflow_stage_write.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/workflow_write.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/rest.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/sre/__init__.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/sre/namespace.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/vault/__init__.py +0 -0
- {stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/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.1.
|
|
3
|
+
Version: 0.1.7
|
|
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.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
21
|
+
__version__ = version = '0.1.7'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 7)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from stackgen.aiden.ask import AskArtifactResult
|
|
4
4
|
from stackgen.aiden.namespace import AidenNamespace
|
|
5
|
+
from stackgen.aiden.run_status import ExecutionStatus, RunPhase, RunStatus
|
|
5
6
|
from stackgen.aiden.webhook import WebhookReportResult
|
|
6
7
|
from stackgen.aiden.workflow_builder import (
|
|
7
8
|
AgentDefinition,
|
|
@@ -18,7 +19,10 @@ __all__ = [
|
|
|
18
19
|
"AgentDefinition",
|
|
19
20
|
"AidenNamespace",
|
|
20
21
|
"AskArtifactResult",
|
|
22
|
+
"ExecutionStatus",
|
|
21
23
|
"PublishWorkflowResult",
|
|
24
|
+
"RunPhase",
|
|
25
|
+
"RunStatus",
|
|
22
26
|
"StageDefinition",
|
|
23
27
|
"WebhookReportResult",
|
|
24
28
|
"WorkflowBuilder",
|
|
@@ -10,11 +10,10 @@ from typing import Any
|
|
|
10
10
|
|
|
11
11
|
from stackgen import _http
|
|
12
12
|
from stackgen.aiden import sessions as session_helpers
|
|
13
|
+
from stackgen.aiden.run_status import ExecutionStatus
|
|
13
14
|
from stackgen.config import StackgenConfig
|
|
14
15
|
from stackgen.errors import StackgenError, TimeoutError
|
|
15
16
|
|
|
16
|
-
_TERMINAL_STATUSES = frozenset({"completed", "error"})
|
|
17
|
-
|
|
18
17
|
|
|
19
18
|
@dataclass(frozen=True)
|
|
20
19
|
class AskArtifactResult:
|
|
@@ -156,16 +155,20 @@ class AskArtifactJourney:
|
|
|
156
155
|
if not isinstance(data, dict):
|
|
157
156
|
raise StackgenError(f"unexpected getExecutionTrace payload: {data!r}")
|
|
158
157
|
execution = data.get("execution") or {}
|
|
159
|
-
status = _http.text(execution.get("status"))
|
|
158
|
+
status = ExecutionStatus.parse(_http.text(execution.get("status")))
|
|
160
159
|
# Prefer explicit settle when the mothership sends it. Some builds
|
|
161
160
|
# omit trace_settled on the thin getExecutionTrace summary; treat
|
|
162
161
|
# terminal status alone as done so callers are not stuck forever.
|
|
163
162
|
settled = execution.get("trace_settled")
|
|
164
|
-
ready =
|
|
163
|
+
ready = (
|
|
164
|
+
status is not None
|
|
165
|
+
and status.is_terminal()
|
|
166
|
+
and settled is not False
|
|
167
|
+
)
|
|
165
168
|
if ready:
|
|
166
|
-
if status
|
|
169
|
+
if status in {ExecutionStatus.ERROR, ExecutionStatus.FAILED}:
|
|
167
170
|
raise StackgenError(
|
|
168
|
-
f"execution {trace_id} ended with status
|
|
171
|
+
f"execution {trace_id} ended with status {status.value}"
|
|
169
172
|
)
|
|
170
173
|
return data
|
|
171
174
|
time.sleep(cfg.poll_interval_seconds)
|
|
@@ -6,11 +6,13 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
from stackgen.aiden.ask import AskArtifactJourney, AskArtifactResult
|
|
9
|
+
from stackgen.aiden.run_status import RunStatus, build_run_status, require_run_ids
|
|
9
10
|
from stackgen.aiden.webhook import WebhookReportJourney, WebhookReportResult
|
|
10
11
|
from stackgen.aiden.webhook_ops import WebhookOps
|
|
11
12
|
from stackgen.aiden.workflow_builder import AgentDefinition, WorkflowDefinition
|
|
12
13
|
from stackgen.aiden.workflow_publish import PublishWorkflowResult, WorkflowPublishJourney
|
|
13
14
|
from stackgen.config import StackgenConfig
|
|
15
|
+
from stackgen import _http
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
class AidenNamespace:
|
|
@@ -142,7 +144,12 @@ class AidenNamespace:
|
|
|
142
144
|
source_app: str | None = None,
|
|
143
145
|
source_metadata: dict[str, str] | None = None,
|
|
144
146
|
) -> dict[str, Any]:
|
|
145
|
-
"""POST /guild/api/v1/guild/ask/start (
|
|
147
|
+
"""POST /guild/api/v1/guild/ask/start (fire-and-forget).
|
|
148
|
+
|
|
149
|
+
Returns ``session_id`` / ``trace_id`` immediately. Persist those ids and
|
|
150
|
+
call :meth:`get_run_status` from a separate scheduler — this method does
|
|
151
|
+
not wait for completion.
|
|
152
|
+
"""
|
|
146
153
|
return self._ask.start_ask(
|
|
147
154
|
message,
|
|
148
155
|
entity_refs=entity_refs,
|
|
@@ -152,8 +159,72 @@ class AidenNamespace:
|
|
|
152
159
|
source_metadata=source_metadata,
|
|
153
160
|
)
|
|
154
161
|
|
|
162
|
+
def start_workflow_run(
|
|
163
|
+
self,
|
|
164
|
+
workflow_name: str,
|
|
165
|
+
*,
|
|
166
|
+
input: dict[str, Any] | None = None,
|
|
167
|
+
) -> dict[str, Any]:
|
|
168
|
+
"""POST /guild/api/v1/workflows/{name}/run (fire-and-forget).
|
|
169
|
+
|
|
170
|
+
Returns ``session_id`` / ``trace_id`` immediately. Does not wait.
|
|
171
|
+
"""
|
|
172
|
+
return self._webhook_ops.start_workflow_run(workflow_name, input=input)
|
|
173
|
+
|
|
174
|
+
def get_run_status(
|
|
175
|
+
self,
|
|
176
|
+
*,
|
|
177
|
+
session_id: str | None = None,
|
|
178
|
+
trace_id: str | None = None,
|
|
179
|
+
ready_artifact: str | None = None,
|
|
180
|
+
) -> RunStatus:
|
|
181
|
+
"""Stateless status for a run started elsewhere (queue / scheduler).
|
|
182
|
+
|
|
183
|
+
One HTTP round-trip set only — never blocks or polls. Use from a
|
|
184
|
+
separate process that holds ``session_id`` and/or ``trace_id`` in your
|
|
185
|
+
own store.
|
|
186
|
+
|
|
187
|
+
When ``ready_artifact`` is set (e.g. ``session-report.md``), ``ready`` is
|
|
188
|
+
true only once that artifact appears on the session.
|
|
189
|
+
"""
|
|
190
|
+
require_run_ids(session_id=session_id, trace_id=trace_id)
|
|
191
|
+
sid = _http.text(session_id)
|
|
192
|
+
tid = _http.text(trace_id)
|
|
193
|
+
session: dict[str, Any] = {}
|
|
194
|
+
trace: dict[str, Any] = {}
|
|
195
|
+
names: list[str] = []
|
|
196
|
+
|
|
197
|
+
if tid:
|
|
198
|
+
trace = self.get_execution_trace(tid)
|
|
199
|
+
if not sid:
|
|
200
|
+
sid = _http.text(trace.get("session_id"))
|
|
201
|
+
execution = trace.get("execution") or {}
|
|
202
|
+
if isinstance(execution, dict) and not sid:
|
|
203
|
+
sid = _http.text(execution.get("session_id"))
|
|
204
|
+
|
|
205
|
+
if sid:
|
|
206
|
+
session = self.get_session(sid)
|
|
207
|
+
arts = self.list_session_artifacts(sid)
|
|
208
|
+
for a in arts:
|
|
209
|
+
if isinstance(a, dict):
|
|
210
|
+
name = _http.text(a.get("name"))
|
|
211
|
+
if name:
|
|
212
|
+
names.append(name)
|
|
213
|
+
|
|
214
|
+
return build_run_status(
|
|
215
|
+
session_id=sid,
|
|
216
|
+
trace_id=tid,
|
|
217
|
+
session=session,
|
|
218
|
+
trace=trace,
|
|
219
|
+
artifact_names=names,
|
|
220
|
+
ready_artifact=ready_artifact or "",
|
|
221
|
+
)
|
|
222
|
+
|
|
155
223
|
def wait_for_execution(self, trace_id: str) -> dict[str, Any]:
|
|
156
|
-
"""Poll GET /guild/api/v1/executions/{traceId} until settled.
|
|
224
|
+
"""Poll GET /guild/api/v1/executions/{traceId} until settled (blocking).
|
|
225
|
+
|
|
226
|
+
Prefer :meth:`get_run_status` for queue/scheduler architectures.
|
|
227
|
+
"""
|
|
157
228
|
return self._ask.wait_for_execution(trace_id)
|
|
158
229
|
|
|
159
230
|
def publish_workflow(
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Stateless run status for queue / scheduler architectures.
|
|
2
|
+
|
|
3
|
+
Callers that submit work on one process and poll from another should persist
|
|
4
|
+
``session_id`` / ``trace_id``, then use :meth:`AidenNamespace.get_run_status`.
|
|
5
|
+
These helpers never block.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from stackgen import _http
|
|
15
|
+
from stackgen.errors import StackgenError
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ExecutionStatus(str, Enum):
|
|
19
|
+
"""Raw Guild execution ``status`` values (OpenAPI ExecutionMeta.status).
|
|
20
|
+
|
|
21
|
+
OpenAPI documents ``running``, ``completed``, and ``error``; Guild also
|
|
22
|
+
emits cancel variants. Unknown wire values are left as strings on
|
|
23
|
+
:attr:`RunStatus.execution_status` rather than forced into this enum.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
RUNNING = "running"
|
|
27
|
+
COMPLETED = "completed"
|
|
28
|
+
ERROR = "error"
|
|
29
|
+
FAILED = "failed"
|
|
30
|
+
CANCELLING = "cancelling"
|
|
31
|
+
CANCELLED = "cancelled"
|
|
32
|
+
QUEUED = "queued"
|
|
33
|
+
PENDING = "pending"
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def parse(cls, value: str) -> ExecutionStatus | None:
|
|
37
|
+
key = (value or "").strip().casefold()
|
|
38
|
+
if not key:
|
|
39
|
+
return None
|
|
40
|
+
aliases = {
|
|
41
|
+
"canceled": cls.CANCELLED,
|
|
42
|
+
"in_progress": cls.RUNNING,
|
|
43
|
+
"active": cls.RUNNING,
|
|
44
|
+
"started": cls.RUNNING,
|
|
45
|
+
"success": cls.COMPLETED,
|
|
46
|
+
"succeeded": cls.COMPLETED,
|
|
47
|
+
"terminated": cls.CANCELLED,
|
|
48
|
+
}
|
|
49
|
+
if key in aliases:
|
|
50
|
+
return aliases[key]
|
|
51
|
+
try:
|
|
52
|
+
return cls(key)
|
|
53
|
+
except ValueError:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
def is_terminal(self) -> bool:
|
|
57
|
+
return self in {
|
|
58
|
+
ExecutionStatus.COMPLETED,
|
|
59
|
+
ExecutionStatus.ERROR,
|
|
60
|
+
ExecutionStatus.FAILED,
|
|
61
|
+
ExecutionStatus.CANCELLED,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
def is_active(self) -> bool:
|
|
65
|
+
return self in {
|
|
66
|
+
ExecutionStatus.RUNNING,
|
|
67
|
+
ExecutionStatus.CANCELLING,
|
|
68
|
+
ExecutionStatus.QUEUED,
|
|
69
|
+
ExecutionStatus.PENDING,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class RunPhase(str, Enum):
|
|
74
|
+
"""Normalized scheduler-facing phase from :meth:`AidenNamespace.get_run_status`."""
|
|
75
|
+
|
|
76
|
+
PENDING = "pending"
|
|
77
|
+
RUNNING = "running"
|
|
78
|
+
COMPLETED = "completed"
|
|
79
|
+
ERROR = "error"
|
|
80
|
+
UNKNOWN = "unknown"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass(frozen=True)
|
|
84
|
+
class RunStatus:
|
|
85
|
+
"""Normalized one-shot status for a previously started run."""
|
|
86
|
+
|
|
87
|
+
phase: RunPhase
|
|
88
|
+
session_id: str = ""
|
|
89
|
+
trace_id: str = ""
|
|
90
|
+
run_id: str = ""
|
|
91
|
+
execution_status: str = ""
|
|
92
|
+
session_status: str = ""
|
|
93
|
+
artifact_names: tuple[str, ...] = ()
|
|
94
|
+
ready: bool = False
|
|
95
|
+
ready_artifact: str = ""
|
|
96
|
+
session: dict[str, Any] = field(default_factory=dict)
|
|
97
|
+
execution: dict[str, Any] = field(default_factory=dict)
|
|
98
|
+
trace: dict[str, Any] = field(default_factory=dict)
|
|
99
|
+
|
|
100
|
+
def to_dict(self) -> dict[str, Any]:
|
|
101
|
+
return {
|
|
102
|
+
"phase": self.phase.value,
|
|
103
|
+
"session_id": self.session_id,
|
|
104
|
+
"trace_id": self.trace_id,
|
|
105
|
+
"run_id": self.run_id,
|
|
106
|
+
"execution_status": self.execution_status,
|
|
107
|
+
"session_status": self.session_status,
|
|
108
|
+
"artifact_names": list(self.artifact_names),
|
|
109
|
+
"ready": self.ready,
|
|
110
|
+
"ready_artifact": self.ready_artifact,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _phase_from_status(status: str) -> RunPhase:
|
|
115
|
+
parsed = ExecutionStatus.parse(status)
|
|
116
|
+
if parsed is None:
|
|
117
|
+
return RunPhase.UNKNOWN if not status else RunPhase.RUNNING
|
|
118
|
+
if parsed is ExecutionStatus.COMPLETED:
|
|
119
|
+
return RunPhase.COMPLETED
|
|
120
|
+
if parsed in {
|
|
121
|
+
ExecutionStatus.ERROR,
|
|
122
|
+
ExecutionStatus.FAILED,
|
|
123
|
+
ExecutionStatus.CANCELLED,
|
|
124
|
+
}:
|
|
125
|
+
return RunPhase.ERROR
|
|
126
|
+
if parsed in {ExecutionStatus.QUEUED, ExecutionStatus.PENDING}:
|
|
127
|
+
return RunPhase.PENDING
|
|
128
|
+
if parsed.is_active():
|
|
129
|
+
return RunPhase.RUNNING
|
|
130
|
+
return RunPhase.RUNNING
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def build_run_status(
|
|
134
|
+
*,
|
|
135
|
+
session_id: str = "",
|
|
136
|
+
trace_id: str = "",
|
|
137
|
+
session: dict[str, Any] | None = None,
|
|
138
|
+
trace: dict[str, Any] | None = None,
|
|
139
|
+
artifact_names: list[str] | tuple[str, ...] = (),
|
|
140
|
+
ready_artifact: str = "",
|
|
141
|
+
) -> RunStatus:
|
|
142
|
+
"""Derive :class:`RunStatus` from optional session + execution payloads."""
|
|
143
|
+
session = session or {}
|
|
144
|
+
trace = trace or {}
|
|
145
|
+
execution = trace.get("execution") if isinstance(trace.get("execution"), dict) else {}
|
|
146
|
+
if not execution and isinstance(trace, dict):
|
|
147
|
+
# Some thin responses put status at the top level.
|
|
148
|
+
if "status" in trace and "execution" not in trace:
|
|
149
|
+
execution = trace
|
|
150
|
+
|
|
151
|
+
sid = session_id or _http.text(session.get("id") or session.get("session_id") or trace.get("session_id"))
|
|
152
|
+
tid = trace_id or _http.text(trace.get("trace_id") or execution.get("trace_id"))
|
|
153
|
+
run_id = _http.text(
|
|
154
|
+
execution.get("run_id")
|
|
155
|
+
or session.get("run_id")
|
|
156
|
+
or trace.get("run_id")
|
|
157
|
+
)
|
|
158
|
+
exec_status = _http.text(execution.get("status"))
|
|
159
|
+
sess_status = _http.text(session.get("status") or session.get("state"))
|
|
160
|
+
names = tuple(n for n in artifact_names if n)
|
|
161
|
+
ready_name = ready_artifact.strip()
|
|
162
|
+
ready = bool(ready_name and ready_name in names)
|
|
163
|
+
|
|
164
|
+
phase = RunPhase.UNKNOWN
|
|
165
|
+
if ready:
|
|
166
|
+
phase = RunPhase.COMPLETED
|
|
167
|
+
else:
|
|
168
|
+
exec_phase = _phase_from_status(exec_status)
|
|
169
|
+
sess_phase = _phase_from_status(sess_status)
|
|
170
|
+
if exec_phase is RunPhase.ERROR or sess_phase is RunPhase.ERROR:
|
|
171
|
+
phase = RunPhase.ERROR
|
|
172
|
+
elif exec_phase is RunPhase.COMPLETED or sess_phase is RunPhase.COMPLETED:
|
|
173
|
+
# Terminal execution without the caller's ready artifact yet —
|
|
174
|
+
# still running from a report-consumer perspective when a
|
|
175
|
+
# ready_artifact was requested; otherwise completed.
|
|
176
|
+
phase = RunPhase.RUNNING if ready_name else RunPhase.COMPLETED
|
|
177
|
+
elif exec_phase in {RunPhase.RUNNING, RunPhase.PENDING}:
|
|
178
|
+
phase = exec_phase
|
|
179
|
+
elif sess_phase in {RunPhase.RUNNING, RunPhase.PENDING}:
|
|
180
|
+
phase = sess_phase
|
|
181
|
+
elif sid or tid:
|
|
182
|
+
phase = RunPhase.RUNNING
|
|
183
|
+
|
|
184
|
+
return RunStatus(
|
|
185
|
+
phase=phase,
|
|
186
|
+
session_id=sid,
|
|
187
|
+
trace_id=tid,
|
|
188
|
+
run_id=run_id,
|
|
189
|
+
execution_status=exec_status,
|
|
190
|
+
session_status=sess_status,
|
|
191
|
+
artifact_names=names,
|
|
192
|
+
ready=ready,
|
|
193
|
+
ready_artifact=ready_name,
|
|
194
|
+
session=dict(session),
|
|
195
|
+
execution=dict(execution) if isinstance(execution, dict) else {},
|
|
196
|
+
trace=dict(trace),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def require_run_ids(*, session_id: str | None, trace_id: str | None) -> None:
|
|
201
|
+
if not (session_id or trace_id):
|
|
202
|
+
raise StackgenError("get_run_status requires session_id and/or trace_id")
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
5
6
|
import urllib.parse
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Any
|
|
@@ -170,3 +171,32 @@ class WebhookOps:
|
|
|
170
171
|
if not isinstance(data, dict):
|
|
171
172
|
raise StackgenError(f"unexpected terminate session payload: {data!r}")
|
|
172
173
|
return data
|
|
174
|
+
|
|
175
|
+
def start_workflow_run(
|
|
176
|
+
self,
|
|
177
|
+
workflow_name: str,
|
|
178
|
+
*,
|
|
179
|
+
input: dict[str, Any] | None = None,
|
|
180
|
+
) -> dict[str, Any]:
|
|
181
|
+
"""POST /guild/api/v1/workflows/{name}/run (fire-and-forget).
|
|
182
|
+
|
|
183
|
+
Returns the start body (typically ``session_id`` + ``trace_id``). Does
|
|
184
|
+
not wait for completion — persist those ids and call
|
|
185
|
+
:meth:`AidenNamespace.get_run_status` from a scheduler.
|
|
186
|
+
"""
|
|
187
|
+
name = urllib.parse.quote(workflow_name, safe="")
|
|
188
|
+
url = (
|
|
189
|
+
f"{self._config.aiden_url()}/api/v1/workflows/{name}/run"
|
|
190
|
+
f"{_http.query(self._config.org_id)}"
|
|
191
|
+
)
|
|
192
|
+
body: dict[str, Any] = {"input": input or {}}
|
|
193
|
+
data = _http.request(
|
|
194
|
+
url,
|
|
195
|
+
self._config.api_token,
|
|
196
|
+
method="POST",
|
|
197
|
+
body=json.dumps(body).encode("utf-8"),
|
|
198
|
+
content_type="application/json",
|
|
199
|
+
)
|
|
200
|
+
if not isinstance(data, dict):
|
|
201
|
+
raise StackgenError(f"unexpected workflow run start payload: {data!r}")
|
|
202
|
+
return data
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_analysis_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/alert_sync_run_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/ask_guild_request.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/ask_guild_start_response.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/execution_list_item.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigate_alert_request.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigate_response.py
RENAMED
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_evidence.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_hypothesis.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_ref.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/investigation_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/list_alerts_response.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/prior_session_policy.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/qualified_candidate.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/register_agent_request.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/schedule_run_status.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/schedule_target_type.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_export_part.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_export_part_kind.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_list_response.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/session_responder_kind.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/stage_binding_write.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/trace_dag_response.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/webhook_run_detail.py
RENAMED
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/webhook_run_list_response.py
RENAMED
|
File without changes
|
|
File without changes
|
{stackgen_sdk-0.1.6 → stackgen_sdk-0.1.7}/src/stackgen/generated/models/workflow_stage_write.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|