eq-chatbot-core 3.2.0__tar.gz → 3.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. eq_chatbot_core-3.3.0/AGENTS.md +225 -0
  2. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/CHANGELOG.md +137 -0
  3. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/CLAUDE.md +2 -1
  4. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/PKG-INFO +6 -5
  5. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/README.md +4 -4
  6. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/RELEASE_NOTES.md +56 -0
  7. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/mcp.md +100 -16
  8. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/pyproject.toml +7 -0
  9. eq_chatbot_core-3.3.0/src/eq_chatbot_core/mcp/__init__.py +123 -0
  10. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/mcp/client.py +13 -5
  11. eq_chatbot_core-3.3.0/src/eq_chatbot_core/mcp/streamable_http.py +415 -0
  12. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/version.py +1 -1
  13. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/reports/latest.md +108 -53
  14. eq_chatbot_core-3.3.0/tests/unit/test_docs_extra_pyproject.py +61 -0
  15. eq_chatbot_core-3.3.0/tests/unit/test_mcp_streamable_http.py +439 -0
  16. eq_chatbot_core-3.2.0/src/eq_chatbot_core/mcp/__init__.py +0 -90
  17. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.claude/settings.local.json +0 -0
  18. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.github/workflows/ci.yml +0 -0
  19. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.gitignore +0 -0
  20. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/MILESTONES.md +0 -0
  21. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/PROJECT.md +0 -0
  22. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/REQUIREMENTS.md +0 -0
  23. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/ROADMAP.md +0 -0
  24. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/STATE.md +0 -0
  25. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/codebase/ARCHITECTURE.md +0 -0
  26. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/codebase/CONCERNS.md +0 -0
  27. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/codebase/CONVENTIONS.md +0 -0
  28. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/codebase/INTEGRATIONS.md +0 -0
  29. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/codebase/STACK.md +0 -0
  30. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/codebase/STRUCTURE.md +0 -0
  31. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/codebase/TESTING.md +0 -0
  32. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/config.json +0 -0
  33. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/00-codebase-cleanup/00-01-PLAN.md +0 -0
  34. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/00-codebase-cleanup/00-01-SUMMARY.md +0 -0
  35. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/00-codebase-cleanup/00-02-PLAN.md +0 -0
  36. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/00-codebase-cleanup/00-02-SUMMARY.md +0 -0
  37. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/00-codebase-cleanup/00-03-PLAN.md +0 -0
  38. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/00-codebase-cleanup/00-03-SUMMARY.md +0 -0
  39. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/00-codebase-cleanup/00-VERIFICATION.md +0 -0
  40. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-01-PLAN.md +0 -0
  41. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-01-SUMMARY.md +0 -0
  42. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-02-PLAN.md +0 -0
  43. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-02-SUMMARY.md +0 -0
  44. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-03-PLAN.md +0 -0
  45. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-03-SUMMARY.md +0 -0
  46. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-04-PLAN.md +0 -0
  47. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-04-SUMMARY.md +0 -0
  48. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-05-PLAN.md +0 -0
  49. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-05-SUMMARY.md +0 -0
  50. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-PATTERNS.md +0 -0
  51. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-RESEARCH.md +0 -0
  52. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-REVIEW-FIX.md +0 -0
  53. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-REVIEW.md +0 -0
  54. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-VALIDATION.md +0 -0
  55. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/01-contracts-foundation/01-VERIFICATION.md +0 -0
  56. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-01-PLAN.md +0 -0
  57. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-01-SUMMARY.md +0 -0
  58. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-02-PLAN.md +0 -0
  59. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-02-SUMMARY.md +0 -0
  60. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-03-PLAN.md +0 -0
  61. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-03-SUMMARY.md +0 -0
  62. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-CONTEXT.md +0 -0
  63. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-DISCUSSION-LOG.md +0 -0
  64. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-PATTERNS.md +0 -0
  65. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-RESEARCH.md +0 -0
  66. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-REVIEW.md +0 -0
  67. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-VALIDATION.md +0 -0
  68. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/02-openai-realtime-provider/02-VERIFICATION.md +0 -0
  69. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-01-PLAN.md +0 -0
  70. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-01-SUMMARY.md +0 -0
  71. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-02-PLAN.md +0 -0
  72. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-02-SUMMARY.md +0 -0
  73. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-03-PLAN.md +0 -0
  74. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-03-SUMMARY.md +0 -0
  75. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-04-PLAN.md +0 -0
  76. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-04-SUMMARY.md +0 -0
  77. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-05-PLAN.md +0 -0
  78. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-05-SUMMARY.md +0 -0
  79. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-CONTEXT.md +0 -0
  80. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-DISCUSSION-LOG.md +0 -0
  81. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-HUMAN-UAT.md +0 -0
  82. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-PATTERNS.md +0 -0
  83. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-RESEARCH.md +0 -0
  84. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-VALIDATION.md +0 -0
  85. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03-gemini-live-nova-sonic-stub/03-VERIFICATION.md +0 -0
  86. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/.gitkeep +0 -0
  87. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-01-PLAN.md +0 -0
  88. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-01-SUMMARY.md +0 -0
  89. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-02-PLAN.md +0 -0
  90. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-02-SUMMARY.md +0 -0
  91. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-03-PLAN.md +0 -0
  92. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-03-SUMMARY.md +0 -0
  93. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-CONTEXT.md +0 -0
  94. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-HUMAN-UAT.md +0 -0
  95. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-PATTERNS.md +0 -0
  96. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-RESEARCH.md +0 -0
  97. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-VALIDATION.md +0 -0
  98. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-VERIFICATION.md +0 -0
  99. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/research/ARCHITECTURE.md +0 -0
  100. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/research/FEATURES.md +0 -0
  101. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/research/PITFALLS.md +0 -0
  102. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/research/STACK.md +0 -0
  103. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.planning/research/SUMMARY.md +0 -0
  104. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.pre-commit-config.yaml +0 -0
  105. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/.project-tips +0 -0
  106. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/LICENSE +0 -0
  107. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/MANIFEST.in +0 -0
  108. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/TASKS.md +0 -0
  109. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/README.md +0 -0
  110. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/cli.md +0 -0
  111. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/providers.md +0 -0
  112. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/rag.md +0 -0
  113. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/reasoning.md +0 -0
  114. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/security.md +0 -0
  115. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/server-mode.md +0 -0
  116. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/superpowers/specs/2026-05-25-elevenlabs-realtime-provider-design.md +0 -0
  117. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/docs/testing.md +0 -0
  118. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/__init__.py +0 -0
  119. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/cli.py +0 -0
  120. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/data/__init__.py +0 -0
  121. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/data/capability_catalog.json +0 -0
  122. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/data/capability_overrides.json +0 -0
  123. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/data/config.toml.example +0 -0
  124. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/__init__.py +0 -0
  125. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/anthropic_provider.py +0 -0
  126. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/base.py +0 -0
  127. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/ionos_provider.py +0 -0
  128. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/langdock_provider.py +0 -0
  129. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/litellm_provider.py +0 -0
  130. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/local_provider.py +0 -0
  131. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/mammouth_provider.py +0 -0
  132. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/melious_provider.py +0 -0
  133. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/openai_compatible.py +0 -0
  134. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/openai_provider.py +0 -0
  135. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/openrouter_provider.py +0 -0
  136. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/privatemode_provider.py +0 -0
  137. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/stream_accumulator.py +0 -0
  138. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/providers/temperature_constraints.py +0 -0
  139. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/py.typed +0 -0
  140. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/rag/__init__.py +0 -0
  141. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/rag/chunker.py +0 -0
  142. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/rag/context_manager.py +0 -0
  143. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/rag/embedder.py +0 -0
  144. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/rag/retriever.py +0 -0
  145. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/__init__.py +0 -0
  146. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/abc.py +0 -0
  147. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/contracts.py +0 -0
  148. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/factory.py +0 -0
  149. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/mock.py +0 -0
  150. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/providers/__init__.py +0 -0
  151. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/providers/elevenlabs.py +0 -0
  152. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/providers/gemini_live.py +0 -0
  153. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/providers/openai.py +0 -0
  154. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/realtime/websocket_client.py +0 -0
  155. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/security/__init__.py +0 -0
  156. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/security/encryption.py +0 -0
  157. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/security/file_validator.py +0 -0
  158. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/security/injection.py +0 -0
  159. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/security/rate_limit.py +0 -0
  160. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/server/__init__.py +0 -0
  161. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/server/app.py +0 -0
  162. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/server/auth.py +0 -0
  163. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/server/lifecycle.py +0 -0
  164. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/server/models.py +0 -0
  165. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/server/streaming.py +0 -0
  166. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/services/__init__.py +0 -0
  167. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/services/capability_catalog.py +0 -0
  168. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/services/document_extractor.py +0 -0
  169. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/services/error_handler.py +0 -0
  170. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/services/knowledge_service.py +0 -0
  171. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/utils/__init__.py +0 -0
  172. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/utils/config.py +0 -0
  173. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/utils/image.py +0 -0
  174. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/utils/pdf.py +0 -0
  175. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/utils/secret_scrub.py +0 -0
  176. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/src/eq_chatbot_core/utils/url_validation.py +0 -0
  177. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/.env.example +0 -0
  178. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/INTEGRATION_TESTS.md +0 -0
  179. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/__init__.py +0 -0
  180. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/conftest.py +0 -0
  181. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/__init__.py +0 -0
  182. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_ionos_live.py +0 -0
  183. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_litellm_live.py +0 -0
  184. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_local_live.py +0 -0
  185. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_mammouth_live.py +0 -0
  186. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_mcp_live.py +0 -0
  187. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_melious_live.py +0 -0
  188. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_openai_live.py +0 -0
  189. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_openrouter_live.py +0 -0
  190. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_privatemode_live.py +0 -0
  191. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_realtime_elevenlabs.py +0 -0
  192. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_realtime_gemini_live.py +0 -0
  193. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/integration/test_realtime_openai_live.py +0 -0
  194. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/model_registry.py +0 -0
  195. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/__init__.py +0 -0
  196. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/__init__.py +0 -0
  197. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/conftest.py +0 -0
  198. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_contracts.py +0 -0
  199. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_factory.py +0 -0
  200. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_import_guard.py +0 -0
  201. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_mock.py +0 -0
  202. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_pyproject.py +0 -0
  203. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_realtime_elevenlabs.py +0 -0
  204. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_realtime_gemini.py +0 -0
  205. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_realtime_openai.py +0 -0
  206. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/realtime/test_websocket_client.py +0 -0
  207. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/server/__init__.py +0 -0
  208. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/server/test_app.py +0 -0
  209. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/server/test_auth.py +0 -0
  210. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/server/test_cli_serve.py +0 -0
  211. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/server/test_lifecycle.py +0 -0
  212. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/server/test_streaming.py +0 -0
  213. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_anthropic.py +0 -0
  214. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_anthropic_temperature_transport.py +0 -0
  215. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_capability_catalog.py +0 -0
  216. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_chunker.py +0 -0
  217. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_cli_api_key.py +0 -0
  218. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_cli_chat.py +0 -0
  219. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_cli_image.py +0 -0
  220. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_cli_listing_assets.py +0 -0
  221. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_config.py +0 -0
  222. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_context_manager.py +0 -0
  223. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_document_extractor.py +0 -0
  224. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_embedder.py +0 -0
  225. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_encryption.py +0 -0
  226. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_error_handler.py +0 -0
  227. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_exceptions.py +0 -0
  228. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_factory.py +0 -0
  229. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_file_validator.py +0 -0
  230. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_gpt5_temperature.py +0 -0
  231. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_injection.py +0 -0
  232. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_ionos.py +0 -0
  233. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_knowledge_service.py +0 -0
  234. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_langdock.py +0 -0
  235. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_langdock_agent_errors.py +0 -0
  236. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_langdock_agent_streaming.py +0 -0
  237. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_langdock_backends.py +0 -0
  238. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_langdock_google_models.py +0 -0
  239. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_langdock_http_error_detail.py +0 -0
  240. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_list_models_schema.py +0 -0
  241. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_litellm.py +0 -0
  242. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_local.py +0 -0
  243. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_mammouth.py +0 -0
  244. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_mcp.py +0 -0
  245. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_melious.py +0 -0
  246. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_openai.py +0 -0
  247. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_openai_image.py +0 -0
  248. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_openrouter.py +0 -0
  249. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_openrouter_error_handling.py +0 -0
  250. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_openrouter_image.py +0 -0
  251. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_pdf.py +0 -0
  252. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_privatemode.py +0 -0
  253. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_rate_limit.py +0 -0
  254. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_retriever.py +0 -0
  255. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_security_hardening.py +0 -0
  256. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_stream_accumulator.py +0 -0
  257. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_temperature_constraints.py +0 -0
  258. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_tool_normalization.py +0 -0
  259. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_url_validation.py +0 -0
  260. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_utils_image.py +0 -0
  261. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/tests/unit/test_websocket_is_connected.py +0 -0
  262. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/usage/AGENT.md +0 -0
  263. {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.3.0}/uv.lock +0 -0
