itop-ai-assistant 0.5.0__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 (250) hide show
  1. itop_ai_assistant-0.5.0/.dockerignore +185 -0
  2. itop_ai_assistant-0.5.0/.env.test.dist +17 -0
  3. itop_ai_assistant-0.5.0/.gitignore +256 -0
  4. itop_ai_assistant-0.5.0/.importlinter +145 -0
  5. itop_ai_assistant-0.5.0/.python-version +1 -0
  6. itop_ai_assistant-0.5.0/CLAUDE.md +25 -0
  7. itop_ai_assistant-0.5.0/Dockerfile +66 -0
  8. itop_ai_assistant-0.5.0/LICENSE +661 -0
  9. itop_ai_assistant-0.5.0/PKG-INFO +255 -0
  10. itop_ai_assistant-0.5.0/README.md +12 -0
  11. itop_ai_assistant-0.5.0/hatch_build.py +124 -0
  12. itop_ai_assistant-0.5.0/pyproject.toml +152 -0
  13. itop_ai_assistant-0.5.0/pytest.toml +13 -0
  14. itop_ai_assistant-0.5.0/ruff.toml +15 -0
  15. itop_ai_assistant-0.5.0/src/itop_ai_assistant/THIRD-PARTY-NOTICES.txt +72 -0
  16. itop_ai_assistant-0.5.0/src/itop_ai_assistant/__init__.py +0 -0
  17. itop_ai_assistant-0.5.0/src/itop_ai_assistant/_build_info.py +6 -0
  18. itop_ai_assistant-0.5.0/src/itop_ai_assistant/admin/__init__.py +0 -0
  19. itop_ai_assistant-0.5.0/src/itop_ai_assistant/admin/router.py +304 -0
  20. itop_ai_assistant-0.5.0/src/itop_ai_assistant/admin/setup.py +404 -0
  21. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/__init__.py +0 -0
  22. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/__init__.py +0 -0
  23. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/agent.py +191 -0
  24. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/catalog.py +24 -0
  25. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/compose.py +84 -0
  26. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/config.py +336 -0
  27. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/context.py +49 -0
  28. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/domain.py +190 -0
  29. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/cs.json +108 -0
  30. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/de.json +108 -0
  31. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/es.json +108 -0
  32. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/fr.json +108 -0
  33. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/it.json +108 -0
  34. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/kk.json +108 -0
  35. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/pl.json +108 -0
  36. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/ru.json +112 -0
  37. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/sk.json +108 -0
  38. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/uk.json +108 -0
  39. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/locales/zh.json +108 -0
  40. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/pipeline.py +61 -0
  41. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompt.py +173 -0
  42. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts/catalog_human.md +8 -0
  43. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts/system.md +24 -0
  44. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts/system_clarify.md +27 -0
  45. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts/system_classify.md +11 -0
  46. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts/system_handoff_note.md +5 -0
  47. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts/system_similar.md +13 -0
  48. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts/ticket_human.md +23 -0
  49. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/prompts.py +58 -0
  50. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/run.py +125 -0
  51. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/similar.py +42 -0
  52. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/state.py +50 -0
  53. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/intake/tools.py +382 -0
  54. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/__init__.py +0 -0
  55. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/config.py +45 -0
  56. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/cs.json +27 -0
  57. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/de.json +27 -0
  58. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/es.json +27 -0
  59. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/fr.json +27 -0
  60. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/it.json +27 -0
  61. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/kk.json +27 -0
  62. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/pl.json +27 -0
  63. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/ru.json +27 -0
  64. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/sk.json +27 -0
  65. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/uk.json +27 -0
  66. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/locales/zh.json +27 -0
  67. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/pipeline.py +112 -0
  68. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/prompts/greeting.md +12 -0
  69. itop_ai_assistant-0.5.0/src/itop_ai_assistant/agents/selfcheck/prompts.py +38 -0
  70. itop_ai_assistant-0.5.0/src/itop_ai_assistant/config.py +517 -0
  71. itop_ai_assistant-0.5.0/src/itop_ai_assistant/config.yaml +8 -0
  72. itop_ai_assistant-0.5.0/src/itop_ai_assistant/content_sources/__init__.py +8 -0
  73. itop_ai_assistant-0.5.0/src/itop_ai_assistant/content_sources/faq.py +154 -0
  74. itop_ai_assistant-0.5.0/src/itop_ai_assistant/content_sources/registry.py +88 -0
  75. itop_ai_assistant-0.5.0/src/itop_ai_assistant/content_sources/tickets.py +195 -0
  76. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/api_deps.py +145 -0
  77. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/background.py +52 -0
  78. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/deps.py +189 -0
  79. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/llm_counters.py +101 -0
  80. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/llm_providers.py +108 -0
  81. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/principal.py +58 -0
  82. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/tracing.py +63 -0
  83. itop_ai_assistant-0.5.0/src/itop_ai_assistant/core/tracing_otel.py +112 -0
  84. itop_ai_assistant-0.5.0/src/itop_ai_assistant/domain/__init__.py +0 -0
  85. itop_ai_assistant-0.5.0/src/itop_ai_assistant/domain/catalog.py +27 -0
  86. itop_ai_assistant-0.5.0/src/itop_ai_assistant/domain/faq.py +34 -0
  87. itop_ai_assistant-0.5.0/src/itop_ai_assistant/domain/identity.py +38 -0
  88. itop_ai_assistant-0.5.0/src/itop_ai_assistant/domain/ticket.py +44 -0
  89. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop/connection.py +110 -0
  90. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop/provisioning.py +221 -0
  91. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop/write_policy.py +40 -0
  92. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop_client/__init__.py +12 -0
  93. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop_client/auth.py +26 -0
  94. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop_client/datamodel.py +93 -0
  95. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop_client/exceptions.py +20 -0
  96. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop_client/itop.py +209 -0
  97. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop_client/parallel.py +18 -0
  98. itop_ai_assistant-0.5.0/src/itop_ai_assistant/itop_client/schema.py +300 -0
  99. itop_ai_assistant-0.5.0/src/itop_ai_assistant/main.py +170 -0
  100. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/__init__.py +0 -0
  101. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/agent_run.py +160 -0
  102. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/context.py +51 -0
  103. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/models.py +25 -0
  104. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/ports.py +181 -0
  105. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/registry.py +229 -0
  106. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/runner.py +106 -0
  107. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/scheduler.py +117 -0
  108. itop_ai_assistant-0.5.0/src/itop_ai_assistant/pipelines/shell.py +137 -0
  109. itop_ai_assistant-0.5.0/src/itop_ai_assistant/repositories/access.py +43 -0
  110. itop_ai_assistant-0.5.0/src/itop_ai_assistant/repositories/catalog.py +56 -0
  111. itop_ai_assistant-0.5.0/src/itop_ai_assistant/repositories/faq.py +85 -0
  112. itop_ai_assistant-0.5.0/src/itop_ai_assistant/repositories/identity.py +35 -0
  113. itop_ai_assistant-0.5.0/src/itop_ai_assistant/repositories/sets.py +95 -0
  114. itop_ai_assistant-0.5.0/src/itop_ai_assistant/repositories/ticket.py +179 -0
  115. itop_ai_assistant-0.5.0/src/itop_ai_assistant/request/router.py +63 -0
  116. itop_ai_assistant-0.5.0/src/itop_ai_assistant/schedule/runner.py +78 -0
  117. itop_ai_assistant-0.5.0/src/itop_ai_assistant/settings/config_store.py +85 -0
  118. itop_ai_assistant-0.5.0/src/itop_ai_assistant/settings/module_locales.py +143 -0
  119. itop_ai_assistant-0.5.0/src/itop_ai_assistant/settings/prompt_store.py +174 -0
  120. itop_ai_assistant-0.5.0/src/itop_ai_assistant/settings/prompt_validation.py +65 -0
  121. itop_ai_assistant-0.5.0/src/itop_ai_assistant/settings/ui_hints.py +50 -0
  122. itop_ai_assistant-0.5.0/src/itop_ai_assistant/state/__init__.py +0 -0
  123. itop_ai_assistant-0.5.0/src/itop_ai_assistant/state/counters.py +159 -0
  124. itop_ai_assistant-0.5.0/src/itop_ai_assistant/state/install.py +210 -0
  125. itop_ai_assistant-0.5.0/src/itop_ai_assistant/state/journal.py +160 -0
  126. itop_ai_assistant-0.5.0/src/itop_ai_assistant/state/ticket_state.py +111 -0
  127. itop_ai_assistant-0.5.0/src/itop_ai_assistant/telemetry/__init__.py +0 -0
  128. itop_ai_assistant-0.5.0/src/itop_ai_assistant/telemetry/builder.py +127 -0
  129. itop_ai_assistant-0.5.0/src/itop_ai_assistant/telemetry/document.py +128 -0
  130. itop_ai_assistant-0.5.0/src/itop_ai_assistant/telemetry/normalize.py +115 -0
  131. itop_ai_assistant-0.5.0/src/itop_ai_assistant/telemetry/ports.py +32 -0
  132. itop_ai_assistant-0.5.0/src/itop_ai_assistant/telemetry/sender.py +165 -0
  133. itop_ai_assistant-0.5.0/src/itop_ai_assistant/telemetry/telemetrydeck.py +145 -0
  134. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/THIRD-PARTY-NOTICES.txt +791 -0
  135. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/cs-34Hs9WnS.js +1 -0
  136. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/de-CSTT7joJ.js +1 -0
  137. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/en-D_iKkHoV.js +1 -0
  138. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/es-CVSOA3yH.js +1 -0
  139. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/fr-CWyfKOu1.js +1 -0
  140. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/index-C95TKUGq.css +1 -0
  141. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/index-CRwjksIq.js +62 -0
  142. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/it-LPTgw0X1.js +1 -0
  143. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/kk-Br7yMjBK.js +1 -0
  144. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/pl-BChkt9W-.js +1 -0
  145. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/ru-Dt8oX5MF.js +1 -0
  146. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/sk-DTE4f2Yw.js +1 -0
  147. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/uk-37AEmiaq.js +1 -0
  148. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/assets/zh-BnK24CyI.js +1 -0
  149. itop_ai_assistant-0.5.0/src/itop_ai_assistant/ui_dist/index.html +13 -0
  150. itop_ai_assistant-0.5.0/src/itop_ai_assistant/util/build_info.py +80 -0
  151. itop_ai_assistant-0.5.0/src/itop_ai_assistant/util/redis_capped_index.py +34 -0
  152. itop_ai_assistant-0.5.0/src/itop_ai_assistant/util/redis_keyspace.py +93 -0
  153. itop_ai_assistant-0.5.0/src/itop_ai_assistant/util/text.py +113 -0
  154. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/__init__.py +74 -0
  155. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/adapters/embedder.py +75 -0
  156. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/adapters/qdrant_store.py +586 -0
  157. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/assembly.py +104 -0
  158. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/chunker.py +182 -0
  159. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/config.py +126 -0
  160. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/domain.py +171 -0
  161. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/ports/query.py +118 -0
  162. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/ports/source.py +197 -0
  163. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/ports/store.py +177 -0
  164. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/router.py +466 -0
  165. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/state/index_journal.py +90 -0
  166. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/state/sync_state.py +142 -0
  167. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/use_cases/indexer.py +507 -0
  168. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/use_cases/probe.py +24 -0
  169. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/use_cases/reindex.py +80 -0
  170. itop_ai_assistant-0.5.0/src/itop_ai_assistant/vector/use_cases/search.py +252 -0
  171. itop_ai_assistant-0.5.0/src/itop_ai_assistant/webhook/models.py +8 -0
  172. itop_ai_assistant-0.5.0/src/itop_ai_assistant/webhook/router.py +67 -0
  173. itop_ai_assistant-0.5.0/test/__init__.py +0 -0
  174. itop_ai_assistant-0.5.0/test/integration/__init__.py +0 -0
  175. itop_ai_assistant-0.5.0/test/integration/agents/__init__.py +0 -0
  176. itop_ai_assistant-0.5.0/test/integration/agents/intake/__init__.py +0 -0
  177. itop_ai_assistant-0.5.0/test/integration/agents/intake/conftest.py +182 -0
  178. itop_ai_assistant-0.5.0/test/integration/agents/intake/test_intake_agent_live.py +106 -0
  179. itop_ai_assistant-0.5.0/test/unit/__init__.py +0 -0
  180. itop_ai_assistant-0.5.0/test/unit/agents/__init__.py +0 -0
  181. itop_ai_assistant-0.5.0/test/unit/agents/intake/__init__.py +0 -0
  182. itop_ai_assistant-0.5.0/test/unit/agents/intake/test_intake_agent.py +606 -0
  183. itop_ai_assistant-0.5.0/test/unit/agents/intake/test_intake_config.py +130 -0
  184. itop_ai_assistant-0.5.0/test/unit/agents/intake/test_intake_domain.py +248 -0
  185. itop_ai_assistant-0.5.0/test/unit/agents/intake/test_intake_pipeline.py +175 -0
  186. itop_ai_assistant-0.5.0/test/unit/agents/intake/test_intake_prompt.py +307 -0
  187. itop_ai_assistant-0.5.0/test/unit/agents/intake/test_intake_similar_query.py +78 -0
  188. itop_ai_assistant-0.5.0/test/unit/agents/intake/test_intake_tools.py +608 -0
  189. itop_ai_assistant-0.5.0/test/unit/agents/selfcheck/__init__.py +0 -0
  190. itop_ai_assistant-0.5.0/test/unit/agents/selfcheck/test_selfcheck.py +189 -0
  191. itop_ai_assistant-0.5.0/test/unit/conftest.py +44 -0
  192. itop_ai_assistant-0.5.0/test/unit/test_access_repository.py +48 -0
  193. itop_ai_assistant-0.5.0/test/unit/test_admin_api.py +472 -0
  194. itop_ai_assistant-0.5.0/test/unit/test_catalog_repository.py +87 -0
  195. itop_ai_assistant-0.5.0/test/unit/test_chunker.py +178 -0
  196. itop_ai_assistant-0.5.0/test/unit/test_config.py +305 -0
  197. itop_ai_assistant-0.5.0/test/unit/test_config_store.py +111 -0
  198. itop_ai_assistant-0.5.0/test/unit/test_content_sources_faq.py +192 -0
  199. itop_ai_assistant-0.5.0/test/unit/test_content_sources_registry.py +123 -0
  200. itop_ai_assistant-0.5.0/test/unit/test_content_sources_tickets.py +312 -0
  201. itop_ai_assistant-0.5.0/test/unit/test_daily_counters.py +111 -0
  202. itop_ai_assistant-0.5.0/test/unit/test_deps.py +105 -0
  203. itop_ai_assistant-0.5.0/test/unit/test_domain_identity.py +20 -0
  204. itop_ai_assistant-0.5.0/test/unit/test_dry_run.py +178 -0
  205. itop_ai_assistant-0.5.0/test/unit/test_embedder.py +125 -0
  206. itop_ai_assistant-0.5.0/test/unit/test_engineer_scoped_search.py +109 -0
  207. itop_ai_assistant-0.5.0/test/unit/test_faq_repository.py +144 -0
  208. itop_ai_assistant-0.5.0/test/unit/test_identity_repository.py +34 -0
  209. itop_ai_assistant-0.5.0/test/unit/test_index_journal.py +63 -0
  210. itop_ai_assistant-0.5.0/test/unit/test_indexer.py +1026 -0
  211. itop_ai_assistant-0.5.0/test/unit/test_install_identity.py +143 -0
  212. itop_ai_assistant-0.5.0/test/unit/test_itop_connection.py +171 -0
  213. itop_ai_assistant-0.5.0/test/unit/test_itop_provisioning.py +179 -0
  214. itop_ai_assistant-0.5.0/test/unit/test_itop_repositories.py +127 -0
  215. itop_ai_assistant-0.5.0/test/unit/test_itop_schema.py +214 -0
  216. itop_ai_assistant-0.5.0/test/unit/test_journal.py +192 -0
  217. itop_ai_assistant-0.5.0/test/unit/test_llm_counters.py +90 -0
  218. itop_ai_assistant-0.5.0/test/unit/test_llm_providers.py +55 -0
  219. itop_ai_assistant-0.5.0/test/unit/test_module_locales.py +108 -0
  220. itop_ai_assistant-0.5.0/test/unit/test_package_layers.py +299 -0
  221. itop_ai_assistant-0.5.0/test/unit/test_pipelines_ports.py +90 -0
  222. itop_ai_assistant-0.5.0/test/unit/test_pipelines_registry.py +267 -0
  223. itop_ai_assistant-0.5.0/test/unit/test_pipelines_runner.py +142 -0
  224. itop_ai_assistant-0.5.0/test/unit/test_pipelines_shell.py +187 -0
  225. itop_ai_assistant-0.5.0/test/unit/test_principal.py +78 -0
  226. itop_ai_assistant-0.5.0/test/unit/test_prompt_store.py +250 -0
  227. itop_ai_assistant-0.5.0/test/unit/test_qdrant_smoke.py +75 -0
  228. itop_ai_assistant-0.5.0/test/unit/test_qdrant_store.py +828 -0
  229. itop_ai_assistant-0.5.0/test/unit/test_redis_capped_index.py +61 -0
  230. itop_ai_assistant-0.5.0/test/unit/test_request_api.py +186 -0
  231. itop_ai_assistant-0.5.0/test/unit/test_router.py +137 -0
  232. itop_ai_assistant-0.5.0/test/unit/test_schedule_runner.py +163 -0
  233. itop_ai_assistant-0.5.0/test/unit/test_scheduler.py +151 -0
  234. itop_ai_assistant-0.5.0/test/unit/test_search_query.py +68 -0
  235. itop_ai_assistant-0.5.0/test/unit/test_setup_api.py +715 -0
  236. itop_ai_assistant-0.5.0/test/unit/test_telemetry_document.py +205 -0
  237. itop_ai_assistant-0.5.0/test/unit/test_telemetry_normalization.py +128 -0
  238. itop_ai_assistant-0.5.0/test/unit/test_telemetry_sender.py +255 -0
  239. itop_ai_assistant-0.5.0/test/unit/test_telemetry_telemetrydeck.py +115 -0
  240. itop_ai_assistant-0.5.0/test/unit/test_text_utils.py +173 -0
  241. itop_ai_assistant-0.5.0/test/unit/test_ticket_repository.py +322 -0
  242. itop_ai_assistant-0.5.0/test/unit/test_ticket_state.py +189 -0
  243. itop_ai_assistant-0.5.0/test/unit/test_tracing.py +80 -0
  244. itop_ai_assistant-0.5.0/test/unit/test_vector_config.py +19 -0
  245. itop_ai_assistant-0.5.0/test/unit/test_vector_domain.py +62 -0
  246. itop_ai_assistant-0.5.0/test/unit/test_vector_search.py +469 -0
  247. itop_ai_assistant-0.5.0/test/unit/test_vector_status.py +789 -0
  248. itop_ai_assistant-0.5.0/test/unit/test_vector_store_protocol.py +29 -0
  249. itop_ai_assistant-0.5.0/test/unit/test_vector_sync_state.py +148 -0
  250. itop_ai_assistant-0.5.0/uv.lock +2317 -0
