yera 0.1.1__tar.gz → 0.2.1__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 (213) hide show
  1. yera-0.2.1/.containerignore +14 -0
  2. yera-0.2.1/.github/actions/build-ui/action.yml +38 -0
  3. yera-0.2.1/.github/actions/run-build-tests/action.yml +19 -0
  4. yera-0.2.1/.github/actions/run-package-tests/action.yml +24 -0
  5. yera-0.2.1/.github/python-versions.json +1 -0
  6. yera-0.2.1/.github/workflows/benchmarks.yml +35 -0
  7. yera-0.2.1/.github/workflows/build-and-test-package.yml +67 -0
  8. yera-0.2.1/.github/workflows/ci-cd.yml +178 -0
  9. yera-0.2.1/.github/workflows/deploy-aks.yml +64 -0
  10. yera-0.2.1/.github/workflows/deploy-eks.yml +86 -0
  11. yera-0.2.1/.github/workflows/destroy-aks.yml +138 -0
  12. yera-0.2.1/.github/workflows/destroy-eks.yml +131 -0
  13. yera-0.2.1/.github/workflows/release.yml +93 -0
  14. yera-0.2.1/.gitignore +45 -0
  15. yera-0.2.1/.pre-commit-config.yaml +39 -0
  16. yera-0.2.1/CONTRIBUTING.md +157 -0
  17. yera-0.2.1/PKG-INFO +65 -0
  18. yera-0.2.1/README.md +27 -0
  19. yera-0.2.1/pyproject.toml +298 -0
  20. yera-0.2.1/src/infra_mvp/base_client.py +29 -0
  21. yera-0.2.1/src/infra_mvp/base_server.py +68 -0
  22. yera-0.2.1/src/infra_mvp/monitoring/__init__.py +15 -0
  23. yera-0.2.1/src/infra_mvp/monitoring/metrics.py +185 -0
  24. yera-0.2.1/src/infra_mvp/stream/README.md +56 -0
  25. yera-0.2.1/src/infra_mvp/stream/__init__.py +14 -0
  26. yera-0.2.1/src/infra_mvp/stream/__main__.py +101 -0
  27. yera-0.2.1/src/infra_mvp/stream/agents/demos/financial/chart_additions_plan.md +170 -0
  28. yera-0.2.1/src/infra_mvp/stream/agents/demos/financial/portfolio_assistant_stream.json +1571 -0
  29. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/action.json +170 -0
  30. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/button.json +66 -0
  31. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/date.json +65 -0
  32. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/input_prompt.json +94 -0
  33. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/layout.json +288 -0
  34. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/markdown.json +344 -0
  35. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/slider.json +67 -0
  36. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/spinner.json +110 -0
  37. yera-0.2.1/src/infra_mvp/stream/agents/reference/blocks/table.json +56 -0
  38. yera-0.2.1/src/infra_mvp/stream/agents/reference/chat_dynamics/branching_test_stream.json +145 -0
  39. yera-0.2.1/src/infra_mvp/stream/app.py +49 -0
  40. yera-0.2.1/src/infra_mvp/stream/container.py +112 -0
  41. yera-0.2.1/src/infra_mvp/stream/schemas/__init__.py +16 -0
  42. yera-0.2.1/src/infra_mvp/stream/schemas/agent.py +24 -0
  43. yera-0.2.1/src/infra_mvp/stream/schemas/interaction.py +28 -0
  44. yera-0.2.1/src/infra_mvp/stream/schemas/session.py +30 -0
  45. yera-0.2.1/src/infra_mvp/stream/server.py +321 -0
  46. yera-0.2.1/src/infra_mvp/stream/services/__init__.py +12 -0
  47. yera-0.2.1/src/infra_mvp/stream/services/agent_service.py +40 -0
  48. yera-0.2.1/src/infra_mvp/stream/services/event_converter.py +83 -0
  49. yera-0.2.1/src/infra_mvp/stream/services/session_service.py +247 -0
  50. yera-0.2.1/src/yera/__init__.py +51 -0
  51. yera-0.2.1/src/yera/agents/__init__.py +2 -0
  52. yera-0.2.1/src/yera/agents/context.py +41 -0
  53. yera-0.2.1/src/yera/agents/dataclasses.py +69 -0
  54. yera-0.2.1/src/yera/agents/decorator.py +207 -0
  55. yera-0.2.1/src/yera/agents/discovery.py +124 -0
  56. yera-0.2.1/src/yera/agents/typing/__init__.py +0 -0
  57. yera-0.2.1/src/yera/agents/typing/coerce.py +408 -0
  58. yera-0.2.1/src/yera/agents/typing/utils.py +19 -0
  59. yera-0.2.1/src/yera/agents/typing/validate.py +206 -0
  60. yera-0.2.1/src/yera/cli.py +377 -0
  61. yera-0.2.1/src/yera/config/__init__.py +1 -0
  62. yera-0.2.1/src/yera/config/config_utils.py +164 -0
  63. yera-0.2.1/src/yera/config/function_config.py +55 -0
  64. yera-0.2.1/src/yera/config/logging.py +18 -0
  65. yera-0.2.1/src/yera/config/tool_config.py +8 -0
  66. yera-0.2.1/src/yera/config2/__init__.py +8 -0
  67. yera-0.2.1/src/yera/config2/dataclasses.py +534 -0
  68. yera-0.2.1/src/yera/config2/keyring.py +270 -0
  69. yera-0.2.1/src/yera/config2/paths.py +28 -0
  70. yera-0.2.1/src/yera/config2/read.py +113 -0
  71. yera-0.2.1/src/yera/config2/setup.py +109 -0
  72. yera-0.2.1/src/yera/config2/setup_handlers/__init__.py +1 -0
  73. yera-0.2.1/src/yera/config2/setup_handlers/anthropic.py +126 -0
  74. yera-0.2.1/src/yera/config2/setup_handlers/azure.py +236 -0
  75. yera-0.2.1/src/yera/config2/setup_handlers/base.py +125 -0
  76. yera-0.2.1/src/yera/config2/setup_handlers/llama_cpp.py +205 -0
  77. yera-0.2.1/src/yera/config2/setup_handlers/ollama.py +157 -0
  78. yera-0.2.1/src/yera/config2/setup_handlers/openai.py +137 -0
  79. yera-0.2.1/src/yera/config2/write.py +87 -0
  80. yera-0.2.1/src/yera/dsl/__init__.py +0 -0
  81. yera-0.2.1/src/yera/dsl/functions.py +94 -0
  82. yera-0.2.1/src/yera/dsl/struct.py +20 -0
  83. yera-0.2.1/src/yera/dsl/workspace.py +79 -0
  84. yera-0.2.1/src/yera/events/__init__.py +57 -0
  85. yera-0.2.1/src/yera/events/blocks/__init__.py +68 -0
  86. yera-0.2.1/src/yera/events/blocks/action.py +57 -0
  87. yera-0.2.1/src/yera/events/blocks/bar_chart.py +92 -0
  88. yera-0.2.1/src/yera/events/blocks/base/__init__.py +20 -0
  89. yera-0.2.1/src/yera/events/blocks/base/base.py +166 -0
  90. yera-0.2.1/src/yera/events/blocks/base/chart.py +288 -0
  91. yera-0.2.1/src/yera/events/blocks/base/layout.py +111 -0
  92. yera-0.2.1/src/yera/events/blocks/buttons.py +37 -0
  93. yera-0.2.1/src/yera/events/blocks/columns.py +26 -0
  94. yera-0.2.1/src/yera/events/blocks/container.py +24 -0
  95. yera-0.2.1/src/yera/events/blocks/date_picker.py +50 -0
  96. yera-0.2.1/src/yera/events/blocks/exit.py +39 -0
  97. yera-0.2.1/src/yera/events/blocks/form.py +24 -0
  98. yera-0.2.1/src/yera/events/blocks/input_echo.py +22 -0
  99. yera-0.2.1/src/yera/events/blocks/input_request.py +31 -0
  100. yera-0.2.1/src/yera/events/blocks/line_chart.py +97 -0
  101. yera-0.2.1/src/yera/events/blocks/markdown.py +67 -0
  102. yera-0.2.1/src/yera/events/blocks/slider.py +54 -0
  103. yera-0.2.1/src/yera/events/blocks/spinner.py +55 -0
  104. yera-0.2.1/src/yera/events/blocks/system_prompt.py +22 -0
  105. yera-0.2.1/src/yera/events/blocks/table.py +291 -0
  106. yera-0.2.1/src/yera/events/models/__init__.py +39 -0
  107. yera-0.2.1/src/yera/events/models/block_data.py +112 -0
  108. yera-0.2.1/src/yera/events/models/in_event.py +7 -0
  109. yera-0.2.1/src/yera/events/models/out_event.py +75 -0
  110. yera-0.2.1/src/yera/events/runtime.py +187 -0
  111. yera-0.2.1/src/yera/events/stream.py +91 -0
  112. yera-0.2.1/src/yera/models/__init__.py +0 -0
  113. yera-0.2.1/src/yera/models/data_classes.py +20 -0
  114. yera-0.2.1/src/yera/models/llm_atlas_proxy.py +44 -0
  115. yera-0.2.1/src/yera/models/llm_context.py +99 -0
  116. yera-0.2.1/src/yera/models/llm_interfaces/__init__.py +0 -0
  117. yera-0.2.1/src/yera/models/llm_interfaces/anthropic.py +153 -0
  118. yera-0.2.1/src/yera/models/llm_interfaces/aws_bedrock.py +14 -0
  119. yera-0.2.1/src/yera/models/llm_interfaces/azure_openai.py +143 -0
  120. yera-0.2.1/src/yera/models/llm_interfaces/base.py +26 -0
  121. yera-0.2.1/src/yera/models/llm_interfaces/interface_registry.py +74 -0
  122. yera-0.2.1/src/yera/models/llm_interfaces/llama_cpp.py +136 -0
  123. yera-0.2.1/src/yera/models/llm_interfaces/mock.py +29 -0
  124. yera-0.2.1/src/yera/models/llm_interfaces/ollama_interface.py +118 -0
  125. yera-0.2.1/src/yera/models/llm_interfaces/open_ai.py +150 -0
  126. yera-0.2.1/src/yera/models/llm_workspace.py +19 -0
  127. yera-0.2.1/src/yera/models/model_atlas.py +139 -0
  128. yera-0.2.1/src/yera/models/model_definition.py +38 -0
  129. yera-0.2.1/src/yera/models/model_factory.py +33 -0
  130. yera-0.2.1/src/yera/opaque/__init__.py +9 -0
  131. yera-0.2.1/src/yera/opaque/base.py +20 -0
  132. yera-0.2.1/src/yera/opaque/decorator.py +8 -0
  133. yera-0.2.1/src/yera/opaque/markdown.py +57 -0
  134. yera-0.2.1/src/yera/opaque/opaque_function.py +25 -0
  135. yera-0.2.1/src/yera/tools/__init__.py +29 -0
  136. yera-0.2.1/src/yera/tools/atlas_tool.py +20 -0
  137. yera-0.2.1/src/yera/tools/base.py +24 -0
  138. yera-0.2.1/src/yera/tools/decorated_tool.py +18 -0
  139. yera-0.2.1/src/yera/tools/decorator.py +35 -0
  140. yera-0.2.1/src/yera/tools/tool_atlas.py +51 -0
  141. yera-0.2.1/src/yera/tools/tool_utils.py +361 -0
  142. yera-0.2.1/src/yera/ui/dist/404.html +1 -0
  143. yera-0.2.1/src/yera/ui/dist/__next.__PAGE__.txt +10 -0
  144. yera-0.2.1/src/yera/ui/dist/__next._full.txt +23 -0
  145. yera-0.2.1/src/yera/ui/dist/__next._head.txt +6 -0
  146. yera-0.2.1/src/yera/ui/dist/__next._index.txt +5 -0
  147. yera-0.2.1/src/yera/ui/dist/__next._tree.txt +7 -0
  148. yera-0.2.1/src/yera/ui/dist/_next/static/T8WGYqDMoHDKKoHj0O3HK/_buildManifest.js +11 -0
  149. yera-0.2.1/src/yera/ui/dist/_next/static/T8WGYqDMoHDKKoHj0O3HK/_clientMiddlewareManifest.json +1 -0
  150. yera-0.2.1/src/yera/ui/dist/_next/static/T8WGYqDMoHDKKoHj0O3HK/_ssgManifest.js +1 -0
  151. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/4c4688e1ff21ad98.js +1 -0
  152. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/652cd53c27924d50.js +4 -0
  153. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/786d2107b51e8499.css +1 -0
  154. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/7de9141b1af425c3.js +1 -0
  155. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/87ef65064d3524c1.js +2 -0
  156. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  157. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
  158. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/c4c79d5d0b280aeb.js +1 -0
  159. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/dc2d2a247505d66f.css +5 -0
  160. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/f773f714b55ec620.js +37 -0
  161. yera-0.2.1/src/yera/ui/dist/_next/static/chunks/turbopack-98b3031e1b1dbc33.js +4 -0
  162. yera-0.2.1/src/yera/ui/dist/_next/static/media/14e23f9b59180572-s.9c448f3c.woff2 +0 -0
  163. yera-0.2.1/src/yera/ui/dist/_next/static/media/2a65768255d6b625-s.p.d19752fb.woff2 +0 -0
  164. yera-0.2.1/src/yera/ui/dist/_next/static/media/2b2eb4836d2dad95-s.f36de3af.woff2 +0 -0
  165. yera-0.2.1/src/yera/ui/dist/_next/static/media/31183d9fd602dc89-s.c4ff9b73.woff2 +0 -0
  166. yera-0.2.1/src/yera/ui/dist/_next/static/media/3fcb63a1ac6a562e-s.2f77a576.woff2 +0 -0
  167. yera-0.2.1/src/yera/ui/dist/_next/static/media/45ec8de98929b0f6-s.81056204.woff2 +0 -0
  168. yera-0.2.1/src/yera/ui/dist/_next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  169. yera-0.2.1/src/yera/ui/dist/_next/static/media/65c558afe41e89d6-s.e2c8389a.woff2 +0 -0
  170. yera-0.2.1/src/yera/ui/dist/_next/static/media/67add6cc0f54b8cf-s.8ce53448.woff2 +0 -0
  171. yera-0.2.1/src/yera/ui/dist/_next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  172. yera-0.2.1/src/yera/ui/dist/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  173. yera-0.2.1/src/yera/ui/dist/_next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  174. yera-0.2.1/src/yera/ui/dist/_next/static/media/a8ff2d5d0ccb0d12-s.fc5b72a7.woff2 +0 -0
  175. yera-0.2.1/src/yera/ui/dist/_next/static/media/aae5f0be330e13db-s.p.853e26d6.woff2 +0 -0
  176. yera-0.2.1/src/yera/ui/dist/_next/static/media/b11a6ccf4a3edec7-s.2113d282.woff2 +0 -0
  177. yera-0.2.1/src/yera/ui/dist/_next/static/media/b49b0d9b851e4899-s.4f3fa681.woff2 +0 -0
  178. yera-0.2.1/src/yera/ui/dist/_next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  179. yera-0.2.1/src/yera/ui/dist/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  180. yera-0.2.1/src/yera/ui/dist/_next/static/media/favicon.0b3bf435.ico +0 -0
  181. yera-0.2.1/src/yera/ui/dist/_not-found/__next._full.txt +14 -0
  182. yera-0.2.1/src/yera/ui/dist/_not-found/__next._head.txt +6 -0
  183. yera-0.2.1/src/yera/ui/dist/_not-found/__next._index.txt +5 -0
  184. yera-0.2.1/src/yera/ui/dist/_not-found/__next._not-found.__PAGE__.txt +5 -0
  185. yera-0.2.1/src/yera/ui/dist/_not-found/__next._not-found.txt +4 -0
  186. yera-0.2.1/src/yera/ui/dist/_not-found/__next._tree.txt +2 -0
  187. yera-0.2.1/src/yera/ui/dist/_not-found.html +1 -0
  188. yera-0.2.1/src/yera/ui/dist/_not-found.txt +14 -0
  189. yera-0.2.1/src/yera/ui/dist/agent-icon.svg +3 -0
  190. yera-0.2.1/src/yera/ui/dist/favicon.ico +0 -0
  191. yera-0.2.1/src/yera/ui/dist/file.svg +1 -0
  192. yera-0.2.1/src/yera/ui/dist/globe.svg +1 -0
  193. yera-0.2.1/src/yera/ui/dist/index.html +1 -0
  194. yera-0.2.1/src/yera/ui/dist/index.txt +23 -0
  195. yera-0.2.1/src/yera/ui/dist/logo/full_logo.png +0 -0
  196. yera-0.2.1/src/yera/ui/dist/logo/rune_logo.png +0 -0
  197. yera-0.2.1/src/yera/ui/dist/logo/rune_logo_borderless.png +0 -0
  198. yera-0.2.1/src/yera/ui/dist/logo/text_logo.png +0 -0
  199. yera-0.2.1/src/yera/ui/dist/next.svg +1 -0
  200. yera-0.2.1/src/yera/ui/dist/send.png +0 -0
  201. yera-0.2.1/src/yera/ui/dist/send_single.png +0 -0
  202. yera-0.2.1/src/yera/ui/dist/vercel.svg +1 -0
  203. yera-0.2.1/src/yera/ui/dist/window.svg +1 -0
  204. yera-0.2.1/src/yera/utils/__init__.py +1 -0
  205. yera-0.2.1/src/yera/utils/path_utils.py +38 -0
  206. yera-0.2.1/uv.lock +5418 -0
  207. yera-0.1.1/.gitignore +0 -10
  208. yera-0.1.1/PKG-INFO +0 -11
  209. yera-0.1.1/README.md +0 -4
  210. yera-0.1.1/main.py +0 -6
  211. yera-0.1.1/pyproject.toml +0 -11
  212. yera-0.1.1/src/yera/__init__.py +0 -2
  213. {yera-0.1.1 → yera-0.2.1}/.python-version +0 -0