@@ -0,0 +1,225 @@
1
+ # AGENTS.md
2
+
3
+ This file provides guidance to AI coding agents when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Standalone Python library for LLM chatbot integration. Provides unified API across multiple providers (OpenAI, Anthropic, LangDock, OpenRouter, local servers). Originally extracted from v18-chatbot Odoo project for independent PyPI publishing.
8
+
9
+ ## Commands
10
+
11
+ ### Development Setup
12
+
13
+ ```bash
14
+ uv venv && source .venv/bin/activate # or: venv+
15
+ uv pip install -e ".[dev,pdf,security]"
16
+ ```
17
+
18
+ ### Testing
19
+
20
+ ```bash
21
+ # Run all unit tests (fast, mocked)
22
+ pytest tests/unit/ -v
23
+
24
+ # Run all tests with coverage
25
+ pytest tests/ -v --cov=eq_chatbot_core --cov-report=html
26
+
27
+ # Run single test file
28
+ pytest tests/unit/test_openai.py -v
29
+
30
+ # Run single test function
31
+ pytest tests/unit/test_openai.py::TestOpenAIProviderInit::test_basic_init -v
32
+
33
+ # Run tests by marker
34
+ pytest -m unit -v # Unit tests only (mocked)
35
+ pytest -m integration -v # Integration tests (real API calls)
36
+ pytest -m local -v # Local server tests
37
+
38
+ # Skip expensive tests
39
+ SKIP_LIVE_TESTS=true pytest tests/ -v
40
+ ```
41
+
42
+ ### Linting
43
+
44
+ ```bash
45
+ ruff check src/ && ruff format src/ --check # Check only
46
+ ruff check src/ --fix && ruff format src/ # Auto-fix
47
+ mypy src/ # Type checking
48
+ ```
49
+
50
+ ### Building
51
+
52
+ ```bash
53
+ python -m build # Build package
54
+ twine check dist/* # Verify package
55
+ ```
56
+
57
+ ## Architecture
58
+
59
+ ### Provider Factory Pattern
60
+
61
+ All providers use a factory function with consistent interface:
62
+
63
+ ```python
64
+ from eq_chatbot_core.providers import get_provider
65
+
66
+ # Cloud providers
67
+ provider = get_provider("openai", api_key="sk-...")
68
+ provider = get_provider("anthropic", api_key="sk-ant-...")
69
+ provider = get_provider("langdock", api_key="ld-...")
70
+ provider = get_provider("openrouter", api_key="sk-or-...")
71
+ provider = get_provider("mammouth", api_key="mm-...")
72
+ provider = get_provider("litellm", api_key="...", base_url="https://gateway/v1") # OpenAI-compatible gateway
73
+ provider = get_provider("ionos", api_key="...") # IONOS AI Model Hub (EU-hosted, base_url has a default)
74
+ provider = get_provider("melious", api_key="sk-mel-...") # Melious.ai (sovereign EU-hosted, base_url has a default)
75
+ provider = get_provider("privatemode") # Privatemode.ai (end-to-end encrypted; needs the local privatemode-proxy on :8080)
76
+
77
+ # Local providers (LM Studio, Ollama)
78
+ provider = get_provider("lm_studio") # defaults to localhost:1234
79
+ provider = get_provider("ollama") # defaults to localhost:11434
80
+ provider = get_provider("local", base_url="http://custom:port/v1")
81
+ ```
82
+
83
+ ### Provider Base Class
84
+
85
+ All providers inherit from `BaseLLMProvider` and must implement:
86
+
87
+ ```python
88
+ class BaseLLMProvider(ABC):
89
+ provider_name: str # Property: "openai", "anthropic", etc.
90
+ default_model: str # Property: Default model ID
91
+
92
+ def chat_completion(messages, model, temperature, max_tokens, tools) -> LLMResponse
93
+ def stream_completion(messages, model, ...) -> Iterator[StreamChunk]
94
+ def list_models() -> list[dict]
95
+ ```
96
+
97
+ ### Response Types
98
+
99
+ - `LLMResponse`: Complete response with content, token counts, tool_calls
100
+ - `StreamChunk`: Streaming delta with is_final flag and accumulated tool_calls
101
+ - `ModelInfo`: Model metadata (id, context_length, supports_vision, etc.)
102
+
103
+ ### Exception Hierarchy
104
+
105
+ ```
106
+ ProviderError (base)
107
+ ├── RateLimitError # 429 errors, has retry_after
108
+ ├── AuthenticationError # 401/403 errors
109
+ ├── ContextLengthError # Token limit exceeded
110
+ └── OverloadedError # 529/503 transient errors (retryable)
111
+ ```
112
+
113
+ ### Module Structure
114
+
115
+ ```
116
+ src/eq_chatbot_core/
117
+ ├── providers/ # LLM adapters
118
+ │ ├── base.py # BaseLLMProvider, response types, exceptions
119
+ │ ├── openai_provider.py # OpenAI
120
+ │ ├── anthropic_provider.py
121
+ │ ├── langdock_provider.py # LangDock gateway (EU/US regions)
122
+ │ ├── openrouter_provider.py # OpenRouter (400+ models)
123
+ │ ├── litellm_provider.py # LiteLLM / any OpenAI-compatible gateway
124
+ │ ├── ionos_provider.py # IONOS AI Model Hub (EU-hosted, OpenAI-compatible)
125
+ │ ├── melious_provider.py # Melious.ai (sovereign EU-hosted, OpenAI-compatible)
126
+ │ ├── privatemode_provider.py # Privatemode.ai (E2E-encrypted, via local attesting proxy)
127
+ │ └── local_provider.py # LM Studio, Ollama (OpenAI-compatible)
128
+ ├── security/
129
+ │ ├── encryption.py # FernetEncryption for API key storage
130
+ │ ├── injection.py # Prompt injection detection
131
+ │ ├── rate_limit.py # Token bucket rate limiter
132
+ │ └── file_validator.py # MIME type validation (requires [security])
133
+ ├── rag/
134
+ │ ├── chunker.py # Text chunking strategies
135
+ │ ├── embedder.py # Embedding generation
136
+ │ ├── retriever.py # Qdrant vector retrieval
137
+ │ └── context_manager.py # RAG context assembly
138
+ ├── mcp/
139
+ │ ├── client.py # MCP client (legacy HTTP/SSE and stdio transports)
140
+ │ └── streamable_http.py # MCP client (Streamable HTTP, the current remote transport)
141
+ ├── services/
142
+ │ ├── error_handler.py # Centralized error handling
143
+ │ └── knowledge_service.py # Knowledge export for vector DBs
144
+ ├── utils/
145
+ │ ├── url_validation.py # SSRF / DNS-rebinding guard (shared by all providers)
146
+ │ └── pdf.py # PDF to image (requires [pdf])
147
+ ├── cli.py # Click CLI: eq-chatbot
148
+ └── version.py # Version string
149
+ ```
150
+
151
+ ## Testing Patterns
152
+
153
+ ### Unit Test Structure
154
+
155
+ Unit tests mock SDK clients at module level to avoid API calls:
156
+
157
+ ```python
158
+ import sys
159
+ from unittest.mock import MagicMock
160
+
161
+ # Mock before importing provider
162
+ mock_openai_module = MagicMock()
163
+ sys.modules["openai"] = mock_openai_module
164
+
165
+ from eq_chatbot_core.providers.openai_provider import OpenAIProvider
166
+ ```
167
+
168
+ ### Test Markers
169
+
170
+ - `@pytest.mark.unit` - Mocked tests, no external dependencies
171
+ - `@pytest.mark.integration` - Real API calls, requires keys
172
+ - `@pytest.mark.local` - Requires running LM Studio/Ollama
173
+ - `@pytest.mark.expensive` - Uses expensive models, skipped in CI
174
+ - `@pytest.mark.slow` - Long-running tests
175
+
176
+ ### Test Configuration
177
+
178
+ API keys come from `~/.config/eq-chatbot/config.toml` (`[providers.<name>].api_key`),
179
+ the same file the CLI uses. `conftest.py` mirrors them into `<NAME>_API_KEY` at
180
+ import; a real environment variable wins. `tests/.env.test` was removed in 3.1.0 —
181
+ it lived inside the repository, so the keys were one `git add -f` from publication.
182
+
183
+ - Keys: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `LANGDOCK_API_KEY`, `MAMMOUTH_API_KEY`, `IONOS_API_KEY`, `MELIOUS_API_KEY`, `PRIVATEMODE_API_KEY`, `LITELLM_API_KEY`, `OPENROUTER_API_KEY`
184
+ - `SKIP_LIVE_TESTS=true` - Skip integration tests (default false)
185
+ - `SKIP_LOCAL_TESTS=true` - Skip local server tests (default false)
186
+ - `<PROVIDER>_TEST_MODEL` - Override a model choice; defaults in `tests/model_registry.py`
187
+
188
+ ### Fixtures (conftest.py)
189
+
190
+ - `test_config` - Session config from environment
191
+ - `mock_openai_client`, `mock_anthropic_client` - Pre-configured mocks
192
+ - `sample_messages`, `minimal_test_messages` - Test data
193
+ - `openai_provider`, `anthropic_provider` - Live provider instances
194
+
195
+ ## Git Commit Conventions
196
+
197
+ - `[ADD]` - New features
198
+ - `[CHG]` - Modifications
199
+ - `[FIX]` - Bug fixes
200
+
201
+ ## Dependencies
202
+
203
+ ### Core (always installed)
204
+
205
+ openai (>=3), anthropic (>=1), httpx2, pydantic, cryptography, tiktoken, qdrant-client, click
206
+
207
+ One HTTP client library: `httpx2` (Pydantic's maintained continuation of httpx) carries this
208
+ library's own requests, the OpenAI SDK and — since anthropic 1.0.0 — the Anthropic SDK too.
209
+ The separate `httpx<1` dependency is gone; anthropic 1.0.0 rejects an httpx client with
210
+ `TypeError: Expected an instance of httpx2.Client`, so the floor is `>=1.0.0`.
211
+ `build_pinned_transport_for_url()` still takes an `http=` argument and works against either
212
+ module, which is why one guard implementation covers a future SDK that diverges again.
213
+
214
+ That release also removed `temperature`, `top_p` and `top_k` from `messages.create()` and
215
+ `messages.stream()`. Never write `params["temperature"]` for an Anthropic call — use
216
+ `apply_anthropic_temperature()` from `providers/temperature_constraints.py`, which clamps and
217
+ routes the value into `extra_body`.
218
+
219
+ ### Optional
220
+
221
+ - `[dev]` - pytest, ruff, mypy, twine, pytest-cov, pytest-asyncio
222
+ - `[security]` - puremagic (MIME validation)
223
+ - `[pdf]` - pymupdf (PDF to image conversion)
224
+ - `[rag]` - qdrant-client (Qdrant vector retrieval; optional since v3.0.0)
225
+ - `[local]` - sentence-transformers (local embeddings)
@@ -5,6 +5,143 @@ All notable changes to eq-chatbot-core will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.3.0] - 2026-09-08
9
+
10
+ ### Added
11
+
12
+ - **MCP client for the Streamable HTTP transport** (`mcp/streamable_http.py`,
13
+ `StreamableHTTPMCPClient`, factory `get_mcp_client(transport="http", ...)`). Until now the
14
+ library only spoke the HTTP+SSE transport of the 2024-11-05 spec (`GET /sse` plus a
15
+ server-announced POST URL). Current server SDKs - .NET, TypeScript, Python - offer Streamable
16
+ HTTP (spec 2025-03-26 and later) for remote operation: one POST endpoint such as
17
+ `http://host:5100/mcp`, answered with JSON or with an SSE stream. Against such a server the
18
+ old client ran into a connect timeout before it ever sent `initialize`. The new client reads
19
+ both answer shapes, carries a server-assigned `Mcp-Session-Id`, re-initialises once when the
20
+ server reports the session as gone (HTTP 404), and sends `MCP-Protocol-Version` after the
21
+ negotiation; stateless servers need none of that. `list_tools()` follows `nextCursor`
22
+ pagination; a tool reporting `isError: true` comes back as `success=False` with its text.
23
+ Same public surface as the SSE client, so callers switch without code changes. Verified
24
+ live against the official Python SDK 1.x in both modes (stateful with SSE answers, stateless
25
+ with JSON answers). `sse` and `stdio` are unchanged; the docs had promised
26
+ `transport="http"` all along, which the factory never accepted.
27
+ - **LAN mode for both HTTP transports** - `allow_private_ranges=True` on `get_mcp_client()`,
28
+ `MCPClient` and `StreamableHTTPMCPClient`. The SSRF check of the server URL always ran in
29
+ strict mode for MCP servers: private addresses, loopback and unresolvable hostnames were
30
+ rejected, so an MCP server on the company intranet was unreachable by construction even
31
+ though `validate_url()` has had a LAN mode for local LLM servers for a long time. In LAN
32
+ mode private and loopback targets become reachable and a hostname only the on-prem resolver
33
+ knows is accepted without an IP pin; link-local (cloud-metadata endpoint), reserved and
34
+ multicast addresses stay blocked. The SSE client applies the same mode to the POST URL it
35
+ receives in the `endpoint` event. Strict remains the default.
36
+
37
+ Tests: 1913 unit tests (52 new in `tests/unit/test_mcp_streamable_http.py`), mypy --strict clean.
38
+
39
+ ## [3.2.1] - 2026-08-24
40
+
41
+ ### Fixed
42
+
43
+ - **`.xlsx` conversion failed with an error about pandas.** The `[docs]` extra pulls
44
+ `markitdown[xlsx]`, which asks for a bare `openpyxl` and a bare `pandas` - no version on
45
+ either. The floor `openpyxl>=3.1.5` exists only inside pandas' own `excel` extra, and
46
+ markitdown does not request that extra, so nothing in the chain ever states it. A resolver
47
+ is therefore free to leave an older `openpyxl` in place, and Odoo pins exactly 3.1.2, so the
48
+ combination is not hypothetical - it is the normal case inside an Odoo install. Every
49
+ spreadsheet ended in:
50
+
51
+ XlsxConverter threw ImportError with message: Pandas requires version '3.1.5' or
52
+ newer of 'openpyxl' (version '3.1.2' currently installed).
53
+
54
+ Downstream that surfaces as "no text could be extracted", which names neither the library
55
+ nor the version. The `[docs]` extra now declares `openpyxl>=3.1.5,<4.0.0` itself.
56
+
57
+ Only `.xlsx` was affected - `.docx` goes through mammoth, `.pptx` through python-pptx and
58
+ `.pdf` through pymupdf, none of which route via pandas. Verified against all ten supported
59
+ extensions after the change.
60
+
61
+ ## [3.2.0] - 2026-08-23
62
+
63
+ ### Breaking
64
+
65
+ - **`anthropic` floor raised to >= 1.0.0; `httpx` is no longer a core dependency.**
66
+ The Anthropic SDK moved to `httpx2` in 1.0.0 and now rejects an `httpx` client outright
67
+ (`TypeError: Expected an instance of httpx2.Client`). Since `pyproject.toml` allowed
68
+ `<2.0.0`, a `pip install -U` would have silently broken the Anthropic provider. Both SDK
69
+ clients run on `httpx2` now, and the separate `httpx>=0.27,<1` dependency is gone — it
70
+ existed solely because of that one incompatibility.
71
+
72
+ The same SDK release **removed** `temperature`, `top_p` and `top_k` from `messages.create()`
73
+ and `messages.stream()`; passing one is a `TypeError`, not a warning. The SDK notes call this
74
+ "some minor breaking changes" — in practice every temperature-setting call failed. The new
75
+ helper `providers.temperature_constraints.apply_anthropic_temperature()` clamps the value and
76
+ routes it into `extra_body`. **Never write `params["temperature"]` for an Anthropic call again.**
77
+
78
+ ### Fixed
79
+
80
+ - **GPT-5 temperature support is not uniform — every call to `gpt-5`, `gpt-5.5` and the whole
81
+ current `gpt-5.6` tier failed with HTTP 400.** The constraint table carried a single permissive
82
+ `gpt-5` prefix declaring the entire family temperature-capable. Measured live on 23.08.2026:
83
+ `gpt-5` and `gpt-5-mini` refuse ("Only the default (1) value is supported"), `gpt-5.1`/`5.2`/`5.4`
84
+ accept, `gpt-5.5` and `gpt-5.6` refuse again. The generic prefix now says **no** and the
85
+ accepting generations are listed individually, so an untested future generation inherits "no
86
+ temperature" — omitting it never breaks, sending it does.
87
+
88
+ - **`get_temperature_constraints()` fell through to the permissive default for a prefixed model.**
89
+ `openai/gpt-5.6-luna` matched no entry, got 0.0-2.0, and was therefore sent a parameter the model
90
+ rejects. The function now strips the provider prefix itself instead of trusting every caller to.
91
+
92
+ - **LangDock agents really stream now.** `_agent_stream_completion` sent `"stream": false` and
93
+ yielded the finished answer as a single chunk — no streaming, and LangDock aborts non-streaming
94
+ requests after 100 seconds with HTTP 524, which an agent with tools or knowledge search reaches
95
+ easily. Both agent paths now go through `_agent_request_events()` and the AI SDK 5 data-stream
96
+ protocol; the synchronous path streams internally and assembles the answer itself. The parser
97
+ splits on the `data: ` marker rather than on line boundaries (LangDock glues events together) and
98
+ skips unparseable blocks instead of letting one kill a running answer.
99
+
100
+ - **The LangDock Google backend was entirely broken.** `list_models()` served a hand-maintained
101
+ catalogue (`gemini-2.5-flash`, `gemini-2.5-pro`) the gateway had retired — including the backend
102
+ default model, so every call without an explicit model ended in 400. The list now comes live from
103
+ the same endpoint the error came from. On top of that the streaming path silently yielded
104
+ **nothing**: the parser looks for SSE lines, but without `?alt=sse` LangDock answers with a JSON
105
+ array — no match, no chunks, no error. The parameter is now set.
106
+
107
+ - **Google and Codestral errors swallowed their own cause.** Both logged the response body and then
108
+ called `raise_for_status()`, so the caller saw only "Client error '400 Bad Request'" while the
109
+ actual reason — a retired model, a missing entitlement — sat in a log line. The shared
110
+ `_raise_http_error()` now appends the body without losing the typed mapping (401 stays
111
+ `AuthenticationError`, 429 `RateLimitError`).
112
+
113
+ - **The Agent API's HTTP 400 is translated.** It covers three entirely different cases: agent
114
+ unknown, agent not shared with the API key, or no model resolvable at all. The last happens when
115
+ the agent's model is set to "Auto" in LangDock — the auto-router works only in the chat UI, and a
116
+ top-level `model` demonstrably does not override it. The message now names the remedy in plain
117
+ words.
118
+
119
+ ### Changed
120
+
121
+ - **Every default model raised to the current generation.** Four were unusable or outdated:
122
+ `anthropic` pointed at `claude-sonnet-4-20250514` and `melious` at `minimax-428b-m3` — both
123
+ withdrawn — while `openai`, `mammouth` and `openrouter` still named `gpt-4o`. Now:
124
+ `gpt-5.6-luna`, `claude-sonnet-5`, `openai/gpt-5.6-luna`, `nemotron-3-nano-30b-a3b`. Three of
125
+ LangDock's four backend defaults were dead (`gpt-4o`, `claude-sonnet-4-20250514`,
126
+ `gemini-2.5-flash`).
127
+
128
+ A default model is the one unavoidable constant — everything else is resolved live. The new live
129
+ guards `TestProviderDefaultsAreLive` and `TestLangDockDefaultsAreLive` fail the moment a provider
130
+ stops serving one, and additionally check that it actually answers: being listed is not enough.
131
+
132
+ - **Dependency floors raised to the current release** (21 entries), among them
133
+ `sentence-transformers` 3 -> 6, `websockets` 13 -> 17.0.1, `pytest-asyncio` 0.24 -> 1.4,
134
+ `pytest` 8 -> 9.1.1, `mypy` 1.15 -> 2.3.1, `pytest-cov` 6 -> 7.1, `qdrant-client` 1.12 -> 1.19,
135
+ `fastapi` 0.115 -> 0.141, `uvicorn` 0.32 -> 0.52. An old floor is an open vulnerability waiting
136
+ for a fresh install. The suite runs green on all new majors without a code change.
137
+
138
+ - **Live coverage now spans all LangDock backends.** Only `openai` and `anthropic` were tested;
139
+ the Google backend speaks an entirely different protocol and was never touched live — which is
140
+ precisely why its defect went unnoticed. The Codestral path has no coverage any more: Mistral is
141
+ not of interest via LangDock.
142
+
143
+ **Test suite:** 1858 unit tests, 51 live tests (0 failures), mypy `--strict` clean.
144
+
8
145
  ## [3.1.1] - 2026-08-20