@@ -0,0 +1,185 @@
1
+ test
2
+ .pre-commit-config.yaml
3
+ README.md
4
+ pytest.toml
5
+ ruff.toml
6
+ *.iml
7
+
8
+ ### VirtualEnv template
9
+ # Virtualenv
10
+ # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
11
+ .Python
12
+ [Bb]in
13
+ [Ii]nclude
14
+ [Ll]ib
15
+ [Ll]ib64
16
+ [Ll]ocal
17
+ [Ss]cripts
18
+ pyvenv.cfg
19
+ .venv
20
+ pip-selfcheck.json
21
+
22
+ ### Python template
23
+ # Byte-compiled / optimized / DLL files
24
+ __pycache__/
25
+ *.py[cod]
26
+ *$py.class
27
+
28
+ # C extensions
29
+ *.so
30
+
31
+ # Distribution / packaging
32
+ .Python
33
+ build/
34
+ develop-eggs/
35
+ dist/
36
+ downloads/
37
+ eggs/
38
+ .eggs/
39
+ lib/
40
+ lib64/
41
+ parts/
42
+ sdist/
43
+ var/
44
+ wheels/
45
+ share/python-wheels/
46
+ *.egg-info/
47
+ .installed.cfg
48
+ *.egg
49
+ MANIFEST
50
+
51
+ # PyInstaller
52
+ # Usually these files are written by a python script from a template
53
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
54
+ *.manifest
55
+ *.spec
56
+
57
+ # Installer logs
58
+ pip-log.txt
59
+ pip-delete-this-directory.txt
60
+
61
+ # Unit test / coverage reports
62
+ htmlcov/
63
+ .tox/
64
+ .nox/
65
+ .coverage
66
+ .coverage.*
67
+ .cache
68
+ nosetests.xml
69
+ coverage.xml
70
+ *.cover
71
+ *.py,cover
72
+ .hypothesis/
73
+ .pytest_cache/
74
+ cover/
75
+
76
+ # Translations
77
+ *.mo
78
+ *.pot
79
+
80
+ # Django stuff:
81
+ *.log
82
+ local_settings.py
83
+ db.sqlite3
84
+ db.sqlite3-journal
85
+
86
+ # Flask stuff:
87
+ instance/
88
+ .webassets-cache
89
+
90
+ # Scrapy stuff:
91
+ .scrapy
92
+
93
+ # Sphinx documentation
94
+ docs/_build/
95
+
96
+ # PyBuilder
97
+ .pybuilder/
98
+ target/
99
+
100
+ # Jupyter Notebook
101
+ .ipynb_checkpoints
102
+
103
+ # IPython
104
+ profile_default/
105
+ ipython_config.py
106
+
107
+ # pyenv
108
+ # For a library or package, you might want to ignore these files since the code is
109
+ # intended to run in multiple environments; otherwise, check them in:
110
+ # .python-version
111
+
112
+ # pipenv
113
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
114
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
115
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
116
+ # install all needed dependencies.
117
+ #Pipfile.lock
118
+
119
+ # poetry
120
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
121
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
122
+ # commonly ignored for libraries.
123
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
124
+ #poetry.lock
125
+
126
+ # pdm
127
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
128
+ #pdm.lock
129
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
130
+ # in version control.
131
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
132
+ .pdm.toml
133
+ .pdm-python
134
+ .pdm-build/
135
+
136
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
137
+ __pypackages__/
138
+
139
+ # Celery stuff
140
+ celerybeat-schedule
141
+ celerybeat.pid
142
+
143
+ # SageMath parsed files
144
+ *.sage.py
145
+
146
+ # Environments
147
+ .env
148
+ .venv
149
+ env/
150
+ venv/
151
+ ENV/
152
+ env.bak/
153
+ venv.bak/
154
+
155
+ # Spyder project settings
156
+ .spyderproject
157
+ .spyproject
158
+
159
+ # Rope project settings
160
+ .ropeproject
161
+
162
+ # mkdocs documentation
163
+ /site
164
+
165
+ # mypy
166
+ .mypy_cache/
167
+ .dmypy.json
168
+ dmypy.json
169
+
170
+ # Pyre type checker
171
+ .pyre/
172
+
173
+ # pytype static type analyzer
174
+ .pytype/
175
+
176
+ # Cython debug symbols
177
+ cython_debug/
178
+
179
+ # PyCharm
180
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
181
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
182
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
183
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
184
+ #.idea/
185
+
@@ -0,0 +1,17 @@
1
+ # Integration test environment — copy to .env.test and fill in real values.
2
+ # .env.test is gitignored.
3
+ #
4
+ # These settings override config.yaml for integration test runs.
5
+ # LLM must be reachable when running: uv run pytest test/integration/
6
+
7
+ # openai_compatible (default) | openai | google_genai | ollama
8
+ LLM_PROVIDER=openai_compatible
9
+ LLM_BASE_URL=http://localhost:1234/v1
10
+ LLM_MODEL=your-model-name
11
+ LLM_API_KEY=none
12
+ # Set true if the endpoint accepts a forced tool_choice (vLLM yes, DeepSeek no)
13
+ # LLM_SUPPORTS_FORCED_TOOL_CHOICE=true
14
+
15
+ # Dummy iTop credentials — real iTop is NOT used (mocked via httpx transport)
16
+ ITOP_USER=dummy
17
+ ITOP_PWD=dummy
@@ -0,0 +1,256 @@
1
+ .env
2
+ .env.*
3
+ !.env.example
4
+ !.env.test.dist
5
+ src/routes/VERSION
6
+
7
+ ### VisualStudioCode template
8
+ .vscode
9
+
10
+ # Local History for Visual Studio Code
11
+ .history/
12
+
13
+ # Built Visual Studio Code Extensions
14
+ *.vsix
15
+
16
+ ### Linux template
17
+ *~
18
+
19
+ # temporary files which can be created if a process still has a handle open of a deleted file
20
+ .fuse_hidden*
21
+
22
+ # KDE directory preferences
23
+ .directory
24
+
25
+ # Linux trash folder which might appear on any partition or disk
26
+ .Trash-*
27
+
28
+ # .nfs files are created when an open file is removed but is still being accessed
29
+ .nfs*
30
+
31
+ ### Windows template
32
+ # Windows thumbnail cache files
33
+ Thumbs.db
34
+ Thumbs.db:encryptable
35
+ ehthumbs.db
36
+ ehthumbs_vista.db
37
+
38
+ # Dump file
39
+ *.stackdump
40
+
41
+ # Folder config file
42
+ [Dd]esktop.ini
43
+
44
+ # Recycle Bin used on file shares
45
+ $RECYCLE.BIN/
46
+
47
+ # Windows Installer files
48
+ *.cab
49
+ *.msi
50
+ *.msix
51
+ *.msm
52
+ *.msp
53
+
54
+ # Windows shortcuts
55
+ *.lnk
56
+
57
+ ### macOS template
58
+ # General
59
+ .DS_Store
60
+ .AppleDouble
61
+ .LSOverride
62
+
63
+ # Icon must end with two \r
64
+ Icon
65
+
66
+ # Thumbnails
67
+ ._*
68
+
69
+ # Files that might appear in the root of a volume
70
+ .DocumentRevisions-V100
71
+ .fseventsd
72
+ .Spotlight-V100
73
+ .TemporaryItems
74
+ .Trashes
75
+ .VolumeIcon.icns
76
+ .com.apple.timemachine.donotpresent
77
+
78
+ # Directories potentially created on remote AFP share
79
+ .AppleDB
80
+ .AppleDesktop
81
+ Network Trash Folder
82
+ Temporary Items
83
+ .apdisk
84
+
85
+ ### Python template
86
+ # Byte-compiled / optimized / DLL files
87
+ __pycache__/
88
+ *.py[cod]
89
+ *$py.class
90
+
91
+ # C extensions
92
+ *.so
93
+
94
+ # Distribution / packaging
95
+ .Python
96
+ build/
97
+ develop-eggs/
98
+ dist/
99
+ downloads/
100
+ eggs/
101
+ .eggs/
102
+ lib/
103
+ lib64/
104
+ parts/
105
+ sdist/
106
+ var/
107
+ wheels/
108
+ share/python-wheels/
109
+ *.egg-info/
110
+ .installed.cfg
111
+ *.egg
112
+ MANIFEST
113
+
114
+ # PyInstaller
115
+ # Usually these files are written by a python script from a template
116
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
117
+ *.manifest
118
+ *.spec
119
+
120
+ # Installer logs
121
+ pip-log.txt
122
+ pip-delete-this-directory.txt
123
+
124
+ # Unit test / coverage reports
125
+ htmlcov/
126
+ .tox/
127
+ .nox/
128
+ .coverage
129
+ .coverage.*
130
+ .cache
131
+ nosetests.xml
132
+ coverage.xml
133
+ *.cover
134
+ *.py,cover
135
+ .hypothesis/
136
+ .pytest_cache/
137
+ cover/
138
+ report.xml
139
+
140
+ # Translations
141
+ *.mo
142
+ *.pot
143
+
144
+ # Django stuff:
145
+ *.log
146
+ local_settings.py
147
+ db.sqlite3
148
+ db.sqlite3-journal
149
+
150
+ # Flask stuff:
151
+ instance/
152
+ .webassets-cache
153
+
154
+ # Scrapy stuff:
155
+ .scrapy
156
+
157
+ # Sphinx documentation
158
+ docs/_build/
159
+
160
+ # PyBuilder
161
+ .pybuilder/
162
+ target/
163
+
164
+ # Jupyter Notebook
165
+ .ipynb_checkpoints
166
+
167
+ # IPython
168
+ profile_default/
169
+ ipython_config.py
170
+
171
+ # pyenv
172
+ # For a library or package, you might want to ignore these files since the code is
173
+ # intended to run in multiple environments; otherwise, check them in:
174
+ # .python-version
175
+
176
+ # pipenv
177
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
178
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
179
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
180
+ # install all needed dependencies.
181
+ #Pipfile.lock
182
+
183
+ # poetry
184
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
185
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
186
+ # commonly ignored for libraries.
187
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
188
+ #poetry.lock
189
+
190
+ # pdm
191
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
192
+ #pdm.lock
193
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
194
+ # in version control.
195
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
196
+ .pdm.toml
197
+ .pdm-python
198
+ .pdm-build/
199
+
200
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
201
+ __pypackages__/
202
+
203
+ # Celery stuff
204
+ celerybeat-schedule
205
+ celerybeat.pid
206
+
207
+ # SageMath parsed files
208
+ *.sage.py
209
+
210
+ # Environments
211
+ .env
212
+ .venv
213
+ env/
214
+ venv/
215
+ ENV/
216
+ env.bak/
217
+ venv.bak/
218
+
219
+ # Spyder project settings
220
+ .spyderproject
221
+ .spyproject
222
+
223
+ # Rope project settings
224
+ .ropeproject
225
+
226
+ # mkdocs documentation
227
+ /site
228
+
229
+ # mypy
230
+ .mypy_cache/
231
+ .dmypy.json
232
+ dmypy.json
233
+
234
+ # Pyre type checker
235
+ .pyre/
236
+
237
+ # pytype static type analyzer
238
+ .pytype/
239
+
240
+ # Cython debug symbols
241
+ cython_debug/
242
+
243
+ # PyCharm
244
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
245
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
246
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
247
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
248
+ .idea/
249
+ *.iml
250
+ # Generated at build time by hatch_build.py
251
+ src/itop_ai_assistant/_build_info.py
252
+
253
+ # Built by `npm run build` in ui/ — see ui/vite.config.ts
254
+ src/itop_ai_assistant/ui_dist/
255
+
256
+ .import_linter_cache/
@@ -0,0 +1,145 @@
1
+ ; Module-boundary invariants expressible as a plain import graph — see
2
+ ; test/unit/test_package_layers.py for the invariants an import graph has no
3
+ ; vocabulary for (declared names, class shapes, signatures, file layout),
4
+ ; which stay hand-written there.
5
+ ; grimp only walks into subpackages that have an `__init__.py`; most of ours
6
+ ; are plain PEP 420 namespace packages, so each is listed as its own root too
7
+ ; or its modules would be invisible to every contract below.
8
+ [importlinter]
9
+ root_packages =
10
+ itop_ai_assistant
11
+ itop_ai_assistant.core
12
+ itop_ai_assistant.itop
13
+ itop_ai_assistant.repositories
14
+ itop_ai_assistant.request
15
+ itop_ai_assistant.schedule
16
+ itop_ai_assistant.settings
17
+ itop_ai_assistant.util
18
+ itop_ai_assistant.webhook
19
+ itop_ai_assistant.vector.adapters
20
+ itop_ai_assistant.vector.ports
21
+ itop_ai_assistant.vector.state
22
+ itop_ai_assistant.vector.use_cases
23
+
24
+ ; `.claude/rules/itop.md`: nothing outside the repositories touches iTop.
25
+ ; `core/principal.py` is not an exception to the rule but to its wording: it
26
+ ; names `ItopAuth` as the type of a principal's credentials, and never calls
27
+ ; iTop.
28
+ [importlinter:contract:itop-boundary]
29
+ name = Only itop/, repositories/ and core/principal.py import the vendored client
30
+ type = forbidden
31
+ ; Direct imports only, matching the AST check this replaced — a module
32
+ ; reaching itop_client through another module's re-export is that module's
33
+ ; boundary to answer for, not this one's.
34
+ allow_indirect_imports = true
35
+ source_modules =
36
+ itop_ai_assistant.admin
37
+ itop_ai_assistant.agents
38
+ itop_ai_assistant.config
39
+ itop_ai_assistant.content_sources
40
+ itop_ai_assistant.core
41
+ itop_ai_assistant.domain
42
+ itop_ai_assistant.main
43
+ itop_ai_assistant.pipelines
44
+ itop_ai_assistant.request
45
+ itop_ai_assistant.schedule
46
+ itop_ai_assistant.settings
47
+ itop_ai_assistant.state
48
+ itop_ai_assistant.telemetry
49
+ itop_ai_assistant.util
50
+ itop_ai_assistant.vector
51
+ itop_ai_assistant.webhook
52
+ forbidden_modules =
53
+ itop_ai_assistant.itop_client
54
+ ignore_imports =
55
+ itop_ai_assistant.core.principal -> itop_ai_assistant.itop_client
56
+
57
+ ; `ports/` and `state/` are the bottom of vector/'s own dependency graph.
58
+ ; `adapters/`, `use_cases/` and `router.py` are ordered as they already are
59
+ ; in practice (use_cases depends on adapters, router depends on use_cases).
60
+ [importlinter:contract:vector-layers]
61
+ name = vector/: ports and state sit below adapters, use_cases and router
62
+ type = layers
63
+ layers =
64
+ router
65
+ use_cases
66
+ adapters
67
+ ports | state
68
+ containers =
69
+ itop_ai_assistant.vector
70
+ ; reindex.py is the `itop-ai-reindex` CLI script (pyproject.toml
71
+ ; [project.scripts]) — it bootstraps the whole app through the composition
72
+ ; root and the pipeline registry, both of which loop back through the vector
73
+ ; facade into router. That is the composition root's business, not a
74
+ ; use_cases-reaches-upward violation.
75
+ ignore_imports =
76
+ itop_ai_assistant.vector.use_cases.reindex -> itop_ai_assistant.core.deps
77
+ itop_ai_assistant.vector.use_cases.reindex -> itop_ai_assistant.pipelines.registry
78
+
79
+ ; Rule 3.4, TASK-040: a port must not import a settings section.
80
+ [importlinter:contract:source-port-sheds-config]
81
+ name = vector/ports/source.py does not import the settings section
82
+ type = forbidden
83
+ allow_indirect_imports = true
84
+ source_modules =
85
+ itop_ai_assistant.vector.ports.source
86
+ forbidden_modules =
87
+ itop_ai_assistant.vector.config
88
+
89
+ ; architecture/alignment-plan.md §5: content providers live outside vector/
90
+ ; entirely, so nothing under vector/ may import the ticket/FAQ domain models
91
+ ; or their repositories. router.py's import of repositories.sets is not
92
+ ; domain knowledge (ADR-022) and is deliberately not listed here.
93
+ [importlinter:contract:vector-does-not-know-content-domains]
94
+ name = vector/ does not know the ticket/FAQ content domains
95
+ type = forbidden
96
+ allow_indirect_imports = true
97
+ source_modules =
98
+ itop_ai_assistant.vector
99
+ forbidden_modules =
100
+ itop_ai_assistant.domain.ticket
101
+ itop_ai_assistant.domain.faq
102
+ itop_ai_assistant.repositories.ticket
103
+ itop_ai_assistant.repositories.faq
104
+
105
+ ; Rule 6.10, TASK-044: agents/ is business logic, webhook/ is one entry
106
+ ; point's transport shape.
107
+ [importlinter:contract:agents-do-not-import-webhook]
108
+ name = agents/ does not import the webhook transport
109
+ type = forbidden
110
+ allow_indirect_imports = true
111
+ source_modules =
112
+ itop_ai_assistant.agents
113
+ forbidden_modules =
114
+ itop_ai_assistant.webhook
115
+
116
+ ; Rule 1.3/5.1, TASK-045: a module reaches the LLM factory through
117
+ ; `RunDeps.create_llm`, not by importing the composition root that assembles
118
+ ; `AppDeps` and holds the Redis/Qdrant wiring.
119
+ [importlinter:contract:agents-do-not-import-core-deps]
120
+ name = agents/ does not import the composition root
121
+ type = forbidden
122
+ allow_indirect_imports = true
123
+ source_modules =
124
+ itop_ai_assistant.agents
125
+ forbidden_modules =
126
+ itop_ai_assistant.core.deps
127
+
128
+ ; The mirror image of vector-does-not-know-content-domains above — that one
129
+ ; keeps the domain out of vector/ entirely, this one keeps search.py,
130
+ ; indexer.py and router.py from building the source *list* themselves via the
131
+ ; door content_sources.registry leaves open: vector/assembly.py is the one
132
+ ; caller of build_vector_sources() in the process (TASK-037). Whole-module,
133
+ ; not just the one name — stronger than the invariant this replaces, since
134
+ ; none of the three currently has any other reason to import that module
135
+ ; either.
136
+ [importlinter:contract:vector-sources-are-injected-not-built]
137
+ name = search.py, indexer.py and router.py do not build the source list themselves
138
+ type = forbidden
139
+ allow_indirect_imports = true
140
+ source_modules =
141
+ itop_ai_assistant.vector.use_cases.search
142
+ itop_ai_assistant.vector.use_cases.indexer
143
+ itop_ai_assistant.vector.router
144
+ forbidden_modules =
145
+ itop_ai_assistant.content_sources.registry
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,25 @@
1
+ # Development Commands
2
+
3
+ All commands run from `assistant/` unless noted.
4
+
5
+ ```bash
6
+ uv sync # deps (--no-dev for production)
7
+ uv run uvicorn itop_ai_assistant.main:app --host 0.0.0.0 --port 8001 --reload
8
+ uv run pytest # unit tests (the default suite)
9
+ uv run pytest -k "test_name" # one test
10
+ uv run ruff check . && uv run ruff format .
11
+ cd ../docker && docker-compose up -d # full stack: iTop + assistant + Redis + Qdrant
12
+ ```
13
+
14
+ **Before pushing**, run what CI runs: `uv run pre-commit run --all-files` and
15
+ `uv run pytest`. Note that `pre-commit run mypy --all-files` is the **strict**
16
+ type gate — `uv run mypy src/` is not the same check and passing it proves
17
+ less. CI (`.github/workflows/ci.yml`) runs on every push to `main` and every PR
18
+ and gates the image publish; it adds `npm run build` for the UI.
19
+ `test/integration` needs a real model endpoint and is excluded there.
20
+
21
+ **Live verification on the stand** (`docker-compose up`, manual checks against
22
+ the running stack) happens only after the user confirms — don't start the
23
+ stack or poke it unprompted, even to "just double-check" a change. Unit tests
24
+ and `pre-commit` are enough to report work as done; note in the summary that
25
+ live verification is still pending.
@@ -0,0 +1,66 @@
1
+ # Build context is the repository root (ui/ and assistant/ are siblings):
2
+ # docker build -f assistant/Dockerfile .
3
+
4
+ FROM node:22-alpine AS ui-builder
5
+
6
+ WORKDIR /ui
7
+
8
+ # Install dependencies first — this layer is cached unless the lockfile changes
9
+ COPY ui/package.json ui/package-lock.json ./
10
+ RUN npm ci
11
+
12
+ COPY ui/ ./
13
+ RUN npm run build
14
+
15
+ # ---- python dependencies + the project itself ----
16
+ FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder
17
+
18
+ WORKDIR /app
19
+
20
+ # Install dependencies into a separate venv — this layer is cached unless lockfile changes.
21
+ # `--extra tracing` even though tracing is off by default (TRACING_ENABLED): an
22
+ # image without the packages could not be told to trace at all, and a
23
+ # deployment cannot pip-install into a published image. Cheap here — the extra
24
+ # is the OTel SDK, the HTTP exporter and the OpenInference conventions, no gRPC.
25
+ COPY assistant/pyproject.toml assistant/uv.lock ./
26
+ RUN uv sync --frozen --no-dev --extra tracing --no-install-project --no-editable
27
+
28
+ # The build stamp, baked into the package by hatch_build.py and readable at
29
+ # run time through importlib.metadata and _build_info.py. No git here: the
30
+ # tag is something CI already knows, so it is handed over rather than
31
+ # rediscovered from history. Unset (a local build) yields the 0.0.0 fallback.
32
+ # BUILD_CHANNEL is what telemetry gates on: `release` only from the publish
33
+ # workflow, so an image built here by hand reports nothing.
34
+ ARG APP_VERSION=""
35
+ ARG BUILD_COMMIT=""
36
+ ARG BUILD_CHANNEL=""
37
+ ENV SETUPTOOLS_SCM_PRETEND_VERSION=${APP_VERSION} BUILD_COMMIT=${BUILD_COMMIT} BUILD_CHANNEL=${BUILD_CHANNEL}
38
+
39
+ # Install the application itself. --no-editable puts the package inside the
40
+ # venv, so the runtime image needs nothing but /app/.venv.
41
+ COPY assistant/ ./
42
+ # The SPA is part of the package (ADR-032) — `npm run build` writes it here in
43
+ # a checkout, and here is where the wheel picks it up. Copied after the source
44
+ # so a frontend change does not invalidate the layers above, and so the build
45
+ # fails (hatch_build.py) if the stage above produced nothing.
46
+ COPY --from=ui-builder /assistant/src/itop_ai_assistant/ui_dist ./src/itop_ai_assistant/ui_dist
47
+ RUN uv sync --frozen --no-dev --extra tracing --no-editable
48
+
49
+ # ---- runtime image ----
50
+ FROM python:3.13-slim-bookworm
51
+
52
+ LABEL org.opencontainers.image.title="iTop AI Assistant"
53
+ LABEL org.opencontainers.image.licenses="AGPL-3.0"
54
+
55
+ WORKDIR /app
56
+
57
+ # The venv already contains the application, its build stamp, default prompts,
58
+ # config.yaml and the admin SPA — no source, and no .git, reaches the runtime
59
+ # image
60
+ COPY --from=builder /app/.venv ./.venv
61
+
62
+ ENV PATH="/app/.venv/bin:$PATH"
63
+
64
+ EXPOSE 8000
65
+
66
+ CMD ["uvicorn", "itop_ai_assistant.main:app", "--host", "0.0.0.0", "--port", "8000"]