@@ -0,0 +1,14 @@
1
+ # Create .containerignore (or rename .dockerignore)
2
+ cat > .containerignore << EOF
3
+ __pycache__
4
+ *.pyc
5
+ *.pyo
6
+ .git
7
+ .venv
8
+ *.egg-info
9
+ .pytest_cache
10
+ .vscode
11
+ .idea
12
+ logs/
13
+ reports/
14
+ EOF
@@ -0,0 +1,38 @@
1
+ name: 'Build UI for Editable Install'
2
+ description: 'Builds the Next.js UI and copies it to src/yera/ui/dist for hatchling force-include'
3
+
4
+ inputs:
5
+ node-version:
6
+ description: 'Node.js version to use'
7
+ required: false
8
+ default: '20'
9
+
10
+ runs:
11
+ using: 'composite'
12
+ steps:
13
+ - name: Set up Node.js
14
+ uses: actions/setup-node@v4
15
+ with:
16
+ node-version: ${{ inputs.node-version }}
17
+ cache: 'npm'
18
+ cache-dependency-path: web/yera-chat/package-lock.json
19
+
20
+ - name: Build UI for editable install
21
+ shell: bash
22
+ run: |
23
+ cd web/yera-chat
24
+ npm install
25
+ npm run build
26
+ cd ../..
27
+ mkdir -p src/yera/ui
28
+ rm -rf src/yera/ui/dist
29
+ cp -r web/yera-chat/dist src/yera/ui/
30
+
31
+ - name: Verify UI build succeeded
32
+ shell: bash
33
+ run: |
34
+ if [ ! -f "src/yera/ui/dist/index.html" ]; then
35
+ echo "❌ UI build failed: src/yera/ui/dist/index.html not found"
36
+ exit 1
37
+ fi
38
+ echo "✅ UI build verified: dist/index.html exists"
@@ -0,0 +1,19 @@
1
+ name: 'Run build verification tests'
2
+ description: 'Runs tests/release/build/ in a clean venv. Expects dist/ (wheel + sdist) to exist; call after building the package.'
3
+
4
+ runs:
5
+ using: 'composite'
6
+ steps:
7
+ - name: Install uv
8
+ uses: astral-sh/setup-uv@v4
9
+ with:
10
+ version: "latest"
11
+ enable-cache: true
12
+
13
+ - name: Install Python (from .python-version)
14
+ shell: bash
15
+ run: uv python install $(cat .python-version)
16
+
17
+ - name: Run build verification tests
18
+ shell: bash
19
+ run: ./scripts/release/tests/test_build.sh
@@ -0,0 +1,24 @@
1
+ name: 'Run package-level tests'
2
+ description: 'Runs tests/release/package/ in a clean venv. Expects dist/ (wheel) to exist; call after downloading the build artifact.'
3
+
4
+ inputs:
5
+ python-version:
6
+ description: 'Python version to use (e.g. 3.10, 3.11, 3.12).'
7
+ required: true
8
+
9
+ runs:
10
+ using: 'composite'
11
+ steps:
12
+ - name: Install uv
13
+ uses: astral-sh/setup-uv@v4
14
+ with:
15
+ version: "latest"
16
+ enable-cache: true
17
+
18
+ - name: Install Python
19
+ shell: bash
20
+ run: uv python install "${{ inputs.python-version }}"
21
+
22
+ - name: Run package tests
23
+ shell: bash
24
+ run: ./scripts/release/tests/test_package.sh
@@ -0,0 +1 @@
1
+ ["3.10", "3.11", "3.12"]
@@ -0,0 +1,35 @@
1
+ name: CodSpeed Benchmarks
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - "main"
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read # for actions/checkout
12
+ id-token: write # for OIDC authentication with CodSpeed (public repos)
13
+
14
+ jobs:
15
+ benchmarks:
16
+ name: Run performance benchmarks
17
+ runs-on: ubuntu-latest
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v7
24
+
25
+ - name: Build UI for editable install
26
+ uses: ./.github/actions/build-ui
27
+
28
+ - name: Install dependencies
29
+ run: uv sync --dev
30
+
31
+ - name: Run benchmarks
32
+ uses: CodSpeedHQ/action@v4
33
+ with:
34
+ mode: instrumentation # Uses Valgrind for consistent measurements + flame graphs
35
+ run: uv run pytest tests/src/performance/ --codspeed
@@ -0,0 +1,67 @@
1
+ # Reusable workflow: build distribution with bundled UI and run build/package tests.
2
+ # Used by ci-cd.yml (on push/PR) and release.yml (after version verification).
3
+ # Callers must pass python-versions (JSON array of version strings, e.g. ["3.10","3.11","3.12"]).
4
+ name: Build and test package
5
+
6
+ on:
7
+ workflow_call:
8
+ inputs:
9
+ python-versions:
10
+ description: 'JSON array of Python versions to test (e.g. ["3.10","3.11","3.12"])'
11
+ required: true
12
+ type: string
13
+
14
+ jobs:
15
+ build:
16
+ name: Build and test distribution
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 15
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Set up Node.js
23
+ uses: actions/setup-node@v4
24
+ with:
25
+ node-version: "20"
26
+ cache: 'npm'
27
+ cache-dependency-path: web/yera-chat/package-lock.json
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v4
31
+ with:
32
+ version: "latest"
33
+ enable-cache: true
34
+
35
+ - name: Build package with bundled UI
36
+ run: ./scripts/release/build_package.sh
37
+
38
+ - name: Run build verification tests
39
+ uses: ./.github/actions/run-build-tests
40
+
41
+ - name: Upload distribution packages
42
+ uses: actions/upload-artifact@v4
43
+ with:
44
+ name: python-package-distributions
45
+ path: dist/
46
+
47
+ test:
48
+ name: Test installation (Python ${{ matrix.python-version }})
49
+ needs: [build]
50
+ runs-on: ubuntu-latest
51
+ timeout-minutes: 10
52
+ strategy:
53
+ matrix:
54
+ python-version: ${{ fromJson(inputs.python-versions) }}
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+
58
+ - name: Download distributions
59
+ uses: actions/download-artifact@v4
60
+ with:
61
+ name: python-package-distributions
62
+ path: dist/
63
+
64
+ - name: Run package tests
65
+ uses: ./.github/actions/run-package-tests
66
+ with:
67
+ python-version: ${{ matrix.python-version }}
@@ -0,0 +1,178 @@
1
+ name: Python CI/CD with uv
2
+ on:
3
+ push:
4
+ branches: [ main, devel ]
5
+ pull_request:
6
+ types: [opened, synchronize, reopened, ready_for_review]
7
+ paths-ignore:
8
+ - '**.md'
9
+ - 'docs/**'
10
+ - '.gitignore'
11
+ - '.pre-commit-config.yaml'
12
+ - '.containerignore'
13
+ - '.dockerignore'
14
+ jobs:
15
+ setup:
16
+ name: Set Python matrix
17
+ runs-on: ubuntu-latest
18
+ outputs:
19
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - id: set-matrix
23
+ run: echo "matrix=$(tr -d '\n' < .github/python-versions.json)" >> $GITHUB_OUTPUT
24
+
25
+ test:
26
+ needs: setup
27
+ runs-on: ubuntu-latest
28
+ timeout-minutes: 10
29
+ strategy:
30
+ matrix:
31
+ python-version: ${{ fromJson(needs.setup.outputs.matrix) }}
32
+ steps:
33
+ # downloads repository's source code into the GitHub Actions runner
34
+ - uses: actions/checkout@v4
35
+ - name: Install uv
36
+ uses: astral-sh/setup-uv@v4
37
+ with:
38
+ version: "latest"
39
+ enable-cache: true
40
+ - name: Set up Python ${{ matrix.python-version }}
41
+ run: uv python install ${{ matrix.python-version }}
42
+ - name: Build UI for editable install
43
+ uses: ./.github/actions/build-ui
44
+ # Fail fast: Check formatting and linting before installing dependencies
45
+ - name: Check code formatting with ruff
46
+ run: uvx ruff format --check .
47
+ - name: Lint with ruff
48
+ run: uvx ruff check . --output-format=github
49
+ - name: Install dependencies
50
+ run: |
51
+ uv sync --python ${{ matrix.python-version }} --group dev
52
+ - name: Run pip-audit
53
+ run: uv run pip-audit
54
+ - name: Run pip-licenses check
55
+ run: |
56
+ LICENSES="MIT;MIT License;BSD License;BSD-2-Clause;BSD-3-Clause;\
57
+ Apache Software License;Apache-2.0;Apache 2.0;ISC License (ISCL);\
58
+ Python Software Foundation License;PSF-2.0;Unlicense;\
59
+ Mozilla Public License 2.0 (MPL 2.0);ISC"
60
+ uv run --no-dev pip-licenses \
61
+ --partial-match \
62
+ --allow-only "$LICENSES" \
63
+ --ignore-packages yera matplotlib-inline
64
+ - name: Run tests with pytest
65
+ run: |
66
+ uv run pytest tests/src --cov=./ --cov-report=xml
67
+ - name: Upload coverage to Codecov
68
+ uses: codecov/codecov-action@v4
69
+ with:
70
+ file: ./coverage.xml
71
+ flags: unittests
72
+ name: codecov-umbrella
73
+
74
+ release-build-and-test:
75
+ name: Build and test package
76
+ needs: setup
77
+ uses: ./.github/workflows/build-and-test-package.yml
78
+ with:
79
+ python-versions: ${{ needs.setup.outputs.matrix }}
80
+
81
+ deploy:
82
+ needs: test
83
+ runs-on: ubuntu-latest
84
+ timeout-minutes: 10
85
+ if: github.ref == 'refs/heads/main' && github.event_name == 'push'
86
+ steps:
87
+ # downloads repository's source code into the GitHub Actions runner
88
+ - uses: actions/checkout@v4
89
+ - name: Install uv
90
+ uses: astral-sh/setup-uv@v4
91
+ with:
92
+ version: "latest"
93
+ enable-cache: true
94
+ - name: Build Docker image
95
+ run: |
96
+ docker build -t python-app:${{ github.sha }} .
97
+ docker tag python-app:${{ github.sha }} python-app:latest
98
+ - name: Run application in Docker container
99
+ run: |
100
+ # Run the container in detached mode
101
+ docker run -d \
102
+ --name python-app-container \
103
+ -p 8000:8000 \
104
+ -e ENVIRONMENT=production \
105
+ -e LOG_LEVEL=info \
106
+ python-app:latest
107
+ - name: Wait for application to start
108
+ run: |
109
+ echo "Waiting for application to start..."
110
+ sleep 10
111
+
112
+ # Check if container is running
113
+ if docker ps | grep -q python-app-container; then
114
+ echo "✅ Container is running successfully!"
115
+ docker logs python-app-container
116
+ else
117
+ echo "❌ Container failed to start"
118
+ docker logs python-app-container
119
+ exit 1
120
+ fi
121
+ - name: Run integration tests against containerized app
122
+ run: |
123
+ # Test if the application is responding, for now just initiate a test against the health endpoint
124
+ echo "Running integration tests..."
125
+
126
+ # Test HTTP endpoints
127
+ if curl -f http://localhost:8000/health; then
128
+ echo "✅ Health check passed!"
129
+ else
130
+ echo "❌ Health check failed!"
131
+ docker logs python-app-container
132
+ exit 1
133
+ fi
134
+ - name: Security scan
135
+ run: |
136
+ # Install Trivy for container security scanning
137
+ sudo apt-get update
138
+ sudo apt-get install wget apt-transport-https gnupg lsb-release
139
+ wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
140
+ echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
141
+ sudo apt-get update
142
+ sudo apt-get install trivy
143
+
144
+ # Scan the Docker image for vulnerabilities
145
+ trivy image --severity HIGH,CRITICAL python-app:latest
146
+ - name: Run application tasks
147
+ run: |
148
+ # Run tests inside container (assuming your Dockerfile includes uv)
149
+ docker run --rm python-app:latest uv run pytest tests/
150
+ - name: Collect logs and artifacts
151
+ if: always()
152
+ run: |
153
+ # Save container logs
154
+ docker logs python-app-container > container.log 2>&1
155
+
156
+ # Copy files from container if needed
157
+ docker cp python-app-container:/app/logs ./logs/ || true
158
+ docker cp python-app-container:/app/reports ./reports/ || true
159
+ - name: Upload logs as artifacts
160
+ if: always()
161
+ uses: actions/upload-artifact@v4
162
+ with:
163
+ name: application-logs-${{ github.sha }}
164
+ path: |
165
+ container.log
166
+ logs/
167
+ reports/
168
+ retention-days: 7
169
+ - name: Cleanup
170
+ if: always()
171
+ run: |
172
+ # Stop and remove container
173
+ docker stop python-app-container || true
174
+ docker rm python-app-container || true
175
+
176
+ # Remove images to save space (optional)
177
+ # docker rmi python-app:${{ github.sha }} || true
178
+ # docker rmi python-app:latest || true
@@ -0,0 +1,64 @@
1
+ name: Deploy AKS Cluster
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - 'infra/azure/**'
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ id-token: write
13
+ contents: read
14
+
15
+ env:
16
+ TERRAFORM_VERSION: '1.9.0'
17
+ WORKING_DIR: './infra/azure'
18
+
19
+ jobs:
20
+ terraform:
21
+ name: Deploy AKS
22
+ runs-on: ubuntu-latest
23
+
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Azure Login (OIDC)
29
+ uses: azure/login@v2
30
+ with:
31
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
32
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
33
+ subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
34
+
35
+ - name: Setup Terraform
36
+ uses: hashicorp/setup-terraform@v3
37
+ with:
38
+ terraform_version: ${{ env.TERRAFORM_VERSION }}
39
+
40
+ - name: Terraform Init
41
+ working-directory: ${{ env.WORKING_DIR }}
42
+ run: terraform init
43
+
44
+ - name: Terraform Validate
45
+ working-directory: ${{ env.WORKING_DIR }}
46
+ run: terraform validate
47
+
48
+ - name: Terraform Plan
49
+ working-directory: ${{ env.WORKING_DIR }}
50
+ run: terraform plan -out=tfplan
51
+
52
+ - name: Terraform Apply
53
+ working-directory: ${{ env.WORKING_DIR }}
54
+ run: terraform apply -auto-approve tfplan
55
+
56
+ - name: Get Kubeconfig
57
+ run: |
58
+ az aks get-credentials \
59
+ --resource-group aks-devel-rg \
60
+ --name aks-devel \
61
+ --overwrite-existing
62
+
63
+ - name: Verify Cluster
64
+ run: kubectl get nodes
@@ -0,0 +1,86 @@
1
+ name: 'Terraform EKS Deployment'
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - 'infra/aws/**'
9
+ pull_request:
10
+ branches:
11
+ - main
12
+ paths:
13
+ - 'infra/aws/**'
14
+ workflow_dispatch:
15
+
16
+ env:
17
+ TF_VERSION: '1.5.0'
18
+ AWS_REGION: 'eu-west-2'
19
+
20
+ jobs:
21
+ terraform:
22
+ name: 'Terraform'
23
+ runs-on: ubuntu-latest
24
+ environment: production
25
+
26
+ # Use the Bash shell regardless of the GitHub Actions runner operating system
27
+ defaults:
28
+ run:
29
+ shell: bash
30
+ working-directory: ./infra/aws
31
+
32
+ steps:
33
+ # Checkout the repository to the GitHub Actions runner
34
+ - name: Checkout
35
+ uses: actions/checkout@v4
36
+
37
+ # Configure AWS credentials using GitHub secrets
38
+ - name: Configure AWS credentials
39
+ uses: aws-actions/configure-aws-credentials@v4
40
+ with:
41
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
42
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
43
+ aws-region: ${{ env.AWS_REGION }}
44
+
45
+ # Install the latest version of Terraform CLI
46
+ - name: Setup Terraform
47
+ uses: hashicorp/setup-terraform@v3
48
+ with:
49
+ terraform_version: ${{ env.TF_VERSION }}
50
+
51
+ # Initialize a new or existing Terraform working directory
52
+ - name: Terraform Init
53
+ run: terraform init
54
+
55
+ # Checks that all Terraform configuration files adhere to a canonical format
56
+ - name: Terraform Format
57
+ run: terraform fmt -check
58
+
59
+ # Import existing IAM roles if they exist
60
+ - name: Import Existing IAM Roles
61
+ continue-on-error: true
62
+ run: |
63
+ echo "🔄 Attempting to import existing IAM roles..."
64
+ terraform import aws_iam_role.eks_cluster devel-cluster-role || echo "eks_cluster role not found or already imported"
65
+ terraform import aws_iam_role.eks_nodes devel-nodes-role || echo "eks_nodes role not found or already imported"
66
+ echo "✅ Import attempt complete"
67
+
68
+ # Validates the configuration used in the GitHub action workflow
69
+ - name: Terraform Validate
70
+ run: terraform validate
71
+
72
+ # Generates an execution plan for Terraform
73
+ - name: Terraform Plan
74
+ run: terraform plan -no-color -input=false
75
+ continue-on-error: true
76
+
77
+ # Apply the configuration only on push to main branch or manual trigger
78
+ - name: Terraform Apply
79
+ if: (github.ref == 'refs/heads/main' && github.event_name == 'push') || github.event_name == 'workflow_dispatch'
80
+ run: terraform apply -auto-approve -input=false
81
+ # Output the kubeconfig command for easy access
82
+ - name: Output Kubeconfig Command
83
+ if: (github.ref == 'refs/heads/main' && github.event_name == 'push') || github.event_name == 'workflow_dispatch'
84
+ run: |
85
+ echo "To configure kubectl, run:"
86
+ terraform output -raw kubeconfig_command
@@ -0,0 +1,138 @@
1
+ name: 'Destroy AKS Infrastructure'
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ confirm_destroy:
7
+ description: 'Type "DESTROY" to confirm destruction'
8
+ required: true
9
+ type: string
10
+ cluster_name:
11
+ description: 'Cluster name to destroy (must match terraform variable)'
12
+ required: true
13
+ type: string
14
+ resource_group:
15
+ description: 'Resource group name (must match terraform variable)'
16
+ required: true
17
+ type: string
18
+
19
+ env:
20
+ TF_VERSION: '1.5.0'
21
+ ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
22
+ ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
23
+
24
+ jobs:
25
+ destroy:
26
+ name: 'Terraform Destroy'
27
+ runs-on: ubuntu-latest
28
+ environment: production
29
+
30
+ defaults:
31
+ run:
32
+ shell: bash
33
+ working-directory: infra/azure
34
+
35
+ steps:
36
+ - name: Checkout
37
+ uses: actions/checkout@v4
38
+
39
+ - name: Validate Destruction Confirmation
40
+ run: |
41
+ if [ "${{ github.event.inputs.confirm_destroy }}" != "DESTROY" ]; then
42
+ echo "❌ Destruction not confirmed. You must type 'DESTROY' exactly."
43
+ exit 1
44
+ fi
45
+ echo "✅ Destruction confirmed"
46
+
47
+ - name: Azure Login
48
+ uses: azure/login@v1
49
+ with:
50
+ creds: ${{ secrets.AZURE_CREDENTIALS }}
51
+
52
+ - name: Setup Terraform
53
+ uses: hashicorp/setup-terraform@v3
54
+ with:
55
+ terraform_version: ${{ env.TF_VERSION }}
56
+
57
+ - name: Terraform Init
58
+ run: terraform init
59
+ env:
60
+ ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
61
+ ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
62
+
63
+ - name: Verify Terraform Variables
64
+ run: |
65
+ echo "📝 Using existing terraform.tfvars:"
66
+ cat terraform.tfvars
67
+ echo ""
68
+ echo "🔍 Verifying cluster name and resource group match input:"
69
+ if grep -q "cluster_name.*=.*\"${{ github.event.inputs.cluster_name }}\"" terraform.tfvars; then
70
+ echo "✅ Cluster name matches terraform.tfvars"
71
+ else
72
+ echo "⚠️ Warning: Cluster name doesn't match terraform.tfvars"
73
+ fi
74
+ if grep -q "resource_group_name.*=.*\"${{ github.event.inputs.resource_group }}\"" terraform.tfvars; then
75
+ echo "✅ Resource group matches terraform.tfvars"
76
+ else
77
+ echo "⚠️ Warning: Resource group doesn't match terraform.tfvars"
78
+ fi
79
+
80
+ - name: Pre-cleanup Kubernetes Resources
81
+ continue-on-error: true
82
+ run: |
83
+ echo "🧹 Cleaning up Kubernetes resources..."
84
+
85
+ # Get AKS credentials
86
+ az aks get-credentials \
87
+ --resource-group ${{ github.event.inputs.resource_group }} \
88
+ --name ${{ github.event.inputs.cluster_name }} \
89
+ --overwrite-existing || {
90
+ echo "⚠️ Could not get AKS credentials. Cluster may not exist or is inaccessible."
91
+ exit 0
92
+ }
93
+
94
+ # Delete LoadBalancer services
95
+ echo "Deleting LoadBalancer services..."
96
+ kubectl get svc --all-namespaces -o json 2>/dev/null | \
97
+ jq -r '.items[] | select(.spec.type=="LoadBalancer") | "\(.metadata.namespace) \(.metadata.name)"' | \
98
+ while read namespace name; do
99
+ echo " Deleting: $namespace/$name"
100
+ kubectl delete svc "$name" -n "$namespace" --timeout=60s || true
101
+ done
102
+
103
+ # Delete PVCs
104
+ echo "Deleting PersistentVolumeClaims..."
105
+ kubectl delete pvc --all --all-namespaces --timeout=60s || true
106
+
107
+ echo "⏳ Waiting for Azure resources cleanup..."
108
+ sleep 30
109
+
110
+ - name: Terraform Plan Destroy
111
+ run: |
112
+ echo "📋 Resources that will be destroyed:"
113
+ terraform plan -destroy -no-color -input=false
114
+ env:
115
+ ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
116
+ ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
117
+
118
+ - name: Terraform Destroy
119
+ run: |
120
+ echo "🚨 Starting infrastructure destruction..."
121
+ terraform destroy -auto-approve -input=false
122
+ echo "✅ Infrastructure destroyed successfully"
123
+ env:
124
+ ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
125
+ ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
126
+
127
+ - name: Verify Cleanup
128
+ continue-on-error: true
129
+ run: |
130
+ echo "🔍 Verifying cleanup..."
131
+
132
+ echo "Checking for AKS clusters in resource group..."
133
+ az aks list --resource-group ${{ github.event.inputs.resource_group }} -o table || true
134
+
135
+ echo "Checking if resource group still exists..."
136
+ az group show --name ${{ github.event.inputs.resource_group }} -o table || echo "Resource group deleted"
137
+
138
+ echo "✅ Cleanup verification complete"