9
146
 
10
147
  ### Fixed
@@ -136,7 +136,8 @@ src/eq_chatbot_core/
136
136
  │ ├── retriever.py # Qdrant vector retrieval
137
137
  │ └── context_manager.py # RAG context assembly
138
138
  ├── mcp/
139
- │ └── client.py # MCP client (HTTP/SSE and stdio transports)
139
+ │ ├── client.py # MCP client (legacy HTTP/SSE and stdio transports)
140
+ │ └── streamable_http.py # MCP client (Streamable HTTP, the current remote transport)
140
141
  ├── services/
141
142
  │ ├── error_handler.py # Centralized error handling
142
143
  │ └── knowledge_service.py # Knowledge export for vector DBs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: eq-chatbot-core
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: Core library for LLM chatbot integration with multi-provider support (OpenAI, Anthropic, LangDock, OpenRouter, Mammouth, Azure, Vertex AI, LiteLLM, IONOS, Local)
5
5
  Project-URL: Homepage, https://www.ownerp.com
6
6
  Project-URL: Documentation, https://github.com/equitania/eq-chatbot-core
@@ -39,6 +39,7 @@ Requires-Dist: ruff<1.0.0,>=0.16.4; extra == 'dev'
39
39
  Requires-Dist: twine<8.0.0,>=7.0.0; extra == 'dev'
