stackgen-sdk 0.1.3__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/.gitignore +6 -0
  2. stackgen_sdk-0.1.6/PKG-INFO +92 -0
  3. stackgen_sdk-0.1.6/README.md +71 -0
  4. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/pyproject.toml +4 -1
  5. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/__init__.py +25 -2
  6. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/_version.py +2 -2
  7. stackgen_sdk-0.1.6/src/stackgen/aiden/__init__.py +29 -0
  8. stackgen_sdk-0.1.6/src/stackgen/aiden/ask.py +172 -0
  9. stackgen_sdk-0.1.6/src/stackgen/aiden/namespace.py +170 -0
  10. stackgen_sdk-0.1.6/src/stackgen/aiden/runs.py +137 -0
  11. stackgen_sdk-0.1.6/src/stackgen/aiden/sessions.py +46 -0
  12. stackgen_sdk-0.1.6/src/stackgen/aiden/webhook.py +77 -0
  13. stackgen_sdk-0.1.6/src/stackgen/aiden/webhook_ops.py +172 -0
  14. stackgen_sdk-0.1.6/src/stackgen/aiden/workflow_builder.py +198 -0
  15. stackgen_sdk-0.1.6/src/stackgen/aiden/workflow_publish.py +211 -0
  16. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/cli.py +9 -1
  17. stackgen_sdk-0.1.6/src/stackgen/config.py +70 -0
  18. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/.openapi-generator/FILES +78 -0
  19. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/__init__.py +52 -0
  20. stackgen_sdk-0.1.6/src/stackgen/generated/api/aiden_api.py +6054 -0
  21. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/api/sre_api.py +6 -6
  22. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/configuration.py +3 -3
  23. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/__init__.py +26 -0
  24. stackgen_sdk-0.1.6/src/stackgen/generated/models/agent_status.py +89 -0
  25. stackgen_sdk-0.1.6/src/stackgen/generated/models/ask_guild_request.py +119 -0
  26. stackgen_sdk-0.1.6/src/stackgen/generated/models/ask_guild_start_response.py +109 -0
  27. stackgen_sdk-0.1.6/src/stackgen/generated/models/candidate_type.py +40 -0
  28. stackgen_sdk-0.1.6/src/stackgen/generated/models/dag_edge.py +89 -0
  29. stackgen_sdk-0.1.6/src/stackgen/generated/models/dag_node.py +103 -0
  30. stackgen_sdk-0.1.6/src/stackgen/generated/models/entity_ref.py +90 -0
  31. stackgen_sdk-0.1.6/src/stackgen/generated/models/execution_list_item.py +112 -0
  32. stackgen_sdk-0.1.6/src/stackgen/generated/models/execution_meta.py +102 -0
  33. stackgen_sdk-0.1.6/src/stackgen/generated/models/execution_structured_output.py +93 -0
  34. stackgen_sdk-0.1.6/src/stackgen/generated/models/prior_session_policy.py +110 -0
  35. stackgen_sdk-0.1.6/src/stackgen/generated/models/qualified_candidate.py +92 -0
  36. stackgen_sdk-0.1.6/src/stackgen/generated/models/register_agent_request.py +107 -0
  37. stackgen_sdk-0.1.6/src/stackgen/generated/models/register_agent_request_auto_approve_tools_inner.py +87 -0
  38. stackgen_sdk-0.1.6/src/stackgen/generated/models/register_agent_request_hitl.py +87 -0
  39. stackgen_sdk-0.1.6/src/stackgen/generated/models/session_export.py +100 -0
  40. stackgen_sdk-0.1.6/src/stackgen/generated/models/session_export_part.py +94 -0
  41. stackgen_sdk-0.1.6/src/stackgen/generated/models/session_export_part_kind.py +38 -0
  42. stackgen_sdk-0.1.6/src/stackgen/generated/models/session_list_response.py +97 -0
  43. stackgen_sdk-0.1.6/src/stackgen/generated/models/session_summary.py +119 -0
  44. stackgen_sdk-0.1.6/src/stackgen/generated/models/stage_binding_write.py +95 -0
  45. stackgen_sdk-0.1.6/src/stackgen/generated/models/terminate_session_response.py +91 -0
  46. stackgen_sdk-0.1.6/src/stackgen/generated/models/trace_dag_response.py +119 -0
  47. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/trigger_webhook202_response.py +6 -2
  48. stackgen_sdk-0.1.6/src/stackgen/generated/models/workflow.py +117 -0
  49. stackgen_sdk-0.1.6/src/stackgen/generated/models/workflow_stage_write.py +93 -0
  50. stackgen_sdk-0.1.6/src/stackgen/generated/models/workflow_write.py +129 -0
  51. stackgen_sdk-0.1.3/PKG-INFO +0 -59
  52. stackgen_sdk-0.1.3/README.md +0 -41
  53. stackgen_sdk-0.1.3/src/stackgen/aiden/__init__.py +0 -9
  54. stackgen_sdk-0.1.3/src/stackgen/aiden/namespace.py +0 -26
  55. stackgen_sdk-0.1.3/src/stackgen/aiden/runs.py +0 -36
  56. stackgen_sdk-0.1.3/src/stackgen/aiden/webhook.py +0 -185
  57. stackgen_sdk-0.1.3/src/stackgen/config.py +0 -88
  58. stackgen_sdk-0.1.3/src/stackgen/generated/api/aiden_api.py +0 -1806
  59. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/_http.py +0 -0
  60. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/client.py +0 -0
  61. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/errors.py +0 -0
  62. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/.openapi-generator/VERSION +0 -0
  63. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/.openapi-generator-ignore +0 -0
  64. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/api/__init__.py +0 -0
  65. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/api_client.py +0 -0
  66. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/api_response.py +0 -0
  67. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/exceptions.py +0 -0
  68. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_analysis_status.py +0 -0
  69. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_attention.py +0 -0
  70. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_categorization_summary.py +0 -0
  71. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_role.py +0 -0
  72. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_sort_by.py +0 -0
  73. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_status.py +0 -0
  74. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_summary.py +0 -0
  75. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_sync_run_status.py +0 -0
  76. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/alert_v1.py +0 -0
  77. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/artifact_info.py +0 -0
  78. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/error_response.py +0 -0
  79. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigate_alert_request.py +0 -0
  80. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigate_response.py +0 -0
  81. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation.py +0 -0
  82. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_evidence.py +0 -0
  83. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_evidence_kind.py +0 -0
  84. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_evidence_source.py +0 -0
  85. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_hypothesis.py +0 -0
  86. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_plain_summary.py +0 -0
  87. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_prior_incident.py +0 -0
  88. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_recommended_next_step.py +0 -0
  89. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_ref.py +0 -0
  90. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_status.py +0 -0
  91. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_structured_hypothesis_entry.py +0 -0
  92. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_structured_limitation_entry.py +0 -0
  93. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_structured_rca.py +0 -0
  94. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/investigation_triage_metadata.py +0 -0
  95. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/json_error.py +0 -0
  96. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/list_alerts_response.py +0 -0
  97. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/list_investigations_response.py +0 -0
  98. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/pagination.py +0 -0
  99. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/schedule_run_status.py +0 -0
  100. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/schedule_target_type.py +0 -0
  101. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/session.py +0 -0
  102. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/session_responder_kind.py +0 -0
  103. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/signal_severity.py +0 -0
  104. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/sync_response.py +0 -0
  105. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/webhook_run.py +0 -0
  106. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/webhook_run_detail.py +0 -0
  107. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/models/webhook_run_list_response.py +0 -0
  108. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/generated/rest.py +0 -0
  109. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/sre/__init__.py +0 -0
  110. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/sre/namespace.py +0 -0
  111. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/vault/__init__.py +0 -0
  112. {stackgen_sdk-0.1.3 → stackgen_sdk-0.1.6}/src/stackgen/vault/namespace.py +0 -0
