GeneralManager 0.76.0__tar.gz → 0.77.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. {generalmanager-0.76.0/src/GeneralManager.egg-info → generalmanager-0.77.1}/PKG-INFO +1 -1
  2. {generalmanager-0.76.0 → generalmanager-0.77.1}/pyproject.toml +3 -1
  3. {generalmanager-0.76.0 → generalmanager-0.77.1/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/GeneralManager.egg-info/SOURCES.txt +16 -0
  5. generalmanager-0.77.1/src/general_manager/chat/audit.py +382 -0
  6. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/consumer.py +116 -2
  7. generalmanager-0.77.1/src/general_manager/chat/errors.py +46 -0
  8. generalmanager-0.77.1/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +320 -0
  9. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/diagnostics.py +53 -2
  10. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/fixtures.py +159 -2
  11. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/runner.py +377 -4
  12. generalmanager-0.77.1/src/general_manager/chat/planned/__init__.py +1 -0
  13. generalmanager-0.77.1/src/general_manager/chat/planned/budget.py +151 -0
  14. generalmanager-0.77.1/src/general_manager/chat/planned/calculations.py +234 -0
  15. generalmanager-0.77.1/src/general_manager/chat/planned/catalog.py +183 -0
  16. generalmanager-0.77.1/src/general_manager/chat/planned/config.py +251 -0
  17. generalmanager-0.77.1/src/general_manager/chat/planned/events.py +112 -0
  18. generalmanager-0.77.1/src/general_manager/chat/planned/evidence.py +320 -0
  19. generalmanager-0.77.1/src/general_manager/chat/planned/models.py +79 -0
  20. generalmanager-0.77.1/src/general_manager/chat/planned/planner.py +393 -0
  21. generalmanager-0.77.1/src/general_manager/chat/planned/provider_calls.py +130 -0
  22. generalmanager-0.77.1/src/general_manager/chat/planned/resolver.py +314 -0
  23. generalmanager-0.77.1/src/general_manager/chat/planned/routing.py +57 -0
  24. generalmanager-0.77.1/src/general_manager/chat/planned/scheduler.py +1361 -0
  25. generalmanager-0.77.1/src/general_manager/chat/planned/synthesis.py +296 -0
  26. generalmanager-0.77.1/src/general_manager/chat/planned/validation.py +455 -0
  27. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/providers/anthropic.py +31 -10
  28. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/providers/base.py +12 -2
  29. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/providers/google.py +31 -10
  30. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/providers/ollama.py +34 -12
  31. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/providers/openai.py +33 -12
  32. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/settings.py +17 -0
  33. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/tools.py +24 -2
  34. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/views.py +112 -29
  35. generalmanager-0.76.0/src/general_manager/chat/audit.py +0 -84
  36. generalmanager-0.76.0/src/general_manager/chat/errors.py +0 -23
  37. {generalmanager-0.76.0 → generalmanager-0.77.1}/LICENSE +0 -0
  38. {generalmanager-0.76.0 → generalmanager-0.77.1}/README.md +0 -0
  39. {generalmanager-0.76.0 → generalmanager-0.77.1}/setup.cfg +0 -0
  40. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  41. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/GeneralManager.egg-info/requires.txt +0 -0
  42. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/GeneralManager.egg-info/top_level.txt +0 -0
  43. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/__init__.py +0 -0
  44. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/__init__.py +0 -0
  45. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/api.py +0 -0
  46. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/bucket.py +0 -0
  47. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/cache.py +0 -0
  48. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/dataframes.py +0 -0
  49. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/factory.py +0 -0
  50. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/general_manager.py +0 -0
  51. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/interface.py +0 -0
  52. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/manager.py +0 -0
  53. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/measurement.py +0 -0
  54. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/permission.py +0 -0
  55. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/rule.py +0 -0
  56. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/search.py +0 -0
  57. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/_types/utils.py +0 -0
  58. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/__init__.py +0 -0
  59. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql.py +0 -0
  60. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_as_of.py +0 -0
  61. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_errors.py +0 -0
  62. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_mutations.py +0 -0
  63. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_output.py +0 -0
  64. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_prefetch.py +0 -0
  65. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_relations.py +0 -0
  66. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_resolvers.py +0 -0
  67. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_search.py +0 -0
  68. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  69. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_subscriptions.py +0 -0
  70. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_type.py +0 -0
  71. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_view.py +0 -0
  72. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_warmup.py +0 -0
  73. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_warmup_registry.py +0 -0
  74. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
  75. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/mutation.py +0 -0
  76. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/notification_batching.py +0 -0
  77. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/property.py +0 -0
  78. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/registry.py +0 -0
  79. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/remote_api.py +0 -0
  80. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/remote_invalidation.py +0 -0
  81. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/api/remote_invalidation_client.py +0 -0
  82. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/apps.py +0 -0
  83. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/as_of.py +0 -0
  84. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bootstrap.py +0 -0
  85. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/__init__.py +0 -0
  86. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/base_bucket.py +0 -0
  87. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/calculation_bucket.py +0 -0
  88. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/database_bucket.py +0 -0
  89. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/group_bucket.py +0 -0
  90. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/indexing.py +0 -0
  91. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/projection.py +0 -0
  92. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/bucket/request_bucket.py +0 -0
  93. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/__init__.py +0 -0
  94. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/cache_decorator.py +0 -0
  95. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/cache_tracker.py +0 -0
  96. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/data_change_context.py +0 -0
  97. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/dependency_cache.py +0 -0
  98. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/dependency_index.py +0 -0
  99. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/dependency_matching.py +0 -0
  100. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/dependency_publish.py +0 -0
  101. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/dependency_shards.py +0 -0
  102. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/model_dependency_collector.py +0 -0
  103. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/run_context.py +0 -0
  104. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/run_context_lru.py +0 -0
  105. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/cache/signals.py +0 -0
  106. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/__init__.py +0 -0
  107. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/bootstrap.py +0 -0
  108. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/checks.py +0 -0
  109. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/__init__.py +0 -0
  110. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/__main__.py +0 -0
  111. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/baseline.py +0 -0
  112. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
  113. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
  114. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
  115. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
  116. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
  117. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
  118. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/fingerprints.py +0 -0
  119. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/judges/__init__.py +0 -0
  120. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
  121. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/judges/contract.py +0 -0
  122. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
  123. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
  124. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/readiness.py +0 -0
  125. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/evals/traces.py +0 -0
  126. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/grounding.py +0 -0
  127. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/models.py +0 -0
  128. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/providers/__init__.py +0 -0
  129. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/providers/_shared.py +0 -0
  130. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/rate_limits.py +0 -0
  131. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/routing.py +0 -0
  132. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/schema_index.py +0 -0
  133. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/signals.py +0 -0
  134. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/system_prompt.py +0 -0
  135. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/chat/tool_metadata.py +0 -0
  136. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/conf.py +0 -0
  137. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/dataframes/__init__.py +0 -0
  138. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/dataframes/measurements.py +0 -0
  139. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/factory/__init__.py +0 -0
  140. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/factory/auto_factory.py +0 -0
  141. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/factory/factories.py +0 -0
  142. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/factory/factory_methods.py +0 -0
  143. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/__init__.py +0 -0
  144. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/base_interface.py +0 -0
  145. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/bundles/__init__.py +0 -0
  146. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/bundles/calculation.py +0 -0
  147. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/bundles/database.py +0 -0
  148. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  149. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/bundles/request.py +0 -0
  150. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/__init__.py +0 -0
  151. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/base.py +0 -0
  152. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/builtin.py +0 -0
  153. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  154. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  155. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
  156. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  157. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/configuration.py +0 -0
  158. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  159. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  160. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  161. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  162. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  163. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  164. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/factory.py +0 -0
  165. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  166. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  167. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  168. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  169. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  170. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  171. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  172. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  173. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  174. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  175. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  176. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  177. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
  178. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  179. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  180. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/registry.py +0 -0
  181. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  182. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  183. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  184. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  185. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  186. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/interfaces/__init__.py +0 -0
  187. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/interfaces/calculation.py +0 -0
  188. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/interfaces/database.py +0 -0
  189. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  190. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/interfaces/read_only.py +0 -0
  191. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  192. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/interfaces/request.py +0 -0
  193. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/manifests/__init__.py +0 -0
  194. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  195. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  196. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/manifests/capability_models.py +0 -0
  197. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/orm_interface.py +0 -0
  198. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/requests.py +0 -0
  199. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/utils/__init__.py +0 -0
  200. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  201. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/utils/errors.py +0 -0
  202. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/utils/history.py +0 -0
  203. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/interface/utils/models.py +0 -0
  204. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/logging.py +0 -0
  205. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/chat_cleanup.py +0 -0
  206. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
  207. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/graphql_warmup.py +0 -0
  208. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
  209. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/search_index.py +0 -0
  210. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/search_reconcile.py +0 -0
  211. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  212. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/shell.py +0 -0
  213. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  214. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  215. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/manager/__init__.py +0 -0
  216. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/manager/general_manager.py +0 -0
  217. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/manager/group_manager.py +0 -0
  218. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/manager/input.py +0 -0
  219. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/manager/meta.py +0 -0
  220. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/measurement/__init__.py +0 -0
  221. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/measurement/measurement.py +0 -0
  222. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/measurement/measurement_field.py +0 -0
  223. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/metrics/__init__.py +0 -0
  224. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/metrics/graphql.py +0 -0
  225. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0001_initial.py +0 -0
  226. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  227. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  228. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
  229. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0004_search_index_state.py +0 -0
  230. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
  231. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
  232. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0007_upload_intent.py +0 -0
  233. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
  234. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
  235. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
  236. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
  237. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/migrations/__init__.py +0 -0
  238. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/models.py +0 -0
  239. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/__init__.py +0 -0
  240. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/audit.py +0 -0
  241. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/base_permission.py +0 -0
  242. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/graphql_capabilities.py +0 -0
  243. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/manager_based_permission.py +0 -0
  244. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/mutation_permission.py +0 -0
  245. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/permission_checks.py +0 -0
  246. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/permission_data_manager.py +0 -0
  247. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/permission/utils.py +0 -0
  248. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/public_api_registry.py +0 -0
  249. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/py.typed +0 -0
  250. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/rule/__init__.py +0 -0
  251. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/rule/handler.py +0 -0
  252. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/rule/rule.py +0 -0
  253. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/__init__.py +0 -0
  254. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/async_tasks.py +0 -0
  255. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/backend.py +0 -0
  256. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/backend_registry.py +0 -0
  257. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/backends/__init__.py +0 -0
  258. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/backends/dev.py +0 -0
  259. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/backends/meilisearch.py +0 -0
  260. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/backends/opensearch.py +0 -0
  261. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/backends/typesense.py +0 -0
  262. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/checks.py +0 -0
  263. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/config.py +0 -0
  264. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/indexer.py +0 -0
  265. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/invalidation.py +0 -0
  266. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/m2m_invalidation.py +0 -0
  267. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/models.py +0 -0
  268. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/reconciliation.py +0 -0
  269. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/registry.py +0 -0
  270. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/tasks.py +0 -0
  271. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/search/utils.py +0 -0
  272. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/seeding/__init__.py +0 -0
  273. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/seeding/manager_landscape.py +0 -0
  274. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/__init__.py +0 -0
  275. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/adapters.py +0 -0
  276. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/checks.py +0 -0
  277. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/config.py +0 -0
  278. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/errors.py +0 -0
  279. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/finalization.py +0 -0
  280. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/graphql.py +0 -0
  281. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/graphql_types.py +0 -0
  282. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/metrics.py +0 -0
  283. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/models.py +0 -0
  284. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/public.py +0 -0
  285. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/s3.py +0 -0
  286. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/services.py +0 -0
  287. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/tokens.py +0 -0
  288. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/types.py +0 -0
  289. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/urls.py +0 -0
  290. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/uploads/views.py +0 -0
  291. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/__init__.py +0 -0
  292. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/args_to_kwargs.py +0 -0
  293. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/filter_parser.py +0 -0
  294. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/format_string.py +0 -0
  295. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/json_encoder.py +0 -0
  296. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/make_cache_key.py +0 -0
  297. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/none_to_zero.py +0 -0
  298. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/path_mapping.py +0 -0
  299. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/public_api.py +0 -0
  300. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/testing.py +0 -0
  301. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/utils/type_checks.py +0 -0
  302. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/__init__.py +0 -0
  303. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/actions.py +0 -0
  304. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/backend_registry.py +0 -0
  305. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/backends/__init__.py +0 -0
  306. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/backends/celery.py +0 -0
  307. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/backends/local.py +0 -0
  308. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/backends/n8n.py +0 -0
  309. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/config.py +0 -0
  310. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/engine.py +0 -0
  311. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/event_registry.py +0 -0
  312. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/events.py +0 -0
  313. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/models.py +0 -0
  314. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/signal_bridge.py +0 -0
  315. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/tasks.py +0 -0
  316. {generalmanager-0.76.0 → generalmanager-0.77.1}/src/general_manager/workflow/telemetry.py +0 -0
  317. {generalmanager-0.76.0 → generalmanager-0.77.1}/tests/test_settings.py +0 -0
  318. {generalmanager-0.76.0 → generalmanager-0.77.1}/tests/test_urls.py +0 -0
  319. {generalmanager-0.76.0 → generalmanager-0.77.1}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.76.0
3
+ Version: 0.77.1
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "GeneralManager"
7
- version = "0.76.0"
7
+ version = "0.77.1"
8
8
  description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
@@ -178,6 +178,8 @@ module = [
178
178
  "graphql",
179
179
  "graphql.*",
180
180
  "numpy",
181
+ "openai",
182
+ "openai.*",
181
183
  "pint",
182
184
  "pint.*",
183
185
  "prometheus_client",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.76.0
3
+ Version: 0.77.1
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License: MIT License
@@ -106,11 +106,27 @@ src/general_manager/chat/evals/datasets/edge_cases.yaml
106
106
  src/general_manager/chat/evals/datasets/follow_ups.yaml
107
107
  src/general_manager/chat/evals/datasets/large_schema.yaml
108
108
  src/general_manager/chat/evals/datasets/multi_hop.yaml
109
+ src/general_manager/chat/evals/datasets/planned_orchestration.yaml
109
110
  src/general_manager/chat/evals/judges/__init__.py
110
111
  src/general_manager/chat/evals/judges/answer_quality.py
111
112
  src/general_manager/chat/evals/judges/contract.py
112
113
  src/general_manager/chat/evals/judges/result_accuracy.py
113
114
  src/general_manager/chat/evals/judges/tool_sequence.py
115
+ src/general_manager/chat/planned/__init__.py
116
+ src/general_manager/chat/planned/budget.py
117
+ src/general_manager/chat/planned/calculations.py
118
+ src/general_manager/chat/planned/catalog.py
119
+ src/general_manager/chat/planned/config.py
120
+ src/general_manager/chat/planned/events.py
121
+ src/general_manager/chat/planned/evidence.py
122
+ src/general_manager/chat/planned/models.py
123
+ src/general_manager/chat/planned/planner.py
124
+ src/general_manager/chat/planned/provider_calls.py
125
+ src/general_manager/chat/planned/resolver.py
126
+ src/general_manager/chat/planned/routing.py
127
+ src/general_manager/chat/planned/scheduler.py
128
+ src/general_manager/chat/planned/synthesis.py
129
+ src/general_manager/chat/planned/validation.py
114
130
  src/general_manager/chat/providers/__init__.py
115
131
  src/general_manager/chat/providers/_shared.py
116
132
  src/general_manager/chat/providers/anthropic.py
@@ -0,0 +1,382 @@
1
+ """Audit helpers for chat interactions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from contextlib import suppress
6
+ import hashlib
7
+ import json
8
+ import math
9
+ from typing import Any
10
+
11
+ from django.utils.module_loading import import_string
12
+
13
+ from general_manager.chat.settings import get_chat_settings
14
+
15
+
16
+ _PLANNED_ROLES = frozenset(
17
+ (
18
+ "planner",
19
+ "simple_executor",
20
+ "complex_executor",
21
+ "synthesizer",
22
+ "fallback_executor",
23
+ )
24
+ )
25
+ _PLANNED_MATCH_SOURCES = frozenset(
26
+ (
27
+ "exact_name",
28
+ "exact_alias",
29
+ "catalog_domain",
30
+ "catalog_alias",
31
+ "catalog_use_when",
32
+ "schema_description",
33
+ "schema_field",
34
+ "schema_filter",
35
+ "schema_relation",
36
+ )
37
+ )
38
+ _PLANNED_PROGRESS = frozenset(
39
+ (
40
+ "candidate_changed",
41
+ "duplicate_rejected",
42
+ "evidence_added",
43
+ "no_progress",
44
+ "task_blocked",
45
+ "task_resolved",
46
+ )
47
+ )
48
+ _PLANNED_EVENT_FIELDS = {
49
+ "plan": frozenset(("plan_id", "task_count", "role", "trust_group_valid")),
50
+ "task_progress": frozenset(
51
+ (
52
+ "plan_id",
53
+ "task_id",
54
+ "root_task_id",
55
+ "parent_task_id",
56
+ "role",
57
+ "match_sources",
58
+ "canonical_call_identity",
59
+ "call_hash",
60
+ "duplicate",
61
+ "progress",
62
+ "local_passes",
63
+ "subtree_rounds_used",
64
+ "subtree_rounds_remaining",
65
+ "global_rounds_used",
66
+ "global_rounds_remaining",
67
+ "stage_latency_ms",
68
+ "task_latency_ms",
69
+ "input_tokens",
70
+ "output_tokens",
71
+ "reported_cost",
72
+ "evidence_counts",
73
+ "coverage",
74
+ "terminal_reason",
75
+ )
76
+ ),
77
+ "route": frozenset(
78
+ (
79
+ "plan_id",
80
+ "task_id",
81
+ "root_task_id",
82
+ "role",
83
+ "route",
84
+ "escalated",
85
+ "trust_group_valid",
86
+ )
87
+ ),
88
+ "candidate": frozenset(
89
+ (
90
+ "plan_id",
91
+ "task_id",
92
+ "match_sources",
93
+ "candidate_count",
94
+ "local_passes",
95
+ )
96
+ ),
97
+ "tool_call": frozenset(
98
+ (
99
+ "plan_id",
100
+ "task_id",
101
+ "canonical_call_identity",
102
+ "call_hash",
103
+ "duplicate",
104
+ )
105
+ ),
106
+ "tool_result": frozenset(
107
+ (
108
+ "plan_id",
109
+ "task_id",
110
+ "call_hash",
111
+ "duplicate",
112
+ "progress",
113
+ "evidence_counts",
114
+ )
115
+ ),
116
+ "budget": frozenset(
117
+ (
118
+ "plan_id",
119
+ "task_id",
120
+ "subtree_rounds_used",
121
+ "subtree_rounds_remaining",
122
+ "global_rounds_used",
123
+ "global_rounds_remaining",
124
+ )
125
+ ),
126
+ "latency": frozenset(
127
+ ("plan_id", "task_id", "stage", "stage_latency_ms", "task_latency_ms")
128
+ ),
129
+ "usage": frozenset(
130
+ ("plan_id", "task_id", "role", "input_tokens", "output_tokens", "reported_cost")
131
+ ),
132
+ "evidence": frozenset(("plan_id", "task_id", "evidence_counts", "progress")),
133
+ "coverage": frozenset(("plan_id", "coverage", "terminal_reason")),
134
+ "terminal": frozenset(("plan_id", "coverage", "terminal_reason")),
135
+ }
136
+ _PLANNED_REASONS = frozenset(
137
+ (
138
+ "invalid_plan",
139
+ "manager_unresolved",
140
+ "dependency_blocked",
141
+ "budget_exhausted",
142
+ "deadline_exceeded",
143
+ "provider_failed",
144
+ "synthesis_failed",
145
+ )
146
+ )
147
+
148
+
149
+ def _should_emit(event_type: str, level: str) -> bool:
150
+ if level == "off":
151
+ return False
152
+ if level == "messages":
153
+ return event_type in {"user_message", "assistant_message"}
154
+ return True
155
+
156
+
157
+ def _redact(value: Any, redact_fields: set[str]) -> Any:
158
+ if isinstance(value, dict):
159
+ redacted: dict[str, Any] = {}
160
+ for key, item in value.items():
161
+ lowered = str(key).lower()
162
+ if any(field in lowered for field in redact_fields):
163
+ redacted[str(key)] = "[REDACTED]"
164
+ else:
165
+ redacted[str(key)] = _redact(item, redact_fields)
166
+ return redacted
167
+ if isinstance(value, list):
168
+ return [_redact(item, redact_fields) for item in value]
169
+ return value
170
+
171
+
172
+ def _truncate_result(value: Any, max_result_size: int) -> str:
173
+ serialized = json.dumps(value, sort_keys=True)
174
+ if len(serialized) <= max_result_size:
175
+ return serialized
176
+ return f"{serialized[:max_result_size]}..."
177
+
178
+
179
+ def _resolve_sink() -> Any:
180
+ audit_settings = get_chat_settings()["audit"]
181
+ logger_path = audit_settings.get("logger")
182
+ if logger_path is None:
183
+ return None
184
+ if callable(logger_path):
185
+ return logger_path
186
+ return import_string(str(logger_path))
187
+
188
+
189
+ def emit_chat_audit_event(
190
+ event_type: str,
191
+ payload: dict[str, Any],
192
+ *,
193
+ sink: Any | None = None,
194
+ ) -> None:
195
+ """Emit one sanitized chat audit event when chat audit logging is enabled."""
196
+ audit_settings = get_chat_settings()["audit"]
197
+ if not audit_settings.get("enabled"):
198
+ return
199
+ level = str(audit_settings.get("level", "off"))
200
+ if not _should_emit(event_type, level):
201
+ return
202
+
203
+ redact_fields = {
204
+ str(field).lower() for field in audit_settings.get("redact_fields", [])
205
+ }
206
+ sanitized = _redact(payload, redact_fields)
207
+ if "result" in sanitized:
208
+ sanitized["result"] = _truncate_result(
209
+ sanitized["result"],
210
+ int(audit_settings.get("max_result_size", 4096)),
211
+ )
212
+ event = {"event_type": event_type, **sanitized}
213
+
214
+ with suppress(Exception):
215
+ target = sink if sink is not None else _resolve_sink()
216
+ if target is None:
217
+ return
218
+ if callable(target):
219
+ target(event)
220
+
221
+
222
+ def _planned_nonnegative_int(value: object) -> int | None:
223
+ if isinstance(value, bool) or not isinstance(value, int) or value < 0:
224
+ return None
225
+ return value
226
+
227
+
228
+ def _planned_identifier(value: object) -> str | None:
229
+ if not isinstance(value, str) or not value or len(value) > 128:
230
+ return None
231
+ return value
232
+
233
+
234
+ def planned_audit_lineage_id(value: object) -> str | None:
235
+ """Return a deterministic opaque audit identifier for planner-controlled IDs."""
236
+ identifier = _planned_identifier(value)
237
+ if identifier is None:
238
+ return None
239
+ return hashlib.sha256(identifier.encode()).hexdigest()
240
+
241
+
242
+ def _planned_count_mapping(value: object, allowed: set[str]) -> dict[str, int] | None:
243
+ if not isinstance(value, dict):
244
+ return None
245
+ safe: dict[str, int] = {}
246
+ for key, item in value.items():
247
+ if key not in allowed or (number := _planned_nonnegative_int(item)) is None:
248
+ return None
249
+ safe[key] = number
250
+ return safe
251
+
252
+
253
+ def _planned_cost(value: object) -> str | float | int | None:
254
+ if isinstance(value, bool):
255
+ return None
256
+ if isinstance(value, (int, float)):
257
+ return value if math.isfinite(value) and value >= 0 else None
258
+ if isinstance(value, str) and len(value) <= 32:
259
+ try:
260
+ parsed = float(value)
261
+ except ValueError:
262
+ return None
263
+ return value if math.isfinite(parsed) and parsed >= 0 else None
264
+ return None
265
+
266
+
267
+ def _sanitize_planned_audit_payload(
268
+ event_type: str, payload: dict[str, Any]
269
+ ) -> dict[str, Any]:
270
+ """Return the category-specific planned audit allowlist, never a copy."""
271
+ allowed = _PLANNED_EVENT_FIELDS.get(event_type)
272
+ if allowed is None:
273
+ return {}
274
+ sanitized: dict[str, Any] = {}
275
+ for key in ("plan_id", "task_id", "root_task_id", "parent_task_id"):
276
+ if (
277
+ key in allowed
278
+ and (value := planned_audit_lineage_id(payload.get(key))) is not None
279
+ ):
280
+ sanitized[key] = value
281
+ if "role" in allowed and payload.get("role") in _PLANNED_ROLES:
282
+ sanitized["role"] = payload["role"]
283
+ if "route" in allowed and payload.get("route") in {"selected", "escalated"}:
284
+ sanitized["route"] = payload["route"]
285
+ for key in ("duplicate", "escalated", "trust_group_valid"):
286
+ if key in allowed and isinstance(payload.get(key), bool):
287
+ sanitized[key] = payload[key]
288
+ if "match_sources" in allowed and isinstance(payload.get("match_sources"), list):
289
+ sources = payload["match_sources"]
290
+ if all(
291
+ isinstance(item, str) and item in _PLANNED_MATCH_SOURCES for item in sources
292
+ ):
293
+ sanitized["match_sources"] = list(sources)
294
+ if "canonical_call_identity" in allowed and isinstance(
295
+ payload.get("canonical_call_identity"), str
296
+ ):
297
+ sanitized["call_hash"] = hashlib.sha256(
298
+ payload["canonical_call_identity"].encode()
299
+ ).hexdigest()
300
+ elif "call_hash" in allowed and isinstance(payload.get("call_hash"), str):
301
+ call_hash = payload["call_hash"]
302
+ if len(call_hash) == 64 and all(
303
+ char in "0123456789abcdef" for char in call_hash
304
+ ):
305
+ sanitized["call_hash"] = call_hash
306
+ if "progress" in allowed and payload.get("progress") in _PLANNED_PROGRESS:
307
+ sanitized["progress"] = payload["progress"]
308
+ for key in (
309
+ "task_count",
310
+ "candidate_count",
311
+ "local_passes",
312
+ "subtree_rounds_used",
313
+ "subtree_rounds_remaining",
314
+ "global_rounds_used",
315
+ "global_rounds_remaining",
316
+ "stage_latency_ms",
317
+ "task_latency_ms",
318
+ "input_tokens",
319
+ "output_tokens",
320
+ ):
321
+ if (
322
+ key in allowed
323
+ and (number := _planned_nonnegative_int(payload.get(key))) is not None
324
+ ):
325
+ sanitized[key] = number
326
+ if "stage" in allowed and payload.get("stage") in {
327
+ "planning",
328
+ "evidence",
329
+ "synthesis",
330
+ }:
331
+ sanitized["stage"] = payload["stage"]
332
+ if (
333
+ "reported_cost" in allowed
334
+ and (cost := _planned_cost(payload.get("reported_cost"))) is not None
335
+ ):
336
+ sanitized["reported_cost"] = cost
337
+ if (
338
+ "evidence_counts" in allowed
339
+ and (
340
+ evidence_counts := _planned_count_mapping(
341
+ payload.get("evidence_counts"),
342
+ {"schema", "path", "query", "calculation"},
343
+ )
344
+ )
345
+ is not None
346
+ ):
347
+ sanitized["evidence_counts"] = evidence_counts
348
+ if (
349
+ "coverage" in allowed
350
+ and (
351
+ coverage := _planned_count_mapping(
352
+ payload.get("coverage"), {"resolved", "total"}
353
+ )
354
+ )
355
+ is not None
356
+ and set(coverage) == {"resolved", "total"}
357
+ and coverage["resolved"] <= coverage["total"]
358
+ ):
359
+ sanitized["coverage"] = coverage
360
+ if (
361
+ "terminal_reason" in allowed
362
+ and payload.get("terminal_reason") in _PLANNED_REASONS
363
+ ):
364
+ sanitized["terminal_reason"] = payload["terminal_reason"]
365
+ return sanitized
366
+
367
+
368
+ def emit_planned_audit_event(
369
+ event_type: str,
370
+ payload: dict[str, Any],
371
+ *,
372
+ sink: Any | None = None,
373
+ ) -> None:
374
+ """Emit only category-approved planned diagnostics through the generic sink."""
375
+ if event_type not in _PLANNED_EVENT_FIELDS:
376
+ return
377
+ with suppress(Exception):
378
+ emit_chat_audit_event(
379
+ f"planned_{event_type}",
380
+ _sanitize_planned_audit_payload(event_type, payload),
381
+ sink=sink,
382
+ )
@@ -20,6 +20,13 @@ from general_manager.chat.grounding import (
20
20
  should_recover_answer_without_query,
21
21
  should_recover_missing_tool_call,
22
22
  )
23
+ from general_manager.chat.planned.catalog import load_manager_catalog
24
+ from general_manager.chat.planned.config import get_planned_chat_settings
25
+ from general_manager.chat.planned.scheduler import (
26
+ SchedulerCallbacks,
27
+ iter_planned_read_events,
28
+ prepare_planned_turn,
29
+ )
23
30
  from general_manager.chat.providers.base import (
24
31
  DoneEvent,
25
32
  Message,
@@ -27,6 +34,7 @@ from general_manager.chat.providers.base import (
27
34
  ToolCallEvent,
28
35
  ToolDefinition,
29
36
  )
37
+ from general_manager.chat.schema_index import build_schema_index
30
38
  from general_manager.chat.rate_limits import enforce_chat_rate_limit
31
39
  from general_manager.chat.signals import (
32
40
  emit_chat_error,
@@ -262,6 +270,11 @@ class ChatConsumer(_ChatConsumerBase):
262
270
  await provider_task
263
271
  except asyncio.CancelledError:
264
272
  pass
273
+ if self._provider_task is provider_task:
274
+ self._provider_task = None
275
+ active_turn = getattr(self, "_active_turn", None)
276
+ if active_turn is not None and not active_turn.done():
277
+ active_turn.set_result(None)
265
278
  await self._cancel_confirmation_timeout()
266
279
  await super().disconnect(code)
267
280
 
@@ -327,6 +340,7 @@ class ChatConsumer(_ChatConsumerBase):
327
340
  return
328
341
  loop = asyncio.get_running_loop()
329
342
  self._active_turn = loop.create_future()
343
+ started_background_turn = False
330
344
  try:
331
345
  if self.conversation is None:
332
346
  self.conversation = await self._get_persistent_conversation()
@@ -357,7 +371,9 @@ class ChatConsumer(_ChatConsumerBase):
357
371
  message=text,
358
372
  conversation_id=getattr(self.conversation, "pk", None),
359
373
  )
360
- await self._stream_provider_turn(messages, history, tool_retries=0)
374
+ started_background_turn = await self._stream_message_turn(
375
+ text, messages, history
376
+ )
361
377
  except Exception as exc: # noqa: BLE001
362
378
  emit_chat_error(
363
379
  user=self.scope.get("user"),
@@ -366,7 +382,11 @@ class ChatConsumer(_ChatConsumerBase):
366
382
  )
367
383
  await self.send_json(public_chat_error(exc).as_event())
368
384
  finally:
369
- if self._active_turn is not None and not self._active_turn.done():
385
+ if (
386
+ not started_background_turn
387
+ and self._active_turn is not None
388
+ and not self._active_turn.done()
389
+ ):
370
390
  self._active_turn.set_result(None)
371
391
 
372
392
  async def _stream_provider_turn(
@@ -526,6 +546,100 @@ class ChatConsumer(_ChatConsumerBase):
526
546
  finally:
527
547
  self._provider_task = None
528
548
 
549
+ @staticmethod
550
+ def _planned_catalog_summary(settings: Any) -> dict[str, Any]:
551
+ """Build inert catalog/schema reference data for the planner request."""
552
+ schema_index = build_schema_index()
553
+ catalog = load_manager_catalog(
554
+ getattr(settings, "catalog_source", None), schema_index
555
+ )
556
+ return {
557
+ "catalog": {
558
+ name: {
559
+ "domain": entry.domain,
560
+ "aliases": list(entry.aliases),
561
+ "use_when": entry.use_when,
562
+ "distinguish_from": list(entry.distinguish_from),
563
+ }
564
+ for name, entry in catalog.entries.items()
565
+ },
566
+ "schema": schema_index,
567
+ }
568
+
569
+ async def _stream_message_turn(
570
+ self,
571
+ text: str,
572
+ messages: list[Message],
573
+ history: list[dict[str, str]],
574
+ ) -> bool:
575
+ """Plan after admission, retaining the unchanged legacy turn as fallback."""
576
+ planned_settings = get_planned_chat_settings()
577
+ if not planned_settings.enabled:
578
+ await self._stream_provider_turn(messages, history, tool_retries=0)
579
+ return False
580
+ self._provider_task = asyncio.create_task(
581
+ self._stream_planned_turn(text, messages, history, planned_settings)
582
+ )
583
+ return True
584
+
585
+ async def _stream_planned_turn(
586
+ self,
587
+ text: str,
588
+ messages: list[Message],
589
+ history: list[dict[str, str]],
590
+ planned_settings: Any,
591
+ ) -> None:
592
+ """Own planning and execution in one cancellable websocket task."""
593
+ planned_messages = messages
594
+ callbacks = SchedulerCallbacks(enforce_rate_limit=enforce_chat_rate_limit)
595
+ try:
596
+ if self.conversation is not None:
597
+ from general_manager.chat.models import build_conversation_context
598
+
599
+ context = await sync_to_async(build_conversation_context)(
600
+ self.conversation
601
+ )
602
+ planned_messages = [
603
+ Message(role="system", content=build_system_prompt()),
604
+ *(
605
+ Message(role=item.role, content=item.content)
606
+ for item in context
607
+ ),
608
+ ]
609
+ planned_turn = await prepare_planned_turn(
610
+ text,
611
+ planned_messages,
612
+ planned_settings,
613
+ self._planned_catalog_summary(planned_settings),
614
+ callbacks=callbacks,
615
+ scope=self.scope,
616
+ )
617
+ if planned_turn.mutation_plan is not None:
618
+ await self._stream_provider_turn(messages, history, tool_retries=0)
619
+ return
620
+ async for event in iter_planned_read_events(
621
+ planned_turn,
622
+ scope=self.scope,
623
+ conversation=self.conversation,
624
+ messages=planned_messages,
625
+ callbacks=callbacks,
626
+ ):
627
+ await self.send_json(event)
628
+ except asyncio.CancelledError:
629
+ raise
630
+ except Exception as exc: # noqa: BLE001
631
+ emit_chat_error(
632
+ user=self.scope.get("user"),
633
+ error=exc,
634
+ context={"transport": "websocket", "session_key": self.session_key},
635
+ )
636
+ await self.send_json(public_chat_error(exc).as_event())
637
+ finally:
638
+ if self._provider_task is asyncio.current_task():
639
+ self._provider_task = None
640
+ if self._active_turn is not None and not self._active_turn.done():
641
+ self._active_turn.set_result(None)
642
+
529
643
  async def _handle_tool_call(
530
644
  self,
531
645
  event: ToolCallEvent,
@@ -0,0 +1,46 @@
1
+ """Public chat error mapping."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Any
7
+
8
+
9
+ PLANNED_PUBLIC_MESSAGES = {
10
+ "invalid_plan": "I could not prepare a safe plan for that request.",
11
+ "manager_unresolved": "I could not resolve the required application data.",
12
+ "dependency_blocked": "A required part of the request could not be completed.",
13
+ "budget_exhausted": "The request reached its execution limit.",
14
+ "deadline_exceeded": "The request reached its time limit.",
15
+ "provider_failed": "The provider could not complete the request.",
16
+ "synthesis_failed": "I could not produce a grounded answer from the available data.",
17
+ }
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class PublicChatError:
22
+ """Sanitized chat error safe to return to clients."""
23
+
24
+ code: str
25
+ message: str
26
+
27
+ def as_event(self) -> dict[str, Any]:
28
+ """Render the error as the public chat event payload."""
29
+ return {"type": "error", "message": self.message, "code": self.code}
30
+
31
+
32
+ def public_chat_error(_exc: Exception) -> PublicChatError:
33
+ """Map an internal exception to a generic public chat error."""
34
+ planned_reason = getattr(_exc, "public_reason", None)
35
+ if isinstance(planned_reason, str):
36
+ return planned_public_error(planned_reason)
37
+ if isinstance(_exc, TimeoutError):
38
+ return planned_public_error("deadline_exceeded")
39
+ return PublicChatError("chat_error", "Chat request failed.")
40
+
41
+
42
+ def planned_public_error(reason: object) -> PublicChatError:
43
+ """Map a stable planned terminal reason without exposing internal details."""
44
+ if isinstance(reason, str) and reason in PLANNED_PUBLIC_MESSAGES:
45
+ return PublicChatError(reason, PLANNED_PUBLIC_MESSAGES[reason])
46
+ return PublicChatError("chat_error", "Chat request failed.")