fin-infra 0.1.60__tar.gz → 0.1.62__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 (179) hide show
  1. {fin_infra-0.1.60 → fin_infra-0.1.62}/PKG-INFO +2 -1
  2. {fin_infra-0.1.60 → fin_infra-0.1.62}/pyproject.toml +2 -1
  3. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/models.py +1 -1
  4. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/spending.py +5 -5
  5. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/__init__.py +4 -4
  6. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/llm_layer.py +1 -1
  7. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/chat/__init__.py +3 -3
  8. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/chat/ease.py +8 -8
  9. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/chat/planning.py +7 -7
  10. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/crypto/insights.py +12 -12
  11. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/documents/analysis.py +5 -5
  12. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/management.py +6 -6
  13. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/models.py +6 -6
  14. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/ease.py +3 -3
  15. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/insights.py +7 -7
  16. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/models.py +14 -14
  17. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/obs/classifier.py +4 -2
  18. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/brokerage/alpaca.py +1 -1
  19. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/detectors_llm.py +10 -10
  20. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/insights.py +10 -10
  21. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/normalizers.py +10 -10
  22. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/token_store.py +6 -2
  23. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/tax/add.py +1 -1
  24. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/tax/tlh.py +5 -5
  25. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/utils/retry.py +1 -1
  26. {fin_infra-0.1.60 → fin_infra-0.1.62}/LICENSE +0 -0
  27. {fin_infra-0.1.60 → fin_infra-0.1.62}/README.md +0 -0
  28. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/__init__.py +0 -0
  29. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/__main__.py +0 -0
  30. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/__init__.py +0 -0
  31. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/add.py +0 -0
  32. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/cash_flow.py +0 -0
  33. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/ease.py +0 -0
  34. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/portfolio.py +0 -0
  35. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/projections.py +0 -0
  36. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/rebalancing.py +0 -0
  37. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/savings.py +0 -0
  38. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/analytics/scenarios.py +0 -0
  39. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/banking/__init__.py +0 -0
  40. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/banking/history.py +0 -0
  41. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/banking/utils.py +0 -0
  42. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/brokerage/__init__.py +0 -0
  43. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/add.py +0 -0
  44. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/alerts.py +0 -0
  45. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/ease.py +0 -0
  46. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/models.py +0 -0
  47. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/scaffold_templates/README.md +0 -0
  48. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/scaffold_templates/__init__.py +0 -0
  49. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/scaffold_templates/models.py.tmpl +0 -0
  50. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/scaffold_templates/repository.py.tmpl +0 -0
  51. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/scaffold_templates/schemas.py.tmpl +0 -0
  52. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/templates.py +0 -0
  53. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/budgets/tracker.py +0 -0
  54. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/cashflows/__init__.py +0 -0
  55. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/cashflows/core.py +0 -0
  56. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/__init__.py +0 -0
  57. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/add.py +0 -0
  58. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/ease.py +0 -0
  59. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/engine.py +0 -0
  60. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/models.py +0 -0
  61. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/rules.py +0 -0
  62. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/categorization/taxonomy.py +0 -0
  63. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/cli/__init__.py +0 -0
  64. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/cli/cmds/__init__.py +0 -0
  65. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/cli/cmds/scaffold_cmds.py +0 -0
  66. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/clients/__init__.py +0 -0
  67. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/clients/base.py +0 -0
  68. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/clients/plaid.py +0 -0
  69. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/compliance/__init__.py +0 -0
  70. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/__init__.py +0 -0
  71. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/add.py +0 -0
  72. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/experian/__init__.py +0 -0
  73. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/experian/auth.py +0 -0
  74. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/experian/client.py +0 -0
  75. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/experian/parser.py +0 -0
  76. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/experian/provider.py +0 -0
  77. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/credit/mock.py +0 -0
  78. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/crypto/__init__.py +0 -0
  79. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/documents/__init__.py +0 -0
  80. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/documents/add.py +0 -0
  81. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/documents/ease.py +0 -0
  82. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/documents/models.py +0 -0
  83. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/documents/ocr.py +0 -0
  84. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/documents/storage.py +0 -0
  85. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/exceptions.py +0 -0
  86. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/__init__.py +0 -0
  87. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/add.py +0 -0
  88. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/funding.py +0 -0
  89. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/milestones.py +0 -0
  90. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/models.py +0 -0
  91. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/scaffold_templates/README.md +0 -0
  92. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/scaffold_templates/__init__.py +0 -0
  93. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/scaffold_templates/models.py.tmpl +0 -0
  94. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/scaffold_templates/repository.py.tmpl +0 -0
  95. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/goals/scaffold_templates/schemas.py.tmpl +0 -0
  96. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/insights/__init__.py +0 -0
  97. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/insights/aggregator.py +0 -0
  98. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/insights/models.py +0 -0
  99. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/__init__.py +0 -0
  100. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/add.py +0 -0
  101. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/ease.py +0 -0
  102. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/providers/__init__.py +0 -0
  103. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/providers/base.py +0 -0
  104. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/providers/plaid.py +0 -0
  105. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/providers/snaptrade.py +0 -0
  106. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/scaffold_templates/README.md +0 -0
  107. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/scaffold_templates/__init__.py +0 -0
  108. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/scaffold_templates/models.py.tmpl +0 -0
  109. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/scaffold_templates/repository.py.tmpl +0 -0
  110. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/investments/scaffold_templates/schemas.py.tmpl +0 -0
  111. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/markets/__init__.py +0 -0
  112. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/__init__.py +0 -0
  113. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/accounts.py +0 -0
  114. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/brokerage.py +0 -0
  115. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/candle.py +0 -0
  116. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/credit.py +0 -0
  117. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/money.py +0 -0
  118. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/quotes.py +0 -0
  119. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/tax.py +0 -0
  120. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/models/transactions.py +0 -0
  121. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/__init__.py +0 -0
  122. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/add.py +0 -0
  123. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/aggregator.py +0 -0
  124. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/calculator.py +0 -0
  125. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/goals.py +0 -0
  126. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/scaffold_templates/README.md +0 -0
  127. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/scaffold_templates/__init__.py +0 -0
  128. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/scaffold_templates/models.py.tmpl +0 -0
  129. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/scaffold_templates/repository.py.tmpl +0 -0
  130. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/net_worth/scaffold_templates/schemas.py.tmpl +0 -0
  131. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/normalization/__init__.py +0 -0
  132. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/normalization/currency_converter.py +0 -0
  133. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/normalization/models.py +0 -0
  134. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/normalization/providers/__init__.py +0 -0
  135. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/normalization/providers/exchangerate.py +0 -0
  136. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/normalization/providers/static_mappings.py +0 -0
  137. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/normalization/symbol_resolver.py +0 -0
  138. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/obs/__init__.py +0 -0
  139. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/__init__.py +0 -0
  140. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/banking/base.py +0 -0
  141. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/banking/plaid_client.py +0 -0
  142. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/banking/teller_client.py +0 -0
  143. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/base.py +0 -0
  144. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/brokerage/base.py +0 -0
  145. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/credit/experian.py +0 -0
  146. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/identity/stripe_identity.py +0 -0
  147. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/market/alphavantage.py +0 -0
  148. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/market/base.py +0 -0
  149. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/market/ccxt_crypto.py +0 -0
  150. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/market/coingecko.py +0 -0
  151. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/market/yahoo.py +0 -0
  152. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/registry.py +0 -0
  153. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/tax/__init__.py +0 -0
  154. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/tax/irs.py +0 -0
  155. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/tax/mock.py +0 -0
  156. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/providers/tax/taxbit.py +0 -0
  157. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/py.typed +0 -0
  158. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/__init__.py +0 -0
  159. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/add.py +0 -0
  160. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/detector.py +0 -0
  161. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/ease.py +0 -0
  162. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/models.py +0 -0
  163. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/normalizer.py +0 -0
  164. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/recurring/summary.py +0 -0
  165. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/scaffold/__init__.py +0 -0
  166. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/scaffold/budgets.py +0 -0
  167. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/scaffold/goals.py +0 -0
  168. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/__init__.py +0 -0
  169. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/add.py +0 -0
  170. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/audit.py +0 -0
  171. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/encryption.py +0 -0
  172. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/models.py +0 -0
  173. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/pii_filter.py +0 -0
  174. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/security/pii_patterns.py +0 -0
  175. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/settings.py +0 -0
  176. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/tax/__init__.py +0 -0
  177. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/utils/__init__.py +0 -0
  178. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/utils/http.py +0 -0
  179. {fin_infra-0.1.60 → fin_infra-0.1.62}/src/fin_infra/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fin-infra