@@ -32,5 +32,11 @@ coverage.out
32
32
  .env
33
33
  .env.*
34
34
 
35
+ # Jekyll (only if native Ruby was used by mistake)
36
+ docs/_site/
37
+ docs/.jekyll-cache/
38
+ docs/.bundle/
39
+ docs/vendor/
40
+
35
41
  # hatch-vcs generated version module (written at build time)
36
42
  clients/python/src/stackgen/_version.py
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.5
2
+ Name: stackgen-sdk
3
+ Version: 0.1.6
4
+ Summary: StackGen SDK — Aiden, SRE, and Vault from one client
5
+ Project-URL: Homepage, https://appcd-dev.github.io/stackgen-sdk/
6
+ Project-URL: Documentation, https://appcd-dev.github.io/stackgen-sdk/
7
+ Project-URL: Repository, https://github.com/appcd-dev/stackgen-sdk
8
+ Project-URL: Bug Tracker, https://github.com/appcd-dev/stackgen-sdk/issues
9
+ Author: StackGen
10
+ License-Expression: Apache-2.0
11
+ Keywords: aiden,openapi,sre,stackgen
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: pydantic>=2.0
14
+ Requires-Dist: python-dateutil>=2.8
15
+ Requires-Dist: typing-extensions>=4.0
16
+ Requires-Dist: urllib3>=2.0
17
+ Provides-Extra: dev
18
+ Requires-Dist: build>=1.2; extra == 'dev'
19
+ Requires-Dist: pytest>=8.0; extra == 'dev'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # StackGen Python SDK
23
+
24
+ **Documentation:** [https://appcd-dev.github.io/stackgen-sdk/](https://appcd-dev.github.io/stackgen-sdk/) — Aiden guide, code samples, FAQ, and CI integration.
25
+
26
+ Install:
27
+
28
+ ```bash
29
+ pip install stackgen-sdk
30
+ ```
31
+
32
+ Import package name is `stackgen`. Construct the client with an explicit config:
33
+
34
+ ```python
35
+ from pathlib import Path
36
+ from stackgen import StackgenClient, StackgenConfig
37
+
38
+ client = StackgenClient(
39
+ StackgenConfig(
40
+ base_url="https://app.stackgen.com",
41
+ api_token="stackgen_…",
42
+ org_id="<project-uuid>",
43
+ webhook_token="sg_aios_…", # webhook journeys only
44
+ )
45
+ )
46
+
47
+ result = client.aiden.run_webhook_and_download_report(
48
+ Path("alert.json").read_text(encoding="utf-8")
49
+ )
50
+ print(result.session_id, result.output_path)
51
+
52
+ ask = client.aiden.run_ask_and_download_artifact(
53
+ message="Run triage for checkout CPU alert",
54
+ entity_refs=[{"name": "observe-uber-triage", "type": "workflow"}],
55
+ )
56
+ print(ask.trace_id, ask.output_path)
57
+
58
+ alerts = client.sre.list_alerts()
59
+ ```
60
+
61
+ ## Default environment variables
62
+
63
+ `StackgenConfig.from_env()` reads **only** these (optional convenience):
64
+
65
+ | Variable | Purpose |
66
+ |----------|---------|
67
+ | `STACKGEN_URL` | Mothership URL (no path suffix) |
68
+ | `STACKGEN_TOKEN` | API token (`stackgen_…`) |
69
+ | `STACKGEN_PROJECT` | Project / org UUID (`orgId`) |
70
+
71
+ Pass `webhook_token`, `webhook_id`, timeouts, and artifact paths as `StackgenConfig` fields — not via env.
72
+
73
+ ```python
74
+ from dataclasses import replace
75
+ from stackgen import StackgenClient, StackgenConfig
76
+
77
+ client = StackgenClient(
78
+ replace(StackgenConfig.from_env(), webhook_token="sg_aios_…")
79
+ )
80
+ ```
81
+
82
+ ## Namespaces
83
+
84
+ - `client.aiden` — webhooks, Ask Guild, sessions, artifact download
85
+ - `client.sre` — alerts and investigations
86
+ - `client.vault` — secrets (not enabled in this release)
87
+
88
+ Prefer `StackgenClient` over `stackgen.generated`.
89
+
90
+ Pin versions in CI: `pip install stackgen-sdk==0.1.5`.
91
+
92
+ **Documentation:** [https://appcd-dev.github.io/stackgen-sdk/](https://appcd-dev.github.io/stackgen-sdk/) (Aiden guide, [FAQ](https://appcd-dev.github.io/stackgen-sdk/faq/), [code samples](https://appcd-dev.github.io/stackgen-sdk/code-samples/))
@@ -0,0 +1,71 @@
1
+ # StackGen Python SDK
2
+
3
+ **Documentation:** [https://appcd-dev.github.io/stackgen-sdk/](https://appcd-dev.github.io/stackgen-sdk/) — Aiden guide, code samples, FAQ, and CI integration.
4
+
5
+ Install:
6
+
7
+ ```bash
8
+ pip install stackgen-sdk
9
+ ```
10
+
11
+ Import package name is `stackgen`. Construct the client with an explicit config:
12
+
13
+ ```python
14
+ from pathlib import Path
15
+ from stackgen import StackgenClient, StackgenConfig
16
+
17
+ client = StackgenClient(
18
+ StackgenConfig(
19
+ base_url="https://app.stackgen.com",
20
+ api_token="stackgen_…",
21
+ org_id="<project-uuid>",
22
+ webhook_token="sg_aios_…", # webhook journeys only
23
+ )
24
+ )
25
+
26
+ result = client.aiden.run_webhook_and_download_report(
27
+ Path("alert.json").read_text(encoding="utf-8")
28
+ )
29
+ print(result.session_id, result.output_path)
30
+
31
+ ask = client.aiden.run_ask_and_download_artifact(
32
+ message="Run triage for checkout CPU alert",
33
+ entity_refs=[{"name": "observe-uber-triage", "type": "workflow"}],
34
+ )
35
+ print(ask.trace_id, ask.output_path)
36
+
37
+ alerts = client.sre.list_alerts()
38
+ ```
39
+
40
+ ## Default environment variables
41
+
42
+ `StackgenConfig.from_env()` reads **only** these (optional convenience):
43
+
44
+ | Variable | Purpose |
45
+ |----------|---------|
46
+ | `STACKGEN_URL` | Mothership URL (no path suffix) |
47
+ | `STACKGEN_TOKEN` | API token (`stackgen_…`) |
48
+ | `STACKGEN_PROJECT` | Project / org UUID (`orgId`) |
49
+
50
+ Pass `webhook_token`, `webhook_id`, timeouts, and artifact paths as `StackgenConfig` fields — not via env.
51
+
52
+ ```python
53
+ from dataclasses import replace
54
+ from stackgen import StackgenClient, StackgenConfig
55
+
56
+ client = StackgenClient(
57
+ replace(StackgenConfig.from_env(), webhook_token="sg_aios_…")
58
+ )
59
+ ```
60
+
61
+ ## Namespaces
62
+
63
+ - `client.aiden` — webhooks, Ask Guild, sessions, artifact download
64
+ - `client.sre` — alerts and investigations
65
+ - `client.vault` — secrets (not enabled in this release)
66
+
67
+ Prefer `StackgenClient` over `stackgen.generated`.
68
+
69
+ Pin versions in CI: `pip install stackgen-sdk==0.1.5`.
70
+
71
+ **Documentation:** [https://appcd-dev.github.io/stackgen-sdk/](https://appcd-dev.github.io/stackgen-sdk/) (Aiden guide, [FAQ](https://appcd-dev.github.io/stackgen-sdk/faq/), [code samples](https://appcd-dev.github.io/stackgen-sdk/code-samples/))
@@ -19,7 +19,10 @@ dependencies = [
19
19
  ]
20
20
 
21
21
  [project.urls]
22
- Homepage = "https://pypi.org/project/stackgen-sdk/"
22
+ Homepage = "https://appcd-dev.github.io/stackgen-sdk/"
23
+ Documentation = "https://appcd-dev.github.io/stackgen-sdk/"
24
+ Repository = "https://github.com/appcd-dev/stackgen-sdk"
25
+ "Bug Tracker" = "https://github.com/appcd-dev/stackgen-sdk/issues"
23
26
 
24
27
  [project.optional-dependencies]
25
28
  dev = ["pytest>=8.0", "build>=1.2"]
@@ -4,8 +4,13 @@ Public entrypoint::
4
4
 
5
5
  from stackgen import StackgenClient, StackgenConfig
6
6
 
7
- client = StackgenClient.from_env()
8
- result = client.aiden.run_webhook_and_download_report(payload)
7
+ client = StackgenClient(
8
+ StackgenConfig(
9
+ base_url="https://app.stackgen.com",
10
+ api_token="stackgen_…",
11
+ org_id="<project-uuid>",
12
+ )
13
+ )
9
14
  """
10
15
 
11
16
  from __future__ import annotations
@@ -13,14 +18,32 @@ from __future__ import annotations
13
18
  from stackgen.client import StackgenClient
14
19
  from stackgen.config import StackgenConfig
15
20
  from stackgen.errors import HttpError, NotAllowlistedError, StackgenError, TimeoutError
21
+ from stackgen.aiden.workflow_builder import (
22
+ AgentDefinition,
23
+ StageDefinition,
24
+ WorkflowBuilder,
25
+ WorkflowDefinition,
26
+ create_agent,
27
+ create_stage,
28
+ create_workflow,
29
+ )
30
+ from stackgen.aiden.workflow_publish import PublishWorkflowResult
16
31
 
17
32
  __all__ = [
33
+ "AgentDefinition",
18
34
  "HttpError",
19
35
  "NotAllowlistedError",
36
+ "PublishWorkflowResult",
20
37
  "StackgenClient",
21
38
  "StackgenConfig",
22
39
  "StackgenError",
40
+ "StageDefinition",
23
41
  "TimeoutError",
42
+ "WorkflowBuilder",
43
+ "WorkflowDefinition",
44
+ "create_agent",
45
+ "create_stage",
46
+ "create_workflow",
24
47
  ]
25
48
 
26
49
 
@@ -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.3'
22
- __version_tuple__ = version_tuple = (0, 1, 3)
21
+ __version__ = version = '0.1.6'
22
+ __version_tuple__ = version_tuple = (0, 1, 6)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -0,0 +1,29 @@
1
+ """Aiden (platform) namespace — webhooks, sessions, artifacts, Ask Guild, workflows."""
2
+
3
+ from stackgen.aiden.ask import AskArtifactResult
4
+ from stackgen.aiden.namespace import AidenNamespace
5
+ from stackgen.aiden.webhook import WebhookReportResult
6
+ from stackgen.aiden.workflow_builder import (
7
+ AgentDefinition,
8
+ StageDefinition,
9
+ WorkflowBuilder,
10
+ WorkflowDefinition,
11
+ create_agent,
12
+ create_stage,
13
+ create_workflow,
14
+ )
15
+ from stackgen.aiden.workflow_publish import PublishWorkflowResult
16
+
17
+ __all__ = [
18
+ "AgentDefinition",
19
+ "AidenNamespace",
20
+ "AskArtifactResult",
21
+ "PublishWorkflowResult",
22
+ "StageDefinition",
23
+ "WebhookReportResult",
24
+ "WorkflowBuilder",
25
+ "WorkflowDefinition",
26
+ "create_agent",
27
+ "create_stage",
28
+ "create_workflow",
29
+ ]
@@ -0,0 +1,172 @@
1
+ """Aiden Ask → execution poll → artifact download journey."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import time
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from stackgen import _http
12
+ from stackgen.aiden import sessions as session_helpers
13
+ from stackgen.config import StackgenConfig
14
+ from stackgen.errors import StackgenError, TimeoutError
15
+
16
+ _TERMINAL_STATUSES = frozenset({"completed", "error"})
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class AskArtifactResult:
21
+ """Result of Ask start → wait → download session artifact."""
22
+
23
+ trace_id: str
24
+ run_id: str
25
+ session_id: str
26
+ artifacts: tuple[dict[str, Any], ...]
27
+ output_path: Path
28
+ candidates: tuple[dict[str, Any], ...] = ()
29
+ plan: str = ""
30
+
31
+
32
+ class AskArtifactJourney:
33
+ """Start Ask Guild, poll execution trace, wait for artifact, download it.
34
+
35
+ Uses ``api_token`` and ``org_id`` only (no webhook token).
36
+ """
37
+
38
+ def __init__(self, config: StackgenConfig) -> None:
39
+ self._config = config
40
+
41
+ def run(
42
+ self,
43
+ message: str,
44
+ *,
45
+ entity_refs: list[dict[str, str]] | None = None,
46
+ artifact_name: str | None = None,
47
+ output_path: str | None = None,
48
+ inputs: dict[str, str] | None = None,
49
+ session_id: str | None = None,
50
+ source_app: str | None = None,
51
+ source_metadata: dict[str, str] | None = None,
52
+ ) -> AskArtifactResult:
53
+ cfg = self._config
54
+ artifact = artifact_name or cfg.artifact_name
55
+ dest = output_path or cfg.output_path
56
+
57
+ start = self.start_ask(
58
+ message,
59
+ entity_refs=entity_refs,
60
+ inputs=inputs,
61
+ session_id=session_id,
62
+ source_app=source_app,
63
+ source_metadata=source_metadata,
64
+ )
65
+ trace_id = _http.text(start.get("trace_id"))
66
+ if not trace_id:
67
+ raise StackgenError(
68
+ "startAskGuild did not return trace_id; "
69
+ f"body={json.dumps(start)}"
70
+ )
71
+
72
+ run_id = _http.text(start.get("run_id"))
73
+ resolved_session = _http.text(start.get("session_id")) or _http.text(session_id)
74
+ plan = _http.text(start.get("plan"))
75
+ candidates = tuple(start.get("candidates") or ())
76
+
77
+ trace = self.wait_for_execution(trace_id)
78
+ if not resolved_session:
79
+ resolved_session = _http.text(trace.get("session_id"))
80
+ execution = trace.get("execution") or {}
81
+ if not resolved_session:
82
+ raise StackgenError(
83
+ f"execution {trace_id} settled without session_id; "
84
+ "cannot download artifacts"
85
+ )
86
+ if not run_id:
87
+ run_id = _http.text(execution.get("run_id"))
88
+
89
+ artifacts = session_helpers.wait_for_artifact(cfg, resolved_session, artifact)
90
+ path = session_helpers.download_artifact(cfg, resolved_session, artifact, dest)
91
+ return AskArtifactResult(
92
+ trace_id=trace_id,
93
+ run_id=run_id,
94
+ session_id=resolved_session,
95
+ artifacts=tuple(artifacts),
96
+ output_path=path,
97
+ candidates=candidates,
98
+ plan=plan,
99
+ )
100
+
101
+ def start_ask(
102
+ self,
103
+ message: str,
104
+ *,
105
+ entity_refs: list[dict[str, str]] | None = None,
106
+ inputs: dict[str, str] | None = None,
107
+ session_id: str | None = None,
108
+ source_app: str | None = None,
109
+ source_metadata: dict[str, str] | None = None,
110
+ ) -> dict[str, Any]:
111
+ """POST /guild/api/v1/guild/ask/start."""
112
+ body: dict[str, Any] = {"message": message}
113
+ if entity_refs:
114
+ body["entity_refs"] = entity_refs
115
+ if inputs:
116
+ body["inputs"] = inputs
117
+ if session_id:
118
+ body["session_id"] = session_id
119
+ if source_app:
120
+ body["source_app"] = source_app
121
+ if source_metadata:
122
+ body["source_metadata"] = source_metadata
123
+
124
+ url = (
125
+ f"{self._config.aiden_url()}/api/v1/guild/ask/start"
126
+ f"{_http.query(self._config.org_id)}"
127
+ )
128
+ data = _http.request(
129
+ url,
130
+ self._config.api_token,
131
+ method="POST",
132
+ body=json.dumps(body).encode("utf-8"),
133
+ content_type="application/json",
134
+ )
135
+ if not isinstance(data, dict):
136
+ raise StackgenError(f"unexpected startAskGuild payload: {data!r}")
137
+
138
+ inputs_required = data.get("inputs_required") or []
139
+ if inputs_required:
140
+ raise StackgenError(
141
+ "Ask requires additional inputs before execution can start: "
142
+ f"{inputs_required}"
143
+ )
144
+ return data
145
+
146
+ def wait_for_execution(self, trace_id: str) -> dict[str, Any]:
147
+ """Poll GET /guild/api/v1/executions/{traceId} until settled."""
148
+ cfg = self._config
149
+ deadline = time.monotonic() + cfg.timeout_seconds
150
+ url = (
151
+ f"{cfg.aiden_url()}/api/v1/executions/{trace_id}"
152
+ f"{_http.query(cfg.org_id)}"
153
+ )
154
+ while time.monotonic() < deadline:
155
+ data = _http.request(url, cfg.api_token)
156
+ if not isinstance(data, dict):
157
+ raise StackgenError(f"unexpected getExecutionTrace payload: {data!r}")
158
+ execution = data.get("execution") or {}
159
+ status = _http.text(execution.get("status")).casefold()
160
+ # Prefer explicit settle when the mothership sends it. Some builds
161
+ # omit trace_settled on the thin getExecutionTrace summary; treat
162
+ # terminal status alone as done so callers are not stuck forever.
163
+ settled = execution.get("trace_settled")
164
+ ready = status in _TERMINAL_STATUSES and settled is not False
165
+ if ready:
166
+ if status == "error":
167
+ raise StackgenError(
168
+ f"execution {trace_id} ended with status error"
169
+ )
170
+ return data
171
+ time.sleep(cfg.poll_interval_seconds)
172
+ raise TimeoutError("execution", cfg.timeout_seconds)
@@ -0,0 +1,170 @@
1
+ """Aiden namespace — public methods for platform APIs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from stackgen.aiden.ask import AskArtifactJourney, AskArtifactResult
9
+ from stackgen.aiden.webhook import WebhookReportJourney, WebhookReportResult
10
+ from stackgen.aiden.webhook_ops import WebhookOps
11
+ from stackgen.aiden.workflow_builder import AgentDefinition, WorkflowDefinition
12
+ from stackgen.aiden.workflow_publish import PublishWorkflowResult, WorkflowPublishJourney
13
+ from stackgen.config import StackgenConfig
14
+
15
+
16
+ class AidenNamespace:
17
+ """Aiden platform APIs (sessions, webhooks, artifacts, Ask Guild, workflows)."""
18
+
19
+ def __init__(self, config: StackgenConfig) -> None:
20
+ self._config = config
21
+ self._webhook = WebhookReportJourney(config)
22
+ self._ask = AskArtifactJourney(config)
23
+ self._workflows = WorkflowPublishJourney(config)
24
+ self._webhook_ops = WebhookOps(config)
25
+
26
+ def run_webhook_and_download_report(
27
+ self,
28
+ payload: str,
29
+ *,
30
+ artifact_name: str | None = None,
31
+ output_path: str | None = None,
32
+ ) -> WebhookReportResult:
33
+ """Trigger a webhook, wait for the session artifact, download it."""
34
+ return self._webhook.run(
35
+ payload, artifact_name=artifact_name, output_path=output_path
36
+ )
37
+
38
+ def trigger_webhook(self, payload: str) -> dict[str, Any]:
39
+ """POST /guild/api/v1/webhooks/trigger (stateless; returns 202 body)."""
40
+ return self._webhook_ops.trigger_webhook(payload)
41
+
42
+ def get_webhook_run(self, webhook_id: str, invocation_id: str) -> dict[str, Any]:
43
+ """GET webhook invocation detail by invocation UUID."""
44
+ return self._webhook_ops.get_webhook_run(webhook_id, invocation_id)
45
+
46
+ def list_webhook_runs(self, webhook_id: str) -> list[dict[str, Any]]:
47
+ """List webhook invocations for a webhook id."""
48
+ return self._webhook_ops.list_webhook_runs(webhook_id)
49
+
50
+ def wait_for_webhook_session(
51
+ self,
52
+ webhook_id: str,
53
+ invocation_id: str,
54
+ *,
55
+ dispatch_run_id: str = "",
56
+ known_run_ids: frozenset[str] | None = None,
57
+ ) -> str:
58
+ """Poll webhook run detail until session_id is set."""
59
+ return self._webhook_ops.wait_for_webhook_session(
60
+ webhook_id,
61
+ invocation_id,
62
+ dispatch_run_id=dispatch_run_id,
63
+ known_run_ids=known_run_ids,
64
+ )
65
+
66
+ def get_execution_trace(self, trace_id: str) -> dict[str, Any]:
67
+ """GET /guild/api/v1/executions/{traceId}."""
68
+ return self._webhook_ops.get_execution_trace(trace_id)
69
+
70
+ def list_executions(self, **params: Any) -> list[dict[str, Any]]:
71
+ """GET /guild/api/v1/executions (optional session_id filter)."""
72
+ return self._webhook_ops.list_executions(**params)
73
+
74
+ def list_sessions(self, **params: Any) -> dict[str, Any]:
75
+ """GET /guild/api/v1/sessions (search with q / source_app)."""
76
+ return self._webhook_ops.list_sessions(**params)
77
+
78
+ def get_session(self, session_id: str) -> dict[str, Any]:
79
+ """GET /guild/api/v1/sessions/{sessionId}."""
80
+ return self._webhook_ops.get_session(session_id)
81
+
82
+ def list_session_artifacts(self, session_id: str) -> list[dict[str, Any]]:
83
+ """GET session artifact metadata list."""
84
+ return self._webhook_ops.list_session_artifacts(session_id)
85
+
86
+ def download_session_artifact(
87
+ self,
88
+ session_id: str,
89
+ artifact_name: str,
90
+ output_path: str,
91
+ ) -> Path:
92
+ """Download one session artifact to a local path."""
93
+ return self._webhook_ops.download_session_artifact(
94
+ session_id, artifact_name, output_path
95
+ )
96
+
97
+ def export_session(
98
+ self,
99
+ session_id: str,
100
+ *,
101
+ parts: str | None = None,
102
+ format: str = "json",
103
+ ) -> dict[str, Any]:
104
+ """GET /guild/api/v1/sessions/{sessionId}/export (report / notes / evidence)."""
105
+ return self._webhook_ops.export_session(session_id, parts=parts, format=format)
106
+
107
+ def terminate_session(self, session_id: str, *, reason: str | None = None) -> dict[str, Any]:
108
+ """POST /guild/api/v1/sessions/{sessionId}/terminate."""
109
+ return self._webhook_ops.terminate_session(session_id, reason=reason)
110
+
111
+ def run_ask_and_download_artifact(
112
+ self,
113
+ message: str,
114
+ *,
115
+ entity_refs: list[dict[str, str]] | None = None,
116
+ artifact_name: str | None = None,
117
+ output_path: str | None = None,
118
+ inputs: dict[str, str] | None = None,
119
+ session_id: str | None = None,
120
+ source_app: str | None = None,
121
+ source_metadata: dict[str, str] | None = None,
122
+ ) -> AskArtifactResult:
123
+ """Start Ask Guild, poll execution, wait for artifact, download it."""
124
+ return self._ask.run(
125
+ message,
126
+ entity_refs=entity_refs,
127
+ artifact_name=artifact_name,
128
+ output_path=output_path,
129
+ inputs=inputs,
130
+ session_id=session_id,
131
+ source_app=source_app,
132
+ source_metadata=source_metadata,
133
+ )
134
+
135
+ def start_ask(
136
+ self,
137
+ message: str,
138
+ *,
139
+ entity_refs: list[dict[str, str]] | None = None,
140
+ inputs: dict[str, str] | None = None,
141
+ session_id: str | None = None,
142
+ source_app: str | None = None,
143
+ source_metadata: dict[str, str] | None = None,
144
+ ) -> dict[str, Any]:
145
+ """POST /guild/api/v1/guild/ask/start (advanced callers)."""
146
+ return self._ask.start_ask(
147
+ message,
148
+ entity_refs=entity_refs,
149
+ inputs=inputs,
150
+ session_id=session_id,
151
+ source_app=source_app,
152
+ source_metadata=source_metadata,
153
+ )
154
+
155
+ def wait_for_execution(self, trace_id: str) -> dict[str, Any]:
156
+ """Poll GET /guild/api/v1/executions/{traceId} until settled."""
157
+ return self._ask.wait_for_execution(trace_id)
158
+
159
+ def publish_workflow(
160
+ self,
161
+ workflow: WorkflowDefinition,
162
+ *,
163
+ agents: list[AgentDefinition] | None = None,
164
+ approve: bool = True,
165
+ ) -> PublishWorkflowResult:
166
+ """Register/update agents and create/update a workflow, optionally approving it.
167
+
168
+ Pass a committed builder from ``create_workflow(...).then(...).commit()``.
169
+ """
170
+ return self._workflows.publish(workflow, agents=agents, approve=approve)