40
40
  Provides-Extra: docs
41
41
  Requires-Dist: markitdown[docx,pdf,pptx,xlsx]<0.2.0,>=0.1.7; extra == 'docs'
42
+ Requires-Dist: openpyxl<4.0.0,>=3.1.5; extra == 'docs'
42
43
  Requires-Dist: pymupdf<2.0.0,>=1.28.2; extra == 'docs'
43
44
  Provides-Extra: image
44
45
  Requires-Dist: pillow<13.0,>=12.3.0; extra == 'image'
@@ -85,7 +86,7 @@ Originally extracted from an Odoo 18 chatbot integration; works standalone witho
85
86
  - **Temperature Safety** — automatic model-specific temperature clamping
86
87
  - **Security** — Fernet encryption, prompt-injection detection (direct user input + indirect tool/RAG content), file-upload validation, race-free token-bucket rate limiting
87
88
  - **RAG Pipeline** — chunking, embeddings (incl. Melious.ai and IONOS embedders), Qdrant-backed retrieval, context-window management
88
- - **MCP Client** — HTTP/SSE and stdio transports, hardened against DNS rebinding, SSRF, and subprocess env injection
89
+ - **MCP Client** — Streamable HTTP, legacy HTTP/SSE and stdio transports, hardened against DNS rebinding, SSRF, and subprocess env injection; LAN mode for servers on the intranet
89
90
  - **CLI Tool** — provider testing, model discovery, programmatic JSON I/O chat