3
- Version: 0.1.60
3
+ Version: 0.1.62
4
4
  Summary: Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations
5
5
  License: MIT
6
6
  Keywords: finance,banking,plaid,brokerage,markets,credit,tax,cashflow,fintech,infra
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
19
19
  Classifier: Topic :: Office/Business :: Financial
20
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
21
  Classifier: Typing :: Typed
22
+ Requires-Dist: ai-infra (>=0.1.142)
22
23
  Requires-Dist: cashews[redis] (>=7.0)
23
24
  Requires-Dist: ccxt (>=4.0.0)
24
25
  Requires-Dist: httpx (>=0.25.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "fin-infra"
3
- version = "0.1.60"
3
+ version = "0.1.62"
4
4
  description = "Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations"
5
5
  authors = ["Ali Khatami <aliikhatami94@gmail.com>"]
6
6
  license = "MIT"
@@ -55,6 +55,7 @@ svc-infra = ">=0.1.0" # Published version for CI/production
55
55
  yahooquery = ">=2.3.0"
56
56
  ccxt = ">=4.0.0"
57
57
  plaid-python = ">=25.0.0"
58
+ ai-infra = ">=0.1.142"
58
59
 
59
60
  [tool.poetry.group.dev.dependencies]
60
61
  pytest = ">=8.0.0"
@@ -114,7 +114,7 @@ class SpendingInsight(BaseModel):
114
114
  class PersonalizedSpendingAdvice(BaseModel):
115
115
  """LLM-generated personalized spending advice.
116
116
 
117
- Uses ai-infra CoreLLM for structured output generation.
117
+ Uses ai-infra LLM for structured output generation.
118
118
  """
119
119
 
120
120
  model_config = ConfigDict(extra="forbid")
@@ -12,7 +12,7 @@ Generic Applicability:
12
12
 
13
13
  Features:
14
14
  - Statistical analysis: Top merchants, category breakdowns, trends, anomalies
15
- - LLM-powered insights: Personalized recommendations using ai-infra CoreLLM
15
+ - LLM-powered insights: Personalized recommendations using ai-infra LLM
16
16
  - Graceful degradation: Falls back to rule-based insights if LLM unavailable
17
17
  - Cost-effective: Structured output for predictable token usage (<$0.01/insight)
18
18
 
@@ -427,12 +427,12 @@ async def generate_spending_insights(
427
427
  ) -> "PersonalizedSpendingAdvice":
428
428
  """Generate personalized spending insights using LLM.
429
429
 
430
- Uses ai-infra CoreLLM for structured output generation with financial context.
430
+ Uses ai-infra LLM for structured output generation with financial context.
431
431
 
432
432
  Args:
433
433
  spending_insight: Analyzed spending data from analyze_spending()
434
434
  user_context: Optional context (income, goals, budget, preferences)
435
- llm_provider: Optional CoreLLM instance (defaults to Google Gemini)
435
+ llm_provider: Optional LLM instance (defaults to Google Gemini)
436
436
 
437
437
  Returns:
438
438
  PersonalizedSpendingAdvice with LLM-generated recommendations
@@ -468,14 +468,14 @@ async def generate_spending_insights(
468
468
 
469
469
  # Try to import ai-infra LLM (optional dependency)
470
470
  try:
471
- from ai_infra.llm import CoreLLM
471
+ from ai_infra.llm import LLM
472
472
  except ImportError:
473
473
  # Graceful degradation: return rule-based insights
474
474
  return _generate_rule_based_insights(spending_insight, user_context)
475
475
 
476
476
  # Initialize LLM if not provided
477
477
  if llm_provider is None:
478
- llm_provider = CoreLLM()
478
+ llm_provider = LLM()
479
479
 
480
480
  # Build financial context prompt
481
481
  prompt = _build_spending_insights_prompt(spending_insight, user_context)
@@ -87,11 +87,11 @@ __all__ = [
87
87
  def __getattr__(name: str):
88
88
  """Lazy import for budgets module components."""
89
89
  if name == "easy_budgets":
90
- from fin_infra.budgets.ease import easy_budgets # type: ignore[attr-defined]
90
+ from fin_infra.budgets.ease import easy_budgets
91
91
 
92
92
  return easy_budgets
93
93
  elif name == "add_budgets":
94
- from fin_infra.budgets.add import add_budgets # type: ignore[attr-defined]
94
+ from fin_infra.budgets.add import add_budgets
95
95
 
96
96
  return add_budgets
97
97
  elif name in (
@@ -119,11 +119,11 @@ def __getattr__(name: str):
119
119
 
120
120
  return BudgetTracker
121
121
  elif name == "check_budget_alerts":
122
- from fin_infra.budgets.alerts import check_budget_alerts # type: ignore[attr-defined]
122
+ from fin_infra.budgets.alerts import check_budget_alerts
123
123
 
124
124
  return check_budget_alerts
125
125
  elif name == "apply_template":
126
- from fin_infra.budgets.templates import apply_template # type: ignore[attr-defined]
126
+ from fin_infra.budgets.templates import apply_template
127
127
 
128
128
  return apply_template
129
129
 
@@ -20,7 +20,7 @@ from pydantic import BaseModel, Field
20
20
 
21
21
  # ai-infra imports
22
22
  try:
23
- from ai_infra.llm import CoreLLM as LLM
23
+ from ai_infra.llm import LLM
24
24
  from ai_infra.llm.providers import Providers
25
25
  except ImportError:
26
26
  raise ImportError("ai-infra not installed. Install with: pip install ai-infra")
@@ -10,10 +10,10 @@ NOT tied to net worth specifically - works across ALL fin-infra domains:
10
10
 
11
11
  Example:
12
12
  from fin_infra.conversation import FinancialPlanningConversation
13
- from ai_infra.llm import CoreLLM
13
+ from ai_infra.llm import LLM
14
14
  from svc_infra.cache import get_cache
15
15
 
16
- llm = CoreLLM()
16
+ llm = LLM()
17
17
  cache = get_cache()
18
18
  conversation = FinancialPlanningConversation(
19
19
  llm=llm,
@@ -101,7 +101,7 @@ def add_financial_conversation(
101
101
 
102
102
  Integration:
103
103
  - Uses user_router (requires authentication)
104
- - Powered by ai-infra CoreLLM (multi-provider support)
104
+ - Powered by ai-infra LLM (multi-provider support)
105
105
  - Uses svc-infra cache for conversation history (24h TTL)
106
106
  - Cost: ~$0.018/user/month with Google Gemini
107
107
 
@@ -13,8 +13,8 @@ Example:
13
13
  conversation = easy_financial_conversation(provider="openai")
14
14
 
15
15
  # Custom LLM instance
16
- from ai_infra.llm import CoreLLM
17
- llm = CoreLLM(temperature=0.3)
16
+ from ai_infra.llm import LLM
17
+ llm = LLM(temperature=0.3)
18
18
  conversation = easy_financial_conversation(llm=llm)
19
19
  """
20
20
 
@@ -33,12 +33,12 @@ def easy_financial_conversation(
33
33
  Easy builder for financial planning conversation.
34
34
 
35
35
  One-call setup with sensible defaults:
36
- - LLM: ai-infra CoreLLM (Google Gemini default)
36
+ - LLM: ai-infra LLM (Google Gemini default)
37
37
  - Cache: svc-infra cache (24h TTL)
38
38
  - Provider: Google (cheapest, $0.018/user/month)
39
39
 
40
40
  Args:
41
- llm: Optional ai-infra CoreLLM instance (auto-created if None)
41
+ llm: Optional ai-infra LLM instance (auto-created if None)
42
42
  cache: Optional svc-infra cache instance (auto-created if None)
43
43
  provider: LLM provider ("google", "openai", "anthropic")
44
44
  model_name: Optional model name override (uses provider defaults)
@@ -62,16 +62,16 @@ def easy_financial_conversation(
62
62
  conversation = easy_financial_conversation(provider="openai")
63
63
 
64
64
  # Custom LLM instance
65
- from ai_infra.llm import CoreLLM
66
- llm = CoreLLM(temperature=0.3)
65
+ from ai_infra.llm import LLM
66
+ llm = LLM(temperature=0.3)
67
67
  conversation = easy_financial_conversation(llm=llm)
68
68
  """
69
69
  # Auto-create LLM if not provided
70
70
  if llm is None:
71
71
  try:
72
- from ai_infra.llm import CoreLLM
72
+ from ai_infra.llm import LLM
73
73
 
74
- llm = CoreLLM()
74
+ llm = LLM()
75
75
  except ImportError:
76
76
  raise ImportError("ai-infra not installed. Install with: pip install ai-infra")
77
77
 
@@ -10,19 +10,19 @@ Provides conversational interface for financial Q&A:
10
10
  - Personalized advice (uses current net worth, goals, historical data)
11
11
  - Natural dialogue (flexible responses, not forced JSON structure)
12
12
 
13
- **Design Choice**: Uses `CoreLLM.achat()` for natural conversation (NOT `with_structured_output()`).
13
+ **Design Choice**: Uses `LLM.achat()` for natural conversation (NOT `with_structured_output()`).
14
14
  Conversation should be flexible and natural, not rigidly structured. Other modules (insights,
15
15
  categorization, goals) correctly use structured output because they need predictable schemas.
16
16
 
17
- Uses ai-infra CoreLLM for natural conversation.
17
+ Uses ai-infra LLM for natural conversation.
18
18
  Caches conversation context for 24h (target: $0.018/user/month cost).
19
19
 
20
20
  Example:
21
- from ai_infra.llm import CoreLLM
21
+ from ai_infra.llm import LLM
22
22
  from svc_infra.cache import get_cache
23
23
  from fin_infra.conversation import FinancialPlanningConversation
24
24
 
25
- llm = CoreLLM()
25
+ llm = LLM()
26
26
  cache = get_cache()
27
27
  conversation = FinancialPlanningConversation(
28
28
  llm=llm,
@@ -196,10 +196,10 @@ class FinancialPlanningConversation:
196
196
  Cost: ~$0.0054/conversation (10 turns with context caching)
197
197
 
198
198
  Example:
199
- from ai_infra.llm import CoreLLM
199
+ from ai_infra.llm import LLM
200
200
  from svc_infra.cache import get_cache
201
201
 
202
- llm = CoreLLM()
202
+ llm = LLM()
203
203
  cache = get_cache()
204
204
  conversation = FinancialPlanningConversation(
205
205
  llm=llm,
@@ -232,7 +232,7 @@ class FinancialPlanningConversation:
232
232
  Initialize conversation manager.
233
233
 
234
234
  Args:
235
- llm: ai-infra CoreLLM instance
235
+ llm: ai-infra LLM instance
236
236
  cache: svc-infra cache instance (for context storage)
237
237
  provider: LLM provider ("google", "openai", "anthropic")
238
238
  model_name: Model name (default: gemini-2.0-flash-exp)
@@ -1,9 +1,9 @@
1
1
  """Crypto portfolio insights using ai-infra LLM.
2
2
 
3
3
  This module generates personalized insights for cryptocurrency holdings using
4
- ai-infra's CoreLLM for intelligent analysis and recommendations.
4
+ ai-infra's LLM for intelligent analysis and recommendations.
5
5
 
6
- CRITICAL: Uses ai-infra.llm.CoreLLM (NEVER custom LLM clients).
6
+ CRITICAL: Uses ai-infra.llm.LLM (NEVER custom LLM clients).
7
7
  """
8
8
 
9
9
  from __future__ import annotations
@@ -15,7 +15,7 @@ from typing import TYPE_CHECKING
15
15
  from pydantic import BaseModel, Field
16
16
 
17
17
  if TYPE_CHECKING:
18
- from ai_infra.llm import CoreLLM
18
+ from ai_infra.llm import LLM
19
19
 
20
20
 
21
21
  class CryptoInsight(BaseModel):
@@ -56,13 +56,13 @@ class CryptoHolding(BaseModel):
56
56
  async def generate_crypto_insights(
57
57
  user_id: str,
58
58
  holdings: list[CryptoHolding],
59
- llm: CoreLLM | None = None,
59
+ llm: LLM | None = None,
60
60
  total_portfolio_value: Decimal | None = None,
61
61
  ) -> list[CryptoInsight]:
62
62
  """
63
63
  Generate personalized crypto insights using ai-infra LLM.
64
64
 
65
- Uses ai-infra.llm.CoreLLM for intelligent analysis based on:
65
+ Uses ai-infra.llm.LLM for intelligent analysis based on:
66
66
  - Portfolio concentration (diversification recommendations)
67
67
  - Performance trends (gains/losses)
68
68
  - Risk assessment (volatility, allocation %)
@@ -71,15 +71,15 @@ async def generate_crypto_insights(
71
71
  Args:
72
72
  user_id: User identifier
73
73
  holdings: List of crypto holdings
74
- llm: CoreLLM instance (if None, uses default Google Gemini)
74
+ llm: LLM instance (if None, uses default Google Gemini)
75
75
  total_portfolio_value: Total portfolio value including non-crypto assets
76
76
 
77
77
  Returns:
78
78
  List of personalized CryptoInsight objects
79
79
 
80
80
  Example:
81
- >>> from ai_infra.llm import CoreLLM
82
- >>> llm = CoreLLM(provider="google_genai", model="gemini-2.0-flash-exp")
81
+ >>> from ai_infra.llm import LLM
82
+ >>> llm = LLM(provider="google_genai", model="gemini-2.0-flash-exp")
83
83
  >>> holdings = [
84
84
  ... CryptoHolding(
85
85
  ... symbol="BTC",
@@ -206,14 +206,14 @@ async def _generate_llm_insights(
206
206
  holdings: list[CryptoHolding],
207
207
  total_crypto_value: Decimal,
208
208
  total_portfolio_value: Decimal | None,
209
- llm: CoreLLM,
209
+ llm: LLM,
210
210
  ) -> list[CryptoInsight]:
211
211
  """
212
- Generate AI-powered insights using ai-infra CoreLLM.
212
+ Generate AI-powered insights using ai-infra LLM.
213
213
 
214
214
  Uses natural language conversation (NO output_schema) for personalized advice.
215
215
 
216
- CRITICAL: Uses ai-infra.llm.CoreLLM (never custom LLM clients).
216
+ CRITICAL: Uses ai-infra.llm.LLM (never custom LLM clients).
217
217
  """
218
218
  insights = []
219
219
 
@@ -260,7 +260,7 @@ Provide your insight:"""
260
260
  # Use natural language conversation (no output_schema)
261
261
  # Note: In tests, achat is mocked with messages= parameter
262
262
  # In production, this should use user_msg, provider, model_name parameters
263
- response = await llm.achat( # type: ignore[call-arg]
263
+ response = await llm.achat(
264
264
  messages=[{"role": "user", "content": prompt}],
265
265
  )
266
266
 
@@ -2,7 +2,7 @@
2
2
  AI-powered document analysis and insights.
3
3
 
4
4
  Uses rule-based analysis (simulated AI) for financial documents.
5
- Production: Use ai-infra CoreLLM for real AI-powered insights.
5
+ Production: Use ai-infra LLM for real AI-powered insights.
6
6
 
7
7
  Quick Start:
8
8
  >>> from fin_infra.documents.analysis import analyze_document
@@ -14,7 +14,7 @@ Quick Start:
14
14
  >>> print(result.recommendations)
15
15
 
16
16
  Production Integration:
17
- - Use ai-infra CoreLLM for all LLM calls (never custom clients)
17
+ - Use ai-infra LLM for all LLM calls (never custom clients)
18
18
  - Cache analysis results (24h TTL via svc-infra cache)
19
19
  - Track LLM costs per user (ai-infra cost tracking)
20
20
  - Add disclaimers for financial advice
@@ -68,7 +68,7 @@ async def analyze_document(
68
68
 
69
69
  Notes:
70
70
  - Current: Rule-based analysis (simulated AI)
71
- - Production: Use ai-infra CoreLLM (never custom LLM clients)
71
+ - Production: Use ai-infra LLM (never custom LLM clients)
72
72
  - Production: Check cache before analysis (svc-infra cache, 24h TTL)
73
73
  - Production: Track LLM costs (ai-infra cost tracking)
74
74
  - Production: Add disclaimer: "Not a substitute for certified financial advisor"
@@ -218,7 +218,7 @@ def _analyze_tax_document(ocr_text: str, metadata: dict, document_id: str) -> "D
218
218
 
219
219
  Notes:
220
220
  - Current: Rule-based analysis (simulated AI)
221
- - Production: Use ai-infra CoreLLM with financial tax prompt
221
+ - Production: Use ai-infra LLM with financial tax prompt
222
222
  - Production: Include tax bracket information
223
223
  - Production: Suggest W-4 adjustments if applicable
224
224
  - Production: Identify potential deductions or credits
@@ -318,7 +318,7 @@ def _analyze_bank_statement(ocr_text: str, metadata: dict, document_id: str) ->
318
318
 
319
319
  Notes:
320
320
  - Current: Rule-based analysis (simulated AI)
321
- - Production: Use ai-infra CoreLLM with spending analysis prompt
321
+ - Production: Use ai-infra LLM with spending analysis prompt
322
322
  - Production: Identify unusual transactions or patterns
323
323
  - Production: Compare to typical spending (if available)
324
324
  - Production: Suggest budget optimizations
@@ -7,14 +7,14 @@ Provides 4 goal types with validation and progress tracking:
7
7
  3. Debt-Free Goal: Debt payoff schedule with APR calculations
8
8
  4. Wealth Milestone: Project growth to target net worth
9
9
 
10
- Uses ai-infra CoreLLM for validation + local math for calculations.
10
+ Uses ai-infra LLM for validation + local math for calculations.
11
11
  Weekly progress check-ins via svc-infra.jobs scheduler ($0.0036/user/month).
12
12
 
13
13
  Example:
14
- from ai_infra.llm import CoreLLM
14
+ from ai_infra.llm import LLM
15
15
  from fin_infra.goals.management import FinancialGoalTracker
16
16
 
17
- llm = CoreLLM()
17
+ llm = LLM()
18
18
  tracker = FinancialGoalTracker(
19
19
  llm=llm,
20
20
  provider="google",
@@ -475,9 +475,9 @@ class FinancialGoalTracker:
475
475
  Cost: ~$0.0009/validation, ~$0.0009/week for progress ($0.0036/user/month)
476
476
 
477
477
  Example:
478
- from ai_infra.llm import CoreLLM
478
+ from ai_infra.llm import LLM
479
479
 
480
- llm = CoreLLM()
480
+ llm = LLM()
481
481
  tracker = FinancialGoalTracker(llm=llm, provider="google")
482
482
 
483
483
  # Validate goal
@@ -503,7 +503,7 @@ class FinancialGoalTracker:
503
503
  Initialize goal tracker.
504
504
 
505
505
  Args:
506
- llm: ai-infra CoreLLM instance
506
+ llm: ai-infra LLM instance
507
507
  provider: LLM provider ("google", "openai", "anthropic")
508
508
  model_name: Model name (default: gemini-2.0-flash-exp)
509
509
  """
@@ -201,7 +201,7 @@ class Holding(BaseModel):
201
201
  unofficial_currency_code: Optional[str] = Field(None, description="For crypto/alt currencies")
202
202
  as_of_date: Optional[date] = Field(None, description="Date of pricing data")
203
203
 
204
- @computed_field # type: ignore[misc]
204
+ @computed_field
205
205
  @property
206
206
  def unrealized_gain_loss(self) -> Optional[Decimal]:
207
207
  """Calculate unrealized gain/loss (current value - cost basis)."""
@@ -209,7 +209,7 @@ class Holding(BaseModel):
209
209
  return None
210
210
  return self.institution_value - self.cost_basis
211
211
 
212
- @computed_field # type: ignore[misc]
212
+ @computed_field
213
213
  @property
214
214
  def unrealized_gain_loss_percent(self) -> Optional[Decimal]:
215
215
  """Calculate unrealized gain/loss percentage."""
@@ -350,7 +350,7 @@ class InvestmentAccount(BaseModel):
350
350
  # Holdings
351
351
  holdings: List[Holding] = Field(default_factory=list, description="List of holdings in account")
352
352
 
353
- @computed_field # type: ignore[misc]
353
+ @computed_field
354
354
  @property
355
355
  def total_value(self) -> Decimal:
356
356
  """Calculate total account value (sum of holdings + cash)."""
@@ -358,20 +358,20 @@ class InvestmentAccount(BaseModel):
358
358
  cash_balance = self.balances.get("current") or Decimal(0)
359
359
  return holdings_value + cash_balance
360
360
 
361
- @computed_field # type: ignore[misc]
361
+ @computed_field
362
362
  @property
363
363
  def total_cost_basis(self) -> Decimal:
364
364
  """Calculate total cost basis (sum of cost_basis across holdings)."""
365
365
  return sum(h.cost_basis for h in self.holdings if h.cost_basis is not None)
366
366
 
367
- @computed_field # type: ignore[misc]
367
+ @computed_field
368
368
  @property
369
369
  def total_unrealized_gain_loss(self) -> Decimal:
370
370
  """Calculate total unrealized P&L (value - cost_basis)."""
371
371
  holdings_value = sum(h.institution_value for h in self.holdings)
372
372
  return holdings_value - self.total_cost_basis
373
373
 
374
- @computed_field # type: ignore[misc]
374
+ @computed_field
375
375
  @property
376
376
  def total_unrealized_gain_loss_percent(self) -> Optional[Decimal]:
377
377
  """Calculate total unrealized P&L percentage."""
@@ -368,7 +368,7 @@ def easy_net_worth(
368
368
 
369
369
  if enable_llm:
370
370
  try:
371
- from ai_infra.llm import CoreLLM
371
+ from ai_infra.llm import LLM
372
372
  except ImportError:
373
373
  raise ImportError(
374
374
  "LLM features require ai-infra package. " "Install with: pip install ai-infra"
@@ -387,8 +387,8 @@ def easy_net_worth(
387
387
  f"Unknown llm_provider: {llm_provider}. " f"Use 'google', 'openai', or 'anthropic'"
388
388
  )
389
389
 
390
- # Create shared CoreLLM instance
391
- llm = CoreLLM()
390
+ # Create shared LLM instance
391
+ llm = LLM()
392
392
 
393
393
  # Create LLM components (deferred import to avoid circular dependency)
394
394
  # These modules will be created in Section 17 V2 implementation
@@ -7,14 +7,14 @@ Provides 4 types of insights:
7
7
  3. Goal Recommendations: Validate financial goals and suggest paths
8
8
  4. Asset Allocation Advice: Portfolio rebalancing based on age/risk
9
9
 
10
- Uses ai-infra CoreLLM with structured output (Pydantic schemas).
10
+ Uses ai-infra LLM with structured output (Pydantic schemas).
11
11
  Caches insights for 24h (target: 95%+ hit rate, $0.042/user/month cost).
12
12
 
13
13
  Example:
14
- from ai_infra.llm import CoreLLM
14
+ from ai_infra.llm import LLM
15
15
  from fin_infra.net_worth.insights import NetWorthInsightsGenerator
16
16
 
17
- llm = CoreLLM()
17
+ llm = LLM()
18
18
  generator = NetWorthInsightsGenerator(
19
19
  llm=llm,
20
20
  provider="google",
@@ -379,7 +379,7 @@ class NetWorthInsightsGenerator:
379
379
  """
380
380
  Generate LLM-powered financial insights for net worth tracking.
381
381
 
382
- Uses ai-infra CoreLLM with structured output (Pydantic schemas).
382
+ Uses ai-infra LLM with structured output (Pydantic schemas).
383
383
  Supports 4 insight types:
384
384
  1. Wealth trends (analyze net worth changes)
385
385
  2. Debt reduction (prioritize payoff by APR)
@@ -389,9 +389,9 @@ class NetWorthInsightsGenerator:
389
389
  Cost: ~$0.042/user/month (1 insight/day, 24h cache, Google Gemini)
390
390
 
391
391
  Example:
392
- from ai_infra.llm import CoreLLM
392
+ from ai_infra.llm import LLM
393
393
 
394
- llm = CoreLLM()
394
+ llm = LLM()
395
395
  generator = NetWorthInsightsGenerator(
396
396
  llm=llm,
397
397
  provider="google",
@@ -412,7 +412,7 @@ class NetWorthInsightsGenerator:
412
412
  Initialize insights generator.
413
413
 
414
414
  Args:
415
- llm: ai-infra CoreLLM instance
415
+ llm: ai-infra LLM instance
416
416
  provider: LLM provider ("google", "openai", "anthropic")
417
417
  model_name: Model name (default: gemini-2.0-flash-exp)
418
418
  """
@@ -207,7 +207,7 @@ class AssetAllocation(BaseModel):
207
207
  vehicles: float = Field(0.0, ge=0, description="Vehicle value")
208
208
  other_assets: float = Field(0.0, ge=0, description="Other asset value")
209
209
 
210
- @computed_field # type: ignore[misc]
210
+ @computed_field
211
211
  @property
212
212
  def total_assets(self) -> float:
213
213
  """Sum of all asset categories."""
@@ -220,37 +220,37 @@ class AssetAllocation(BaseModel):
220
220
  + self.other_assets
221
221
  )
222
222
 
223
- @computed_field # type: ignore[misc]
223
+ @computed_field
224
224
  @property
225
225
  def cash_percentage(self) -> float:
226
226
  """Cash as percentage of total assets."""
227
227
  return (self.cash / self.total_assets * 100) if self.total_assets > 0 else 0.0
228
228
 
229
- @computed_field # type: ignore[misc]
229
+ @computed_field
230
230
  @property
231
231
  def investments_percentage(self) -> float:
232
232
  """Investments as percentage of total assets."""
233
233
  return (self.investments / self.total_assets * 100) if self.total_assets > 0 else 0.0
234
234
 
235
- @computed_field # type: ignore[misc]
235
+ @computed_field
236
236
  @property
237
237
  def crypto_percentage(self) -> float:
238
238
  """Crypto as percentage of total assets."""
239
239
  return (self.crypto / self.total_assets * 100) if self.total_assets > 0 else 0.0
240
240
 
241
- @computed_field # type: ignore[misc]
241
+ @computed_field
242
242
  @property
243
243
  def real_estate_percentage(self) -> float:
244
244
  """Real estate as percentage of total assets."""
245
245
  return (self.real_estate / self.total_assets * 100) if self.total_assets > 0 else 0.0
246
246
 
247
- @computed_field # type: ignore[misc]
247
+ @computed_field
248
248
  @property
249
249
  def vehicles_percentage(self) -> float:
250
250
  """Vehicles as percentage of total assets."""
251
251
  return (self.vehicles / self.total_assets * 100) if self.total_assets > 0 else 0.0
252
252
 
253
- @computed_field # type: ignore[misc]
253
+ @computed_field
254
254
  @property
255
255
  def other_percentage(self) -> float:
256
256
  """Other assets as percentage of total assets."""
@@ -288,7 +288,7 @@ class LiabilityBreakdown(BaseModel):
288
288
  personal_loans: float = Field(0.0, ge=0, description="Personal loan balance")
289
289
  lines_of_credit: float = Field(0.0, ge=0, description="Line of credit balance")
290
290
 
291
- @computed_field # type: ignore[misc]
291
+ @computed_field
292
292
  @property
293
293
  def total_liabilities(self) -> float:
294
294
  """Sum of all liability categories."""
@@ -301,7 +301,7 @@ class LiabilityBreakdown(BaseModel):
301
301
  + self.lines_of_credit
302
302
  )
303
303
 
304
- @computed_field # type: ignore[misc]
304
+ @computed_field
305
305
  @property
306
306
  def credit_cards_percentage(self) -> float:
307
307
  """Credit cards as percentage of total liabilities."""
@@ -311,7 +311,7 @@ class LiabilityBreakdown(BaseModel):
311
311
  else 0.0
312
312
  )
313
313
 
314
- @computed_field # type: ignore[misc]
314
+ @computed_field
315
315
  @property
316
316
  def mortgages_percentage(self) -> float:
317
317
  """Mortgages as percentage of total liabilities."""
@@ -319,7 +319,7 @@ class LiabilityBreakdown(BaseModel):
319
319
  (self.mortgages / self.total_liabilities * 100) if self.total_liabilities > 0 else 0.0
320
320
  )
321
321
 
322
- @computed_field # type: ignore[misc]
322
+ @computed_field
323
323
  @property
324
324
  def auto_loans_percentage(self) -> float:
325
325
  """Auto loans as percentage of total liabilities."""
@@ -327,7 +327,7 @@ class LiabilityBreakdown(BaseModel):
327
327
  (self.auto_loans / self.total_liabilities * 100) if self.total_liabilities > 0 else 0.0
328
328
  )
329
329
 
330
- @computed_field # type: ignore[misc]
330
+ @computed_field
331
331
  @property
332
332
  def student_loans_percentage(self) -> float:
333
333
  """Student loans as percentage of total liabilities."""
@@ -337,7 +337,7 @@ class LiabilityBreakdown(BaseModel):
337
337
  else 0.0
338
338
  )
339
339
 
340
- @computed_field # type: ignore[misc]
340
+ @computed_field
341
341
  @property
342
342
  def personal_loans_percentage(self) -> float:
343
343
  """Personal loans as percentage of total liabilities."""
@@ -347,7 +347,7 @@ class LiabilityBreakdown(BaseModel):
347
347
  else 0.0
348
348
  )
349
349
 
350
- @computed_field # type: ignore[misc]
350
+ @computed_field
351
351
  @property
352
352
  def lines_of_credit_percentage(self) -> float:
353
353
  """Lines of credit as percentage of total liabilities."""
@@ -37,6 +37,8 @@ Usage:
37
37
 
38
38
  from __future__ import annotations
39
39
 
40
+ from typing import Callable
41
+
40
42
  # Financial capability prefix patterns (extensible)
41
43
  FINANCIAL_ROUTE_PREFIXES = (
42
44
  "/banking",
@@ -110,9 +112,9 @@ def financial_route_classifier(route_path: str, method: str) -> str:
110
112
 
111
113
 
112
114
  def compose_classifiers(
113
- *classifiers: callable,
115
+ *classifiers: Callable[[str], str],
114
116
  default: str = "public",
115
- ) -> callable:
117
+ ) -> Callable[[str], str]:
116
118
  """
117
119
  Compose multiple route classifiers with fallback logic.
118
120