techai-webutils 0.1.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 (298) hide show
  1. techai_webutils-0.1.0/PKG-INFO +46 -0
  2. techai_webutils-0.1.0/pyproject.toml +164 -0
  3. techai_webutils-0.1.0/pyproject.toml.orig +235 -0
  4. techai_webutils-0.1.0/src/techai_webutils/__init__.py +5 -0
  5. techai_webutils-0.1.0/src/techai_webutils/clients/__init__.py +8 -0
  6. techai_webutils-0.1.0/src/techai_webutils/clients/cache/__init__.py +35 -0
  7. techai_webutils-0.1.0/src/techai_webutils/clients/cache/builder.py +87 -0
  8. techai_webutils-0.1.0/src/techai_webutils/clients/cache/decorators.py +283 -0
  9. techai_webutils-0.1.0/src/techai_webutils/clients/cache/envelope.py +51 -0
  10. techai_webutils-0.1.0/src/techai_webutils/clients/cache/local/__init__.py +5 -0
  11. techai_webutils-0.1.0/src/techai_webutils/clients/cache/local/cache.py +70 -0
  12. techai_webutils-0.1.0/src/techai_webutils/clients/cache/null/__init__.py +5 -0
  13. techai_webutils-0.1.0/src/techai_webutils/clients/cache/null/cache.py +27 -0
  14. techai_webutils-0.1.0/src/techai_webutils/clients/cache/redis/__init__.py +6 -0
  15. techai_webutils-0.1.0/src/techai_webutils/clients/cache/redis/cache.py +86 -0
  16. techai_webutils-0.1.0/src/techai_webutils/clients/cache/types.py +27 -0
  17. techai_webutils-0.1.0/src/techai_webutils/clients/chunking/__init__.py +13 -0
  18. techai_webutils-0.1.0/src/techai_webutils/clients/chunking/factory.py +47 -0
  19. techai_webutils-0.1.0/src/techai_webutils/clients/chunking/fixed/__init__.py +5 -0
  20. techai_webutils-0.1.0/src/techai_webutils/clients/chunking/fixed/chunker.py +71 -0
  21. techai_webutils-0.1.0/src/techai_webutils/clients/decorators/__init__.py +1 -0
  22. techai_webutils-0.1.0/src/techai_webutils/clients/decorators/event_stack.py +99 -0
  23. techai_webutils-0.1.0/src/techai_webutils/clients/decorators/job_stack.py +77 -0
  24. techai_webutils-0.1.0/src/techai_webutils/clients/decorators/proxy.py +453 -0
  25. techai_webutils-0.1.0/src/techai_webutils/clients/email/__init__.py +13 -0
  26. techai_webutils-0.1.0/src/techai_webutils/clients/email/builder.py +68 -0
  27. techai_webutils-0.1.0/src/techai_webutils/clients/email/noop/__init__.py +5 -0
  28. techai_webutils-0.1.0/src/techai_webutils/clients/email/noop/provider.py +15 -0
  29. techai_webutils-0.1.0/src/techai_webutils/clients/email/ses/__init__.py +5 -0
  30. techai_webutils-0.1.0/src/techai_webutils/clients/email/ses/provider.py +33 -0
  31. techai_webutils-0.1.0/src/techai_webutils/clients/email/smtp/__init__.py +5 -0
  32. techai_webutils-0.1.0/src/techai_webutils/clients/email/smtp/provider.py +27 -0
  33. techai_webutils-0.1.0/src/techai_webutils/clients/embedding/__init__.py +13 -0
  34. techai_webutils-0.1.0/src/techai_webutils/clients/embedding/builder.py +66 -0
  35. techai_webutils-0.1.0/src/techai_webutils/clients/embedding/ollama/__init__.py +5 -0
  36. techai_webutils-0.1.0/src/techai_webutils/clients/embedding/ollama/provider.py +67 -0
  37. techai_webutils-0.1.0/src/techai_webutils/clients/embedding/stub/__init__.py +5 -0
  38. techai_webutils-0.1.0/src/techai_webutils/clients/embedding/stub/provider.py +57 -0
  39. techai_webutils-0.1.0/src/techai_webutils/clients/jobs/__init__.py +26 -0
  40. techai_webutils-0.1.0/src/techai_webutils/clients/jobs/builder.py +26 -0
  41. techai_webutils-0.1.0/src/techai_webutils/clients/jobs/config.py +28 -0
  42. techai_webutils-0.1.0/src/techai_webutils/clients/jobs/memory/__init__.py +18 -0
  43. techai_webutils-0.1.0/src/techai_webutils/clients/jobs/memory/backend.py +92 -0
  44. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/__init__.py +6 -0
  45. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/bedrock/__init__.py +5 -0
  46. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/bedrock/ingestor.py +202 -0
  47. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/builder.py +53 -0
  48. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/decorators.py +259 -0
  49. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/mapping.py +66 -0
  50. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/noop/__init__.py +5 -0
  51. techai_webutils-0.1.0/src/techai_webutils/clients/kb_ingestion/noop/ingestor.py +62 -0
  52. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/__init__.py +38 -0
  53. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/builder.py +84 -0
  54. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/output/__init__.py +5 -0
  55. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/output/registry.py +40 -0
  56. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/roster/__init__.py +5 -0
  57. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/roster/registry.py +77 -0
  58. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/shared/__init__.py +5 -0
  59. techai_webutils-0.1.0/src/techai_webutils/clients/kb_registry/shared/registry.py +33 -0
  60. techai_webutils-0.1.0/src/techai_webutils/clients/llm/__init__.py +5 -0
  61. techai_webutils-0.1.0/src/techai_webutils/clients/llm/bedrock/__init__.py +5 -0
  62. techai_webutils-0.1.0/src/techai_webutils/clients/llm/bedrock/provider.py +221 -0
  63. techai_webutils-0.1.0/src/techai_webutils/clients/llm/builder.py +99 -0
  64. techai_webutils-0.1.0/src/techai_webutils/clients/llm/decorators.py +150 -0
  65. techai_webutils-0.1.0/src/techai_webutils/clients/llm/ollama/__init__.py +5 -0
  66. techai_webutils-0.1.0/src/techai_webutils/clients/llm/ollama/provider.py +142 -0
  67. techai_webutils-0.1.0/src/techai_webutils/clients/llm/stub/__init__.py +5 -0
  68. techai_webutils-0.1.0/src/techai_webutils/clients/llm/stub/provider.py +67 -0
  69. techai_webutils-0.1.0/src/techai_webutils/clients/lock/__init__.py +18 -0
  70. techai_webutils-0.1.0/src/techai_webutils/clients/lock/builder.py +80 -0
  71. techai_webutils-0.1.0/src/techai_webutils/clients/lock/memory/__init__.py +5 -0
  72. techai_webutils-0.1.0/src/techai_webutils/clients/lock/memory/lock.py +46 -0
  73. techai_webutils-0.1.0/src/techai_webutils/clients/lock/postgres/__init__.py +5 -0
  74. techai_webutils-0.1.0/src/techai_webutils/clients/lock/postgres/lock.py +178 -0
  75. techai_webutils-0.1.0/src/techai_webutils/clients/lock/runner.py +39 -0
  76. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/__init__.py +23 -0
  77. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/builder.py +64 -0
  78. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/config.py +45 -0
  79. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/memory/__init__.py +7 -0
  80. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/memory/broker.py +31 -0
  81. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/memory/publisher.py +40 -0
  82. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/memory/subscriber.py +71 -0
  83. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/sqs/__init__.py +11 -0
  84. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/sqs/sqs_publisher.py +91 -0
  85. techai_webutils-0.1.0/src/techai_webutils/clients/messaging/sqs/sqs_subscriber.py +110 -0
  86. techai_webutils-0.1.0/src/techai_webutils/clients/metadata/__init__.py +14 -0
  87. techai_webutils-0.1.0/src/techai_webutils/clients/metadata/factory.py +47 -0
  88. techai_webutils-0.1.0/src/techai_webutils/clients/metadata/langdetect/__init__.py +13 -0
  89. techai_webutils-0.1.0/src/techai_webutils/clients/metadata/langdetect/extractor.py +66 -0
  90. techai_webutils-0.1.0/src/techai_webutils/clients/parsing/__init__.py +14 -0
  91. techai_webutils-0.1.0/src/techai_webutils/clients/parsing/factory.py +57 -0
  92. techai_webutils-0.1.0/src/techai_webutils/clients/parsing/isolated/__init__.py +23 -0
  93. techai_webutils-0.1.0/src/techai_webutils/clients/parsing/isolated/detect.py +109 -0
  94. techai_webutils-0.1.0/src/techai_webutils/clients/parsing/isolated/isolated.py +264 -0
  95. techai_webutils-0.1.0/src/techai_webutils/clients/parsing/isolated/markitdown_parser.py +200 -0
  96. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/__init__.py +7 -0
  97. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/bedrock/__init__.py +5 -0
  98. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/bedrock/engine.py +218 -0
  99. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/builder.py +128 -0
  100. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/filtering.py +112 -0
  101. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/stub/__init__.py +5 -0
  102. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/stub/engine.py +57 -0
  103. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/vector/__init__.py +5 -0
  104. techai_webutils-0.1.0/src/techai_webutils/clients/retrieval/vector/engine.py +66 -0
  105. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/__init__.py +14 -0
  106. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/builder.py +42 -0
  107. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/__init__.py +5 -0
  108. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/client.py +51 -0
  109. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/errors.py +65 -0
  110. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/__init__.py +29 -0
  111. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/auth.py +90 -0
  112. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/builder.py +75 -0
  113. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/circuit_breaker.py +65 -0
  114. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/logging.py +57 -0
  115. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/metrics.py +42 -0
  116. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/retry.py +63 -0
  117. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/server_builder.py +493 -0
  118. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/timeout.py +56 -0
  119. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/tracing.py +41 -0
  120. techai_webutils-0.1.0/src/techai_webutils/clients/rpc/grpc/interceptors/tracing_server.py +122 -0
  121. techai_webutils-0.1.0/src/techai_webutils/clients/splitting/__init__.py +13 -0
  122. techai_webutils-0.1.0/src/techai_webutils/clients/splitting/factory.py +47 -0
  123. techai_webutils-0.1.0/src/techai_webutils/clients/splitting/kb_unit/__init__.py +5 -0
  124. techai_webutils-0.1.0/src/techai_webutils/clients/splitting/kb_unit/splitter.py +150 -0
  125. techai_webutils-0.1.0/src/techai_webutils/clients/storage/__init__.py +21 -0
  126. techai_webutils-0.1.0/src/techai_webutils/clients/storage/builder.py +51 -0
  127. techai_webutils-0.1.0/src/techai_webutils/clients/storage/config.py +42 -0
  128. techai_webutils-0.1.0/src/techai_webutils/clients/storage/memory/__init__.py +5 -0
  129. techai_webutils-0.1.0/src/techai_webutils/clients/storage/memory/client.py +88 -0
  130. techai_webutils-0.1.0/src/techai_webutils/clients/storage/s3/__init__.py +10 -0
  131. techai_webutils-0.1.0/src/techai_webutils/clients/storage/s3/s3_client.py +221 -0
  132. techai_webutils-0.1.0/src/techai_webutils/clients/transport/__init__.py +5 -0
  133. techai_webutils-0.1.0/src/techai_webutils/clients/transport/grpc/__init__.py +9 -0
  134. techai_webutils-0.1.0/src/techai_webutils/clients/transport/grpc/server.py +176 -0
  135. techai_webutils-0.1.0/src/techai_webutils/clients/vector/__init__.py +13 -0
  136. techai_webutils-0.1.0/src/techai_webutils/clients/vector/builder.py +63 -0
  137. techai_webutils-0.1.0/src/techai_webutils/clients/vector/composition.py +74 -0
  138. techai_webutils-0.1.0/src/techai_webutils/clients/vector/qdrant/__init__.py +5 -0
  139. techai_webutils-0.1.0/src/techai_webutils/clients/vector/qdrant/store.py +194 -0
  140. techai_webutils-0.1.0/src/techai_webutils/clients/vector/stub/__init__.py +5 -0
  141. techai_webutils-0.1.0/src/techai_webutils/clients/vector/stub/store.py +99 -0
  142. techai_webutils-0.1.0/src/techai_webutils/clients/vector_kb/__init__.py +15 -0
  143. techai_webutils-0.1.0/src/techai_webutils/clients/vector_kb/builder.py +59 -0
  144. techai_webutils-0.1.0/src/techai_webutils/clients/vector_kb/vector/__init__.py +5 -0
  145. techai_webutils-0.1.0/src/techai_webutils/clients/vector_kb/vector/knowledge_base.py +148 -0
  146. techai_webutils-0.1.0/src/techai_webutils/controllers/__init__.py +28 -0
  147. techai_webutils-0.1.0/src/techai_webutils/controllers/adapt.py +72 -0
  148. techai_webutils-0.1.0/src/techai_webutils/controllers/base.py +106 -0
  149. techai_webutils-0.1.0/src/techai_webutils/controllers/decorators.py +246 -0
  150. techai_webutils-0.1.0/src/techai_webutils/core/__init__.py +1 -0
  151. techai_webutils-0.1.0/src/techai_webutils/core/domain/__init__.py +20 -0
  152. techai_webutils-0.1.0/src/techai_webutils/core/domain/metadata.py +28 -0
  153. techai_webutils-0.1.0/src/techai_webutils/core/domain/parser.py +92 -0
  154. techai_webutils-0.1.0/src/techai_webutils/core/domain/splitter.py +39 -0
  155. techai_webutils-0.1.0/src/techai_webutils/core/domain_types/__init__.py +27 -0
  156. techai_webutils-0.1.0/src/techai_webutils/core/domain_types/types.py +152 -0
  157. techai_webutils-0.1.0/src/techai_webutils/core/errors/__init__.py +29 -0
  158. techai_webutils-0.1.0/src/techai_webutils/core/errors/errors.py +197 -0
  159. techai_webutils-0.1.0/src/techai_webutils/core/events/__init__.py +31 -0
  160. techai_webutils-0.1.0/src/techai_webutils/core/events/events.py +262 -0
  161. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/__init__.py +219 -0
  162. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/adaptive_throttler.py +31 -0
  163. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/auth.py +54 -0
  164. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/bulkhead.py +32 -0
  165. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/byte_cache.py +35 -0
  166. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/cache.py +54 -0
  167. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/chunker.py +21 -0
  168. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/circuit_breaker.py +41 -0
  169. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/config_loader.py +41 -0
  170. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/connection.py +57 -0
  171. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/crud_service.py +76 -0
  172. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/dedup.py +26 -0
  173. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/dlq.py +38 -0
  174. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/document.py +72 -0
  175. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/document_status.py +138 -0
  176. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/email.py +19 -0
  177. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/embedding.py +42 -0
  178. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/event_publisher.py +27 -0
  179. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/execution.py +290 -0
  180. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/hedger.py +29 -0
  181. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/ingestion_job_state.py +81 -0
  182. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/jobs.py +82 -0
  183. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/kb_ingestion.py +155 -0
  184. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/kb_registry.py +85 -0
  185. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/knowledge_base.py +83 -0
  186. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/leader.py +23 -0
  187. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/lifecycle.py +75 -0
  188. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/llm.py +76 -0
  189. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/lock.py +56 -0
  190. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/logger.py +47 -0
  191. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/messaging.py +69 -0
  192. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/metadata.py +22 -0
  193. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/metrics.py +79 -0
  194. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/op_service.py +25 -0
  195. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/parser.py +31 -0
  196. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/pipeline.py +50 -0
  197. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/query.py +122 -0
  198. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/rate_limiter.py +22 -0
  199. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/repository.py +85 -0
  200. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/retrier.py +25 -0
  201. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/retrieval.py +182 -0
  202. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/service.py +56 -0
  203. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/splitter.py +23 -0
  204. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/storage.py +90 -0
  205. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/store.py +56 -0
  206. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/tracer.py +53 -0
  207. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/vector_store.py +87 -0
  208. techai_webutils-0.1.0/src/techai_webutils/core/interfaces/workflow.py +51 -0
  209. techai_webutils-0.1.0/src/techai_webutils/execution/__init__.py +49 -0
  210. techai_webutils-0.1.0/src/techai_webutils/execution/engine/__init__.py +5 -0
  211. techai_webutils-0.1.0/src/techai_webutils/execution/engine/fan_out.py +111 -0
  212. techai_webutils-0.1.0/src/techai_webutils/execution/engine/run.py +61 -0
  213. techai_webutils-0.1.0/src/techai_webutils/execution/executor/__init__.py +36 -0
  214. techai_webutils-0.1.0/src/techai_webutils/execution/executor/asyncio_executor.py +37 -0
  215. techai_webutils-0.1.0/src/techai_webutils/execution/executor/factory.py +90 -0
  216. techai_webutils-0.1.0/src/techai_webutils/execution/executor/pooled.py +151 -0
  217. techai_webutils-0.1.0/src/techai_webutils/execution/executor/ray_executor.py +56 -0
  218. techai_webutils-0.1.0/src/techai_webutils/execution/executor/ray_runtime.py +43 -0
  219. techai_webutils-0.1.0/src/techai_webutils/execution/executor/real_ray_pool.py +114 -0
  220. techai_webutils-0.1.0/src/techai_webutils/execution/executor/real_ray_runtime.py +121 -0
  221. techai_webutils-0.1.0/src/techai_webutils/execution/executor/resilient_ray_runtime.py +93 -0
  222. techai_webutils-0.1.0/src/techai_webutils/execution/gate/__init__.py +19 -0
  223. techai_webutils-0.1.0/src/techai_webutils/execution/gate/gate.py +147 -0
  224. techai_webutils-0.1.0/src/techai_webutils/execution/job/__init__.py +5 -0
  225. techai_webutils-0.1.0/src/techai_webutils/execution/job/conditional.py +45 -0
  226. techai_webutils-0.1.0/src/techai_webutils/execution/job/decorators/__init__.py +5 -0
  227. techai_webutils-0.1.0/src/techai_webutils/execution/job/decorators/builder.py +199 -0
  228. techai_webutils-0.1.0/src/techai_webutils/execution/job/job.py +205 -0
  229. techai_webutils-0.1.0/src/techai_webutils/foundation/__init__.py +1 -0
  230. techai_webutils-0.1.0/src/techai_webutils/foundation/config/__init__.py +35 -0
  231. techai_webutils-0.1.0/src/techai_webutils/foundation/config/bridge.py +173 -0
  232. techai_webutils-0.1.0/src/techai_webutils/foundation/config/config_loader.py +84 -0
  233. techai_webutils-0.1.0/src/techai_webutils/foundation/config/loader.py +116 -0
  234. techai_webutils-0.1.0/src/techai_webutils/foundation/config/settings.py +145 -0
  235. techai_webutils-0.1.0/src/techai_webutils/foundation/decorator.py +331 -0
  236. techai_webutils-0.1.0/src/techai_webutils/foundation/errors/__init__.py +1 -0
  237. techai_webutils-0.1.0/src/techai_webutils/foundation/errors/errors.py +118 -0
  238. techai_webutils-0.1.0/src/techai_webutils/foundation/lifecycle.py +70 -0
  239. techai_webutils-0.1.0/src/techai_webutils/foundation/logger/__init__.py +31 -0
  240. techai_webutils-0.1.0/src/techai_webutils/foundation/logger/builder.py +74 -0
  241. techai_webutils-0.1.0/src/techai_webutils/foundation/logger/logger.py +263 -0
  242. techai_webutils-0.1.0/src/techai_webutils/foundation/logger/stdlib_logger.py +132 -0
  243. techai_webutils-0.1.0/src/techai_webutils/foundation/metrics/__init__.py +31 -0
  244. techai_webutils-0.1.0/src/techai_webutils/foundation/metrics/builder.py +71 -0
  245. techai_webutils-0.1.0/src/techai_webutils/foundation/metrics/execution_observer.py +89 -0
  246. techai_webutils-0.1.0/src/techai_webutils/foundation/metrics/metrics.py +264 -0
  247. techai_webutils-0.1.0/src/techai_webutils/foundation/metrics/null_metrics.py +63 -0
  248. techai_webutils-0.1.0/src/techai_webutils/foundation/middleware/__init__.py +19 -0
  249. techai_webutils-0.1.0/src/techai_webutils/foundation/middleware/chain.py +35 -0
  250. techai_webutils-0.1.0/src/techai_webutils/foundation/middleware/http_observability.py +209 -0
  251. techai_webutils-0.1.0/src/techai_webutils/foundation/middleware/request_id.py +61 -0
  252. techai_webutils-0.1.0/src/techai_webutils/foundation/observability.py +65 -0
  253. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/__init__.py +21 -0
  254. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/adaptive_throttler.py +86 -0
  255. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/async_circuit_breaker.py +94 -0
  256. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/async_retry.py +68 -0
  257. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/budget.py +59 -0
  258. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/bulkhead.py +197 -0
  259. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/circuit_breaker.py +127 -0
  260. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/classify.py +140 -0
  261. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/dedup.py +36 -0
  262. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/dlq.py +67 -0
  263. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/grpc_boundary.py +80 -0
  264. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/hedge.py +95 -0
  265. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/leader.py +17 -0
  266. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/per_key_rate_limiter.py +70 -0
  267. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/rate_limiter.py +64 -0
  268. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/retry.py +69 -0
  269. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/sqs_dlq.py +84 -0
  270. techai_webutils-0.1.0/src/techai_webutils/foundation/resilience/timeout.py +35 -0
  271. techai_webutils-0.1.0/src/techai_webutils/foundation/tracer/__init__.py +25 -0
  272. techai_webutils-0.1.0/src/techai_webutils/foundation/tracer/builder.py +81 -0
  273. techai_webutils-0.1.0/src/techai_webutils/foundation/tracer/null_tracer.py +41 -0
  274. techai_webutils-0.1.0/src/techai_webutils/foundation/tracer/tracer.py +153 -0
  275. techai_webutils-0.1.0/src/techai_webutils/pipelines/__init__.py +24 -0
  276. techai_webutils-0.1.0/src/techai_webutils/pipelines/base.py +80 -0
  277. techai_webutils-0.1.0/src/techai_webutils/pipelines/citations.py +45 -0
  278. techai_webutils-0.1.0/src/techai_webutils/pipelines/decorators.py +315 -0
  279. techai_webutils-0.1.0/src/techai_webutils/pipelines/generator.py +69 -0
  280. techai_webutils-0.1.0/src/techai_webutils/pipelines/rewriter.py +49 -0
  281. techai_webutils-0.1.0/src/techai_webutils/pipelines/title.py +52 -0
  282. techai_webutils-0.1.0/src/techai_webutils/py.typed +0 -0
  283. techai_webutils-0.1.0/src/techai_webutils/repos/__init__.py +21 -0
  284. techai_webutils-0.1.0/src/techai_webutils/repos/cursor.py +49 -0
  285. techai_webutils-0.1.0/src/techai_webutils/repos/decorators/__init__.py +5 -0
  286. techai_webutils-0.1.0/src/techai_webutils/repos/decorators/builder.py +525 -0
  287. techai_webutils-0.1.0/src/techai_webutils/repos/errors/__init__.py +5 -0
  288. techai_webutils-0.1.0/src/techai_webutils/repos/errors/mapper.py +68 -0
  289. techai_webutils-0.1.0/src/techai_webutils/repos/repository.py +54 -0
  290. techai_webutils-0.1.0/src/techai_webutils/services/__init__.py +12 -0
  291. techai_webutils-0.1.0/src/techai_webutils/services/base.py +9 -0
  292. techai_webutils-0.1.0/src/techai_webutils/services/crud_service.py +50 -0
  293. techai_webutils-0.1.0/src/techai_webutils/services/decorators/__init__.py +5 -0
  294. techai_webutils-0.1.0/src/techai_webutils/services/decorators/builder.py +316 -0
  295. techai_webutils-0.1.0/src/techai_webutils/services/op_builder.py +220 -0
  296. techai_webutils-0.1.0/src/techai_webutils/workflows/__init__.py +24 -0
  297. techai_webutils-0.1.0/src/techai_webutils/workflows/base.py +81 -0
  298. techai_webutils-0.1.0/src/techai_webutils/workflows/decorators.py +333 -0
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.3
2
+ Name: techai-webutils
3
+ Version: 0.1.0
4
+ Summary: techai-webutils
5
+ Author: Tech AI at Georgia Institute of Technology
6
+ License: MIT
7
+ Classifier: Operating System :: MacOS
8
+ Classifier: Operating System :: Microsoft :: Windows
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Requires-Dist: aiobotocore>=3.5.0
13
+ Requires-Dist: aiosmtplib>=3.0.0
14
+ Requires-Dist: fastapi>=0.136.0
15
+ Requires-Dist: grpcio>=1.80.0
16
+ Requires-Dist: grpcio-health-checking>=1.80.0
17
+ Requires-Dist: grpcio-reflection>=1.80.0
18
+ Requires-Dist: httpx>=0.28.1
19
+ Requires-Dist: opentelemetry-api>=1.41.0
20
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.41.0
21
+ Requires-Dist: opentelemetry-sdk>=1.41.0
22
+ Requires-Dist: prometheus-client>=0.25.0
23
+ Requires-Dist: pydantic>=2.13.3
24
+ Requires-Dist: pydantic-settings>=2.14.1
25
+ Requires-Dist: qdrant-client>=1.12.0
26
+ Requires-Dist: pyyaml>=6.0.3
27
+ Requires-Dist: redis>=7.4.0
28
+ Requires-Dist: structlog>=25.5.0
29
+ Requires-Dist: tenacity>=9.1.4
30
+ Requires-Dist: uvicorn>=0.48.0
31
+ Requires-Dist: protovalidate>=2.0.0,<3
32
+ Requires-Dist: langdetect>=1.0.9 ; extra == 'langdetect'
33
+ Requires-Dist: markitdown[docx,pdf,pptx,xls,xlsx]>=0.1.6 ; extra == 'parsing'
34
+ Requires-Dist: pymupdf>=1.28.0 ; extra == 'parsing'
35
+ Requires-Dist: asyncpg>=0.30.0 ; extra == 'postgres'
36
+ Requires-Dist: ray==2.56.1 ; extra == 'ray'
37
+ Requires-Python: >=3.12
38
+ Project-URL: Homepage, https://github.com/gt-tech-ai/knowledge-engine
39
+ Project-URL: Documentation, https://github.com/gt-tech-ai/knowledge-engine
40
+ Project-URL: Repository, https://github.com/gt-tech-ai/knowledge-engine
41
+ Provides-Extra: langdetect
42
+ Provides-Extra: parsing
43
+ Provides-Extra: postgres
44
+ Provides-Extra: ray
45
+ Description-Content-Type: text/markdown
46
+
@@ -0,0 +1,164 @@
1
+ [project]
2
+ name = "techai-webutils"
3
+ version = "0.1.0"
4
+ description = "techai-webutils"
5
+ requires-python = ">= 3.12"
6
+ dependencies = [
7
+ "aiobotocore>=3.5.0",
8
+ "aiosmtplib>=3.0.0",
9
+ "fastapi>=0.136.0",
10
+ "grpcio>=1.80.0",
11
+ "grpcio-health-checking>=1.80.0",
12
+ "grpcio-reflection>=1.80.0",
13
+ "httpx>=0.28.1",
14
+ "opentelemetry-api>=1.41.0",
15
+ "opentelemetry-exporter-otlp-proto-grpc>=1.41.0",
16
+ "opentelemetry-sdk>=1.41.0",
17
+ "prometheus-client>=0.25.0",
18
+ "pydantic>=2.13.3",
19
+ "pydantic-settings>=2.14.1",
20
+ "qdrant-client>=1.12.0",
21
+ "pyyaml>=6.0.3",
22
+ "redis>=7.4.0",
23
+ "structlog>=25.5.0",
24
+ "tenacity>=9.1.4",
25
+ "uvicorn>=0.48.0",
26
+ "protovalidate>=2.0.0,<3",
27
+ ]
28
+ classifiers = [
29
+ "Operating System :: MacOS",
30
+ "Operating System :: Microsoft :: Windows",
31
+ "Operating System :: POSIX :: Linux",
32
+ "Programming Language :: Python",
33
+ "Programming Language :: Python :: 3.12",
34
+ ]
35
+
36
+ [project.readme]
37
+ text = ""
38
+ content-type = "text/markdown"
39
+
40
+ [[project.authors]]
41
+ name = "Tech AI at Georgia Institute of Technology"
42
+
43
+ [project.optional-dependencies]
44
+ ray = ["ray==2.56.1"]
45
+ postgres = ["asyncpg>=0.30.0"]
46
+ parsing = [
47
+ "markitdown[docx,pdf,pptx,xls,xlsx]>=0.1.6",
48
+ "pymupdf>=1.28.0",
49
+ ]
50
+ langdetect = ["langdetect>=1.0.9"]
51
+
52
+ [project.license]
53
+ text = "MIT"
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/gt-tech-ai/knowledge-engine"
57
+ Documentation = "https://github.com/gt-tech-ai/knowledge-engine"
58
+ Repository = "https://github.com/gt-tech-ai/knowledge-engine"
59
+
60
+ [build-system]
61
+ requires = ["uv_build>=0.11.15,<0.12.0"]
62
+ build-backend = "uv_build"
63
+
64
+ [dependency-groups]
65
+ dev = [
66
+ "autogitsemver>=0.9.13",
67
+ "pytest>=9.0.3",
68
+ "pytest-asyncio>=1.0.0",
69
+ "pytest-cov>=7.1.0",
70
+ "ray==2.56.1",
71
+ "ruff>=0.15.13",
72
+ "basedpyright>=1.31",
73
+ "asyncpg>=0.30.0",
74
+ "markitdown[docx,pdf,pptx,xls,xlsx]>=0.1.6",
75
+ "pymupdf>=1.28.0",
76
+ "langdetect>=1.0.9",
77
+ "testcontainers[postgres,redis]>=4.14.2",
78
+ "ty>=0.0.38",
79
+ ]
80
+
81
+ [tool.pytest.ini_options]
82
+ addopts = "--verbose -vv --capture=no --strict-markers --cov=techai_webutils --cov-report html --cov-report term --cov-report xml:coverage.xml --cov-fail-under=90.0"
83
+ markers = [
84
+ "integration: real-dependency tests via testcontainers (Docker required); deselected in the unit run",
85
+ "slow: slow tests, deselected with --fast",
86
+ ]
87
+
88
+ [tool.coverage.run]
89
+ relative_files = true
90
+ data_file = "coverage_unit.dat"
91
+
92
+ [tool.coverage.report]
93
+ omit = [
94
+ "*/clients/transport/grpc/server.py",
95
+ "*/clients/rpc/grpc/interceptors/tracing.py",
96
+ "*/clients/rpc/grpc/interceptors/tracing_server.py",
97
+ "*/clients/messaging/sqs/sqs_publisher.py",
98
+ "*/clients/messaging/sqs/sqs_subscriber.py",
99
+ "*/foundation/resilience/sqs_dlq.py",
100
+ "*/clients/storage/s3/s3_client.py",
101
+ "*/clients/llm/bedrock/*.py",
102
+ "*/clients/retrieval/bedrock/*.py",
103
+ "*/clients/kb_ingestion/bedrock/*.py",
104
+ "*/clients/email/ses/provider.py",
105
+ "*/clients/email/smtp/provider.py",
106
+ "*/clients/cache/redis/cache.py",
107
+ "*/foundation/tracer/tracer.py",
108
+ "*/foundation/observability.py",
109
+ "*/execution/executor/real_ray_runtime.py",
110
+ ]
111
+
112
+ [tool.ruff]
113
+ line-length = 110
114
+
115
+ [tool.ruff.lint]
116
+ exclude = ["tests/**"]
117
+ select = ["ALL"]
118
+ ignore = [
119
+ "ANN002",
120
+ "ANN003",
121
+ "BLE001",
122
+ "COM812",
123
+ "CPY001",
124
+ "D105",
125
+ "D107",
126
+ "D202",
127
+ "D203",
128
+ "D213",
129
+ "E501",
130
+ "FIX002",
131
+ "I001",
132
+ "N802",
133
+ "N999",
134
+ "RSE102",
135
+ "S101",
136
+ "TC006",
137
+ "TD002",
138
+ "TD003",
139
+ "TRY002",
140
+ "TRY300",
141
+ "UP032",
142
+ ]
143
+
144
+ [tool.ruff.lint.per-file-ignores]
145
+ "src/techai_webutils/clients/llm/bedrock/*.py" = ["N803"]
146
+ "src/techai_webutils/clients/retrieval/bedrock/*.py" = ["N803"]
147
+ "src/techai_webutils/clients/kb_ingestion/bedrock/*.py" = ["N803"]
148
+
149
+ [tool.ruff.lint.mccabe]
150
+ max-complexity = 15
151
+
152
+ [tool.ruff.lint.pylint]
153
+ max-args = 10
154
+ max-branches = 20
155
+ max-returns = 20
156
+
157
+ [tool.pyright]
158
+ pythonVersion = "3.12"
159
+ typeCheckingMode = "standard"
160
+ include = ["src/techai_webutils"]
161
+ exclude = ["tests"]
162
+
163
+ [tool.uv.build-backend]
164
+ module-name = "techai_webutils"
@@ -0,0 +1,235 @@
1
+ [project]
2
+ name = "techai-webutils"
3
+ version = "0.1.0"
4
+ # ^^^^^
5
+ # Wheel names will be generated according to this value. Do not manually modify this value; instead
6
+ # update it according to committed changes by running this command from the root of the repository:
7
+ #
8
+ # uv run python -m AutoGitSemVer.scripts.UpdatePythonVersion ./pyproject.toml ./src
9
+
10
+ description = "techai-webutils"
11
+ readme = { text = "", content-type = "text/markdown" }
12
+ authors = [
13
+ { name = "Tech AI at Georgia Institute of Technology" }
14
+ ]
15
+ requires-python = ">= 3.12"
16
+ dependencies = [
17
+ "aiobotocore>=3.5.0",
18
+ # aiosmtplib: async SMTP send for the SMTP email backend (clients/email/smtp); lazy-imported by
19
+ # email_from_config only on the SMTP path. Peer of aiobotocore (the SES backend's transport).
20
+ "aiosmtplib>=3.0.0",
21
+ "fastapi>=0.136.0",
22
+ "grpcio>=1.80.0",
23
+ "grpcio-health-checking>=1.80.0",
24
+ "grpcio-reflection>=1.80.0",
25
+ "httpx>=0.28.1",
26
+ "opentelemetry-api>=1.41.0",
27
+ "opentelemetry-exporter-otlp-proto-grpc>=1.41.0",
28
+ "opentelemetry-sdk>=1.41.0",
29
+ "prometheus-client>=0.25.0",
30
+ "pydantic>=2.13.3",
31
+ "pydantic-settings>=2.14.1",
32
+ "qdrant-client>=1.12.0",
33
+ "pyyaml>=6.0.3",
34
+ "redis>=7.4.0",
35
+ "structlog>=25.5.0",
36
+ "tenacity>=9.1.4",
37
+ "uvicorn>=0.48.0",
38
+ "protovalidate>=2.0.0,<3",
39
+ ]
40
+ classifiers = [
41
+ "Operating System :: MacOS",
42
+ "Operating System :: Microsoft :: Windows",
43
+ "Operating System :: POSIX :: Linux",
44
+ "Programming Language :: Python",
45
+ "Programming Language :: Python :: 3.12",
46
+ ]
47
+
48
+ [project.optional-dependencies]
49
+ # Distributed execution backend (RayExecutor + RealRayRuntime). Optional and heavy:
50
+ # only the S3 bulk-ingestion job installs `techai-webutils[ray]`. The default
51
+ # asyncio path (AsyncioExecutor) never pulls Ray — the RayRuntime protocol and
52
+ # RayExecutor carry no `ray` import; only RealRayRuntime does, imported lazily by
53
+ # `executor_from_config` when `ingestion.executor.kind: ray`.
54
+ #
55
+ # ⚠ Ray requires the driver and the cluster to run the SAME version. Pinned EXACTLY to match the
56
+ # `ray-head` Compose image (rayproject/ray:2.56.1-py312), the KubeRay cluster, AND the Ray
57
+ # testcontainer in the integration tests — `ray://` rejects a version mismatch. Bump this pin, the
58
+ # dev-group `ray` pin below, and the compose/KubeRay image together when upgrading Ray.
59
+ ray = ["ray==2.56.1"]
60
+
61
+ # Cross-pod single-writer lock backend (PostgresAdvisoryLock). Optional: only the
62
+ # ingestion worker installs `techai-webutils[postgres]`. The default in-memory lock never pulls
63
+ # asyncpg — the `postgres` backend impl is imported lazily by `lock_from_config` when
64
+ # `ingestion.lock.kind: postgres`.
65
+ postgres = ["asyncpg>=0.30.0"]
66
+
67
+ # Document-parsing backend (the `isolated` parser: MarkItDown + pymupdf). Optional and heavy: only a
68
+ # parse-running deployable (the ingestion worker) installs `techai-webutils[parsing]`. The
69
+ # `clients/parsing` factory + interface never import these — the `isolated` backend imports them
70
+ # lazily inside its parse methods / the forkserver, so the default import graph never pulls them.
71
+ parsing = ["markitdown[docx,pdf,pptx,xls,xlsx]>=0.1.6", "pymupdf>=1.28.0"]
72
+
73
+ # Language-detection backend (the `langdetect` MetadataExtractor). Optional: only a
74
+ # metadata-extracting deployable installs `techai-webutils[langdetect]`. The `clients/metadata`
75
+ # factory never imports it — the `langdetect` backend subpackage is imported lazily by
76
+ # `metadata_extractor_from_config`, so the default import graph never pulls it.
77
+ langdetect = ["langdetect>=1.0.9"]
78
+
79
+ [project.license]
80
+ text = "MIT"
81
+
82
+ [project.urls]
83
+ Homepage = "https://github.com/gt-tech-ai/knowledge-engine"
84
+ Documentation = "https://github.com/gt-tech-ai/knowledge-engine"
85
+ Repository = "https://github.com/gt-tech-ai/knowledge-engine"
86
+
87
+ [build-system]
88
+ requires = ["uv_build>=0.11.15,<0.12.0"]
89
+ build-backend = "uv_build"
90
+
91
+ [dependency-groups]
92
+ dev = [
93
+ "autogitsemver>=0.9.13",
94
+ "pytest>=9.0.3",
95
+ "pytest-asyncio>=1.0.0",
96
+ "pytest-cov>=7.1.0",
97
+ # Installed in dev/CI so basedpyright can resolve RealRayRuntime's `import ray` and the real-Ray
98
+ # integration tests (@pytest.mark.integration) can run against a Ray testcontainer; production
99
+ # consumers pull it via the `ray` extra, not this group. Pinned EXACTLY to the same version as the
100
+ # `ray` extra + the ray-head image so the ray:// driver matches the cluster (see the extra above).
101
+ "ray==2.56.1",
102
+ "ruff>=0.15.13",
103
+ "basedpyright>=1.31",
104
+ # asyncpg in dev so basedpyright resolves `import asyncpg` in the postgres lock backend and the
105
+ # real-Postgres integration test can run; production consumers pull it via the `postgres` extra.
106
+ "asyncpg>=0.30.0",
107
+ # markitdown + pymupdf in dev so basedpyright resolves the `isolated` parser backend's lazy
108
+ # imports and its parity tests (real conversion + real subprocess isolation) run; production
109
+ # consumers pull them via the `parsing` extra.
110
+ "markitdown[docx,pdf,pptx,xls,xlsx]>=0.1.6",
111
+ "pymupdf>=1.28.0",
112
+ # langdetect in dev so basedpyright resolves the `langdetect` metadata backend and its parity
113
+ # tests run; production consumers pull it via the `langdetect` extra.
114
+ "langdetect>=1.0.9",
115
+ "testcontainers[postgres,redis]>=4.14.2",
116
+ "ty>=0.0.38",
117
+ ]
118
+
119
+ [tool.pytest.ini_options]
120
+ # tests/ is put on sys.path by pytest's default prepend import mode (there is no
121
+ # tests/__init__.py). Test doubles are built inline with unittest.mock in each
122
+ # test (spec-bound to the real core interfaces), so no shared test-double package
123
+ # and no pythonpath directive are needed.
124
+ # Phase 3: hand-written unit coverage is gated at >=90%. The earlier "91.6% vs
125
+ # 83.4%" pytest-vs-`python -m pytest` discrepancy did NOT reproduce (both paths
126
+ # measure identically) — it was a stale-`.coverage` artifact. The real driver of
127
+ # the sub-90 reading was the denominator: integration-only external wrappers (gRPC
128
+ # server factory + OTel tracing interceptors, SQS/S3/Redis clients, OTel tracer/
129
+ # observability). Those are carved out below (covered by the Phase-4 integration
130
+ # suite, the Python equivalent of Go's unit-only carve-outs); the genuinely
131
+ # unit-testable interceptor logic was tested instead of excluded.
132
+ addopts = "--verbose -vv --capture=no --strict-markers --cov=techai_webutils --cov-report html --cov-report term --cov-report xml:coverage.xml --cov-fail-under=90.0"
133
+ # Registered markers (enforced by --strict-markers, so a typo'd/unregistered marker
134
+ # now errors instead of silently passing). `integration` tests need a Docker daemon
135
+ # (testcontainers) and are deselected from the default unit run via `-m "not integration"`.
136
+ markers = [
137
+ "integration: real-dependency tests via testcontainers (Docker required); deselected in the unit run",
138
+ "slow: slow tests, deselected with --fast",
139
+ ]
140
+
141
+ [tool.coverage.run]
142
+ # relative_files + a distinct (non-hidden, so GitHub upload-artifact keeps it)
143
+ # data file let the combined coverage GATE merge this unit dataset with the
144
+ # integration dataset across separate CI jobs (see the `python-coverage-gate` job
145
+ # + .coveragerc.combined). `search test unit --python` writes coverage_unit.dat;
146
+ # the integration run writes coverage_integration.dat; the gate combines them.
147
+ relative_files = true
148
+ data_file = "coverage_unit.dat"
149
+
150
+ [tool.coverage.report]
151
+ # Excluded from the UNIT denominator (>=90% gate is over hand-written, unit-testable
152
+ # logic). Each entry is either test infrastructure or a thin external-dependency
153
+ # wrapper whose uncovered lines are the real network/SDK calls — exercised by the
154
+ # Phase-4 integration suite, not unit tests. Mirrors Go's unit-only carve-out set.
155
+ #
156
+ # This omit is at REPORT time (not [run]) so the unit run still MEASURES the
157
+ # wrappers — their partial unit coverage then lands in .coverage.unit and merges
158
+ # into the combined gate (.coveragerc.combined), which counts the wrappers.
159
+ omit = [
160
+ "*/clients/transport/grpc/server.py", # gRPC server factory (binds/serves) — integration
161
+ "*/clients/rpc/grpc/interceptors/tracing.py", # OTel client span wiring — integration/runtime
162
+ "*/clients/rpc/grpc/interceptors/tracing_server.py", # OTel server span wiring — integration/runtime
163
+ "*/clients/messaging/sqs/sqs_publisher.py", # boto3 SQS send — integration (ElasticMQ)
164
+ "*/clients/messaging/sqs/sqs_subscriber.py", # boto3 SQS receive loop — integration (ElasticMQ)
165
+ "*/foundation/resilience/sqs_dlq.py", # boto3 SQS DLQ send — integration (ElasticMQ)
166
+ "*/clients/storage/s3/s3_client.py", # boto3 S3 client — integration (MinIO)
167
+ "*/clients/llm/bedrock/*.py", # aiobotocore bedrock-runtime wrapper — integration/runtime
168
+ "*/clients/retrieval/bedrock/*.py", # aiobotocore bedrock-agent-runtime wrapper — integration/runtime
169
+ "*/clients/kb_ingestion/bedrock/*.py", # aiobotocore bedrock-agent KB ingestion — integration/runtime
170
+ "*/clients/email/ses/provider.py", # aiobotocore SESv2 send — E2E only (staging/prod SES)
171
+ "*/clients/email/smtp/provider.py", # aiosmtplib SMTP send — E2E only (dev Mailpit)
172
+ "*/clients/cache/redis/cache.py", # aioredis wrapper — integration (Redis)
173
+ "*/foundation/tracer/tracer.py", # OTel tracer SDK init — integration/runtime
174
+ "*/foundation/observability.py", # OTel observability bootstrap — integration/runtime
175
+ "*/execution/executor/real_ray_runtime.py", # ray.init + @ray.remote wrapper — integration (real Ray)
176
+ ]
177
+
178
+ [tool.ruff]
179
+ line-length = 110
180
+
181
+ [tool.ruff.lint]
182
+ exclude = ["tests/**"]
183
+
184
+ select = ["ALL"]
185
+
186
+ ignore = [
187
+ "ANN002", # Missing type annotation for `*args`
188
+ "ANN003", # Missing type annotation for `**kwargs`
189
+ "BLE001", # Do not catch blind exception: `Exception`
190
+ "COM812", # Trailing comma missing
191
+ "CPY001", # flake8-copyright: repo does not use file copyright headers
192
+ "D105", # Missing docstring in magic method
193
+ "D107", # Missing docstring in `__init__` method
194
+ "D202", # No blank lines allowed after function docstring
195
+ "D203", # 1 blank line before class docstring (conflicts with D211; ruff keeps D211)
196
+ "D213", # Multi-line summary on second line (conflicts with D212; ruff keeps D212)
197
+ "E501", # Line too long
198
+ "FIX002", # Line contains TODO, consider resolving the issue
199
+ "I001", # Import block is un-sorted or un-formatted
200
+ "N802", # Function name `xxx` should be lowercase
201
+ "N999", # Invalid module name
202
+ "RSE102", # Unnecessary parentheses on raise exception
203
+ "S101", # Use of assert detected
204
+ "TC006", # Add quotes to type expression in `typing.cast()`
205
+ "TD002", # Missing author in TODO
206
+ "TD003", # Missing issue link for this TODO
207
+ "TRY002", # Create your own exception
208
+ "TRY300", # Consider moving this statement to an `else` block
209
+ "UP032", # Use f-string instead of `format` call
210
+ ]
211
+
212
+ [tool.ruff.lint.per-file-ignores]
213
+ # The bedrock clients mirror the AWS bedrock-runtime / bedrock-agent-runtime / bedrock-agent APIs, whose
214
+ # keyword params are camelCase (knowledgeBaseId, modelId, retrievalQuery, dataSourceId, …) — N803 does
215
+ # not apply to a wire mirror.
216
+ "src/techai_webutils/clients/llm/bedrock/*.py" = ["N803"]
217
+ "src/techai_webutils/clients/retrieval/bedrock/*.py" = ["N803"]
218
+ "src/techai_webutils/clients/kb_ingestion/bedrock/*.py" = ["N803"]
219
+
220
+ [tool.ruff.lint.mccabe]
221
+ max-complexity = 15
222
+
223
+ [tool.ruff.lint.pylint]
224
+ max-args = 10
225
+ max-branches = 20
226
+ max-returns = 20
227
+
228
+ [tool.pyright]
229
+ pythonVersion = "3.12"
230
+ typeCheckingMode = "standard"
231
+ include = ["src/techai_webutils"]
232
+ exclude = ["tests"]
233
+
234
+ [tool.uv.build-backend]
235
+ module-name = "techai_webutils"
@@ -0,0 +1,5 @@
1
+ """TechAI web utilities shared library."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ __version__ = version("techai_webutils")
@@ -0,0 +1,8 @@
1
+ """Clients layer - external system integration abstractions.
2
+
3
+ This layer contains gRPC client/server factories, decorators, messaging (SQS),
4
+ storage (S3), cache decorators, and integration code for external systems.
5
+
6
+ Clients implements the third layer in the nine-layer architecture model:
7
+ core -> foundation -> clients -> repos -> services -> pipelines -> workflows -> controllers
8
+ """
@@ -0,0 +1,35 @@
1
+ """Cache client tier — config-selected backends (redis/local/null) + decorators.
2
+
3
+ Mirrors Go's ``clients/cache``: ``builder.py`` selects a backend by ``CacheKind`` and returns the
4
+ core ``Cache`` interface; each backend lives in its own subpackage (``redis``/``local``/``null``);
5
+ ``decorators.py`` wraps a cache with logging + metrics. Relocated from ``foundation/cache`` (D2) so the
6
+ concrete backends sit at the clients tier (L2, external-system integration), matching Go.
7
+ """
8
+
9
+ from techai_webutils.clients.cache.builder import (
10
+ CacheConfig,
11
+ CacheKind,
12
+ default_config,
13
+ new_cache_from_config,
14
+ )
15
+ from techai_webutils.clients.cache.decorators import CacheBuilder
16
+ from techai_webutils.clients.cache.envelope import CacheEnvelope, decode, encode
17
+ from techai_webutils.clients.cache.local import LocalCache
18
+ from techai_webutils.clients.cache.null import NullCache
19
+ from techai_webutils.clients.cache.redis import RedisCache
20
+ from techai_webutils.clients.cache.types import FailureMode
21
+
22
+ __all__ = [
23
+ "CacheBuilder",
24
+ "CacheConfig",
25
+ "CacheEnvelope",
26
+ "CacheKind",
27
+ "FailureMode",
28
+ "LocalCache",
29
+ "NullCache",
30
+ "RedisCache",
31
+ "decode",
32
+ "default_config",
33
+ "encode",
34
+ "new_cache_from_config",
35
+ ]
@@ -0,0 +1,87 @@
1
+ """Cache builder with kind enum, config dataclass, and factory function.
2
+
3
+ Creates cache instances based on configuration. Supports REDIS, LOCAL, and NULL
4
+ cache kinds. The factory function routes to the correct implementation based on
5
+ the CacheKind in the config.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from enum import StrEnum
12
+ from typing import Any, TYPE_CHECKING
13
+
14
+ from techai_webutils.clients.cache.local import LocalCache
15
+ from techai_webutils.clients.cache.null import NullCache
16
+ from techai_webutils.clients.cache.redis import RedisCache
17
+ from techai_webutils.clients.cache.types import FailureMode
18
+
19
+ if TYPE_CHECKING:
20
+ from techai_webutils.core.interfaces.cache import Cache
21
+
22
+
23
+ class CacheKind(StrEnum):
24
+ """Available cache implementations."""
25
+
26
+ REDIS = "redis"
27
+ """The Redis-backed cache (shared, cross-pod; stage/prod)."""
28
+ LOCAL = "local"
29
+ """The in-process TTL cache (single-pod; dev/test)."""
30
+ NULL = "null"
31
+ """The no-op cache that never stores or returns a value (caching disabled)."""
32
+
33
+
34
+ @dataclass
35
+ class CacheConfig:
36
+ """Configuration for cache creation.
37
+
38
+ Attributes:
39
+ kind: Which cache implementation to use.
40
+ default_ttl: Default TTL in seconds.
41
+ redis_client: An async Redis client instance (required when kind is REDIS).
42
+ failure_mode: Redis failure mode (only used when kind is REDIS).
43
+
44
+ """
45
+
46
+ kind: CacheKind = CacheKind.LOCAL
47
+ """Selects the cache implementation (defaults to the in-process LOCAL cache)."""
48
+ default_ttl: int = 300
49
+ """Default time-to-live for cached entries, in seconds."""
50
+ redis_client: Any = None
51
+ """An async Redis client instance (required when ``kind`` is REDIS)."""
52
+ failure_mode: FailureMode = FailureMode.BYPASS
53
+ """How a Redis failure is handled (only used when ``kind`` is REDIS)."""
54
+
55
+
56
+ def default_config() -> CacheConfig:
57
+ """Return a default cache config (LOCAL with 300s TTL)."""
58
+ return CacheConfig(kind=CacheKind.LOCAL, default_ttl=300)
59
+
60
+
61
+ def new_cache_from_config(config: CacheConfig) -> Cache:
62
+ """Create a cache instance from config.
63
+
64
+ Args:
65
+ config: Cache configuration specifying kind and parameters.
66
+
67
+ Returns:
68
+ A Cache implementation matching the requested kind.
69
+
70
+ Raises:
71
+ ValueError: If the kind is unknown or required parameters are missing.
72
+
73
+ """
74
+ if config.kind == CacheKind.LOCAL:
75
+ return LocalCache(default_ttl=config.default_ttl)
76
+
77
+ if config.kind == CacheKind.NULL:
78
+ return NullCache()
79
+
80
+ if config.kind == CacheKind.REDIS:
81
+ if config.redis_client is None:
82
+ msg = "redis_client is required when kind is REDIS"
83
+ raise ValueError(msg)
84
+ return RedisCache(client=config.redis_client, failure_mode=config.failure_mode)
85
+
86
+ msg = f"unknown cache kind: {config.kind}"
87
+ raise ValueError(msg)