90
91
  - **Text-to-Image Generation** (v1.14.0) — `eq-chatbot image` (single PNG) and `eq-chatbot listing-assets` (batch from a recipe); OpenAI `gpt-image-1` and OpenRouter image models
91
92
  - **HTTP/SSE Server Mode** (v1.7.0) — run as a local sidecar (`eq-chatbot serve`) for cross-language integrations (Avalonia/.NET, Electron, native mobile)
@@ -162,7 +163,7 @@ For more — streaming, other providers, error handling — see [docs/providers.
162
163
  | CLI commands | [docs/cli.md](docs/cli.md#english) |
163
164
  | HTTP/SSE server mode | [docs/server-mode.md](docs/server-mode.md#english) |
164
165
  | Security (encryption, injection, files, rate limit) | [docs/security.md](docs/security.md#english) |
165
- | MCP client (HTTP/SSE + stdio) | [docs/mcp.md](docs/mcp.md#english) |
166
+ | MCP client (Streamable HTTP + SSE + stdio) | [docs/mcp.md](docs/mcp.md#english) |
166
167
  | RAG pipeline (chunking, embedding, retrieval) | [docs/rag.md](docs/rag.md#english) |
167
168
  | Testing (markers, integration setup, cost-aware patterns) | [docs/testing.md](docs/testing.md) |
168
169
 
@@ -289,7 +290,7 @@ Ursprünglich aus einer Odoo-18-Chatbot-Integration extrahiert; funktioniert sta
289
290
  - **Temperature-Sicherheit** — automatisches modellspezifisches Temperature-Clamping
290
291
  - **Sicherheit** — Fernet-Verschlüsselung, Prompt-Injection-Erkennung (direkte Nutzereingaben + indirekte Tool-/RAG-Inhalte), File-Upload-Validierung, Race-freies Token-Bucket-Rate-Limiting
291
292
  - **RAG-Pipeline** — Chunking, Embeddings (inkl. Melious.ai- und IONOS-Embedder), Qdrant-basiertes Retrieval, Context-Window-Management
292
- - **MCP-Client** — HTTP/SSE und stdio Transports, gehärtet gegen DNS-Rebinding, SSRF und Subprocess-Env-Injection
293
+ - **MCP-Client** — Streamable HTTP, älteres HTTP/SSE und stdio als Transports, gehärtet gegen DNS-Rebinding, SSRF und Subprocess-Env-Injection; LAN-Modus für Server im Intranet
293
294
  - **CLI-Tool** — Provider-Tests, Modell-Discovery, programmatische JSON-I/O-Chat-Calls
294
295
  - **Text-zu-Bild-Generierung** (v1.14.0) — `eq-chatbot image` (einzelnes PNG) und `eq-chatbot listing-assets` (Batch aus einer Recipe); OpenAI `gpt-image-1` und OpenRouter-Bildmodelle
295
296
  - **HTTP/SSE-Server-Mode** (v1.7.0) — lokaler Sidecar (`eq-chatbot serve`) für Cross-Language-Integrationen (Avalonia/.NET, Electron, native Mobile)
@@ -370,7 +371,7 @@ Für mehr — Streaming, andere Provider, Error-Handling — siehe [docs/provide
370
371
  | CLI-Befehle | [docs/cli.md](docs/cli.md#deutsch) |
371
372
  | HTTP/SSE-Server-Mode | [docs/server-mode.md](docs/server-mode.md#deutsch) |
372
373
  | Security (Verschlüsselung, Injection, Files, Rate-Limit) | [docs/security.md](docs/security.md#deutsch) |
373
- | MCP-Client (HTTP/SSE + stdio) | [docs/mcp.md](docs/mcp.md#deutsch) |
374
+ | MCP-Client (Streamable HTTP + SSE + stdio) | [docs/mcp.md](docs/mcp.md#deutsch) |
374
375
  | RAG-Pipeline (Chunking, Embedding, Retrieval) | [docs/rag.md](docs/rag.md#deutsch) |
375
376
  | Testing (Marker, Integration-Setup, Cost-Aware-Patterns) | [docs/testing.md](docs/testing.md) |
376
377
 
@@ -25,7 +25,7 @@ Originally extracted from an Odoo 18 chatbot integration; works standalone witho
25
25
  - **Temperature Safety** — automatic model-specific temperature clamping
26
26
  - **Security** — Fernet encryption, prompt-injection detection (direct user input + indirect tool/RAG content), file-upload validation, race-free token-bucket rate limiting
27
27
  - **RAG Pipeline** — chunking, embeddings (incl. Melious.ai and IONOS embedders), Qdrant-backed retrieval, context-window management
28
- - **MCP Client** — HTTP/SSE and stdio transports, hardened against DNS rebinding, SSRF, and subprocess env injection
28
+ - **MCP Client** — Streamable HTTP, legacy HTTP/SSE and stdio transports, hardened against DNS rebinding, SSRF, and subprocess env injection; LAN mode for servers on the intranet
29
29
  - **CLI Tool** — provider testing, model discovery, programmatic JSON I/O chat
30
30
  - **Text-to-Image Generation** (v1.14.0) — `eq-chatbot image` (single PNG) and `eq-chatbot listing-assets` (batch from a recipe); OpenAI `gpt-image-1` and OpenRouter image models
31
31
  - **HTTP/SSE Server Mode** (v1.7.0) — run as a local sidecar (`eq-chatbot serve`) for cross-language integrations (Avalonia/.NET, Electron, native mobile)
@@ -102,7 +102,7 @@ For more — streaming, other providers, error handling — see [docs/providers.
102
102
  | CLI commands | [docs/cli.md](docs/cli.md#english) |
103
103
  | HTTP/SSE server mode | [docs/server-mode.md](docs/server-mode.md#english) |
104
104
  | Security (encryption, injection, files, rate limit) | [docs/security.md](docs/security.md#english) |
105
- | MCP client (HTTP/SSE + stdio) | [docs/mcp.md](docs/mcp.md#english) |
105
+ | MCP client (Streamable HTTP + SSE + stdio) | [docs/mcp.md](docs/mcp.md#english) |
106
106
  | RAG pipeline (chunking, embedding, retrieval) | [docs/rag.md](docs/rag.md#english) |
107
107
  | Testing (markers, integration setup, cost-aware patterns) | [docs/testing.md](docs/testing.md) |
108
108
 
@@ -229,7 +229,7 @@ Ursprünglich aus einer Odoo-18-Chatbot-Integration extrahiert; funktioniert sta
229
229
  - **Temperature-Sicherheit** — automatisches modellspezifisches Temperature-Clamping
230
230
  - **Sicherheit** — Fernet-Verschlüsselung, Prompt-Injection-Erkennung (direkte Nutzereingaben + indirekte Tool-/RAG-Inhalte), File-Upload-Validierung, Race-freies Token-Bucket-Rate-Limiting
231
231
  - **RAG-Pipeline** — Chunking, Embeddings (inkl. Melious.ai- und IONOS-Embedder), Qdrant-basiertes Retrieval, Context-Window-Management
232
- - **MCP-Client** — HTTP/SSE und stdio Transports, gehärtet gegen DNS-Rebinding, SSRF und Subprocess-Env-Injection
232
+ - **MCP-Client** — Streamable HTTP, älteres HTTP/SSE und stdio als Transports, gehärtet gegen DNS-Rebinding, SSRF und Subprocess-Env-Injection; LAN-Modus für Server im Intranet
233
233
  - **CLI-Tool** — Provider-Tests, Modell-Discovery, programmatische JSON-I/O-Chat-Calls
234
234
  - **Text-zu-Bild-Generierung** (v1.14.0) — `eq-chatbot image` (einzelnes PNG) und `eq-chatbot listing-assets` (Batch aus einer Recipe); OpenAI `gpt-image-1` und OpenRouter-Bildmodelle
235
235
  - **HTTP/SSE-Server-Mode** (v1.7.0) — lokaler Sidecar (`eq-chatbot serve`) für Cross-Language-Integrationen (Avalonia/.NET, Electron, native Mobile)
@@ -310,7 +310,7 @@ Für mehr — Streaming, andere Provider, Error-Handling — siehe [docs/provide
310
310
  | CLI-Befehle | [docs/cli.md](docs/cli.md#deutsch) |
311
311
  | HTTP/SSE-Server-Mode | [docs/server-mode.md](docs/server-mode.md#deutsch) |
312
312
  | Security (Verschlüsselung, Injection, Files, Rate-Limit) | [docs/security.md](docs/security.md#deutsch) |
313
- | MCP-Client (HTTP/SSE + stdio) | [docs/mcp.md](docs/mcp.md#deutsch) |
313
+ | MCP-Client (Streamable HTTP + SSE + stdio) | [docs/mcp.md](docs/mcp.md#deutsch) |
314
314
  | RAG-Pipeline (Chunking, Embedding, Retrieval) | [docs/rag.md](docs/rag.md#deutsch) |
315
315
  | Testing (Marker, Integration-Setup, Cost-Aware-Patterns) | [docs/testing.md](docs/testing.md) |
316
316
 
@@ -1,5 +1,61 @@
1
1
  # Release Notes
2
2
 
3
+ ## Version 3.3.0 (08.09.2026)
4
+
5
+ ### [ADD]
6
+
7
+ - **MCP-Client für den Streamable-HTTP-Transport** (`mcp/streamable_http.py`,
8
+ `StreamableHTTPMCPClient`, Fabrik `get_mcp_client(transport="http", …)`). Bisher sprach die
9
+ Bibliothek nur den HTTP+SSE-Transport der Spec 2024-11-05 (`GET /sse`, vom Server gemeldete
10
+ POST-URL). Aktuelle Server-SDKs — .NET, TypeScript, Python — bieten für den Fernbetrieb
11
+ Streamable HTTP (Spec ab 2025-03-26): ein einziger POST-Endpunkt wie `http://host:5100/mcp`,
12
+ Antwort als JSON oder als SSE-Stream. Gegen so einen Server lief der alte Client in einen
13
+ Verbindungs-Timeout, bevor überhaupt ein `initialize` gesendet wurde. Der neue Client
14
+ liest beide Antwortformen, führt eine vom Server vergebene `Mcp-Session-Id` mit und
15
+ initialisiert einmal neu, wenn der Server die Sitzung mit HTTP 404 als abgelaufen meldet;
16
+ zustandslose Server brauchen nichts davon. Nach der Aushandlung sendet er
17
+ `MCP-Protocol-Version`. `list_tools()` folgt der `nextCursor`-Blätterung; ein Werkzeug mit
18
+ `isError: true` kommt als `success=False` samt Text zurück. Öffentliche Oberfläche wie beim
19
+ SSE-Client, daher ohne Änderung am Aufrufer austauschbar. Live geprüft gegen das offizielle
20
+ Python-SDK 1.x in beiden Betriebsarten (zustandsbehaftet mit SSE-Antworten, zustandslos mit
21
+ JSON-Antworten). Die Transportnamen `sse` und `stdio` bleiben unverändert; die Doku hatte
22
+ bereits `transport="http"` versprochen, das die Fabrik bis jetzt gar nicht kannte.
23
+ - **LAN-Modus für beide HTTP-Transports** — `allow_private_ranges=True` an
24
+ `get_mcp_client()`, `MCPClient` und `StreamableHTTPMCPClient`. Die SSRF-Prüfung der
25
+ Server-URL lief für MCP-Server immer im strikten Modus: private Adressen, Loopback und
26
+ nicht auflösbare Hostnamen wurden abgewiesen — ein MCP-Server im Firmen-Intranet war damit
27
+ grundsätzlich unerreichbar, obwohl `validate_url()` den LAN-Modus für lokale LLM-Server
28
+ längst kannte. Im LAN-Modus werden private und Loopback-Ziele erreichbar und ein nur intern
29
+ auflösbarer Hostname ohne IP-Pin akzeptiert; Link-Local (Cloud-Metadaten-Endpunkt),
30
+ reservierte und Multicast-Adressen bleiben gesperrt. Beim SSE-Client gilt derselbe Modus
31
+ auch für die im `endpoint`-Event gemeldete POST-URL. Standard bleibt strikt.
32
+
33
+ Tests: 1913 Unit-Tests (52 neu in `tests/unit/test_mcp_streamable_http.py`), mypy --strict
34
+ sauber.
35
+
36
+ ## Version 3.2.1 (24.08.2026)
37
+
38
+ ### [FIX]
39
+
40
+ - **Die Umwandlung von `.xlsx` scheiterte mit einer Meldung über pandas.** Das `[docs]`-Extra
41
+ zieht `markitdown[xlsx]`, und das verlangt schlicht „openpyxl" und „pandas" — ohne jede
42
+ Fassungsangabe. Die Untergrenze `openpyxl>=3.1.5` steht allein im `excel`-Extra von pandas,
43
+ das markitdown nicht anfordert; in der ganzen Kette nennt sie also niemand. Ein Auflöser darf
44
+ damit eine ältere Fassung stehen lassen, und Odoo legt sich genau auf 3.1.2 fest — die
45
+ Kombination ist demnach kein Sonderfall, sondern der Regelfall in einer Odoo-Installation.
46
+ Jede Tabellenkalkulation endete mit:
47
+
48
+ XlsxConverter threw ImportError with message: Pandas requires version '3.1.5' or
49
+ newer of 'openpyxl' (version '3.1.2' currently installed).
50
+
51
+ Beim Aufrufer kommt davon „Es konnte kein Text extrahiert werden" an — eine Meldung, die
52
+ weder die Bibliothek noch die Fassung nennt. Das `[docs]`-Extra verlangt jetzt selbst
53
+ `openpyxl>=3.1.5,<4.0.0`.
54
+
55
+ Betroffen war ausschließlich `.xlsx`: `.docx` läuft über mammoth, `.pptx` über python-pptx
56
+ und `.pdf` über pymupdf, keines davon über pandas. Nach der Änderung gegen alle zehn
57
+ unterstützten Endungen geprüft.
58
+
3
59
  ## Version 3.2.0 (23.08.2026)
4
60
 
5
61
  ### ⚠️ Breaking