eq-chatbot-core 3.2.0__tar.gz → 3.2.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.
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/CHANGELOG.md +106 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/PKG-INFO +2 -1
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/RELEASE_NOTES.md +23 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/pyproject.toml +7 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/version.py +1 -1
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/reports/latest.md +57 -54
- eq_chatbot_core-3.2.1/tests/unit/test_docs_extra_pyproject.py +61 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.claude/settings.local.json +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.github/workflows/ci.yml +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.gitignore +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/MILESTONES.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/PROJECT.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/REQUIREMENTS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/ROADMAP.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/STATE.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/codebase/ARCHITECTURE.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/codebase/CONCERNS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/codebase/CONVENTIONS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/codebase/INTEGRATIONS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/codebase/STACK.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/codebase/STRUCTURE.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/codebase/TESTING.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/config.json +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-01-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-01-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-02-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-02-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-03-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-03-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-VERIFICATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-01-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-01-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-02-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-02-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-03-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-03-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-04-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-04-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-05-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-05-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-PATTERNS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-RESEARCH.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-REVIEW-FIX.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-REVIEW.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-VALIDATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/01-contracts-foundation/01-VERIFICATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-01-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-01-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-02-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-02-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-03-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-03-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-CONTEXT.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-DISCUSSION-LOG.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-PATTERNS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-RESEARCH.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-REVIEW.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-VALIDATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/02-openai-realtime-provider/02-VERIFICATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-01-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-01-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-02-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-02-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-03-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-03-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-04-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-04-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-05-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-05-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-CONTEXT.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-DISCUSSION-LOG.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-HUMAN-UAT.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-PATTERNS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-RESEARCH.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-VALIDATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03-gemini-live-nova-sonic-stub/03-VERIFICATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/.gitkeep +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-01-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-01-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-02-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-02-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-03-PLAN.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-03-SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-CONTEXT.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-HUMAN-UAT.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-PATTERNS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-RESEARCH.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-VALIDATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/03.1-elevenlabs-agents-realtime-provider/03.1-VERIFICATION.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/research/ARCHITECTURE.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/research/FEATURES.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/research/PITFALLS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/research/STACK.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/research/SUMMARY.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.pre-commit-config.yaml +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.project-tips +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/CLAUDE.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/LICENSE +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/MANIFEST.in +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/README.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/TASKS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/README.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/cli.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/mcp.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/providers.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/rag.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/reasoning.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/security.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/server-mode.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/superpowers/specs/2026-05-25-elevenlabs-realtime-provider-design.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/docs/testing.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/cli.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/data/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/data/capability_catalog.json +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/data/capability_overrides.json +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/data/config.toml.example +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/mcp/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/mcp/client.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/anthropic_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/base.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/ionos_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/langdock_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/litellm_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/local_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/mammouth_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/melious_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/openai_compatible.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/openai_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/openrouter_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/privatemode_provider.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/stream_accumulator.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/providers/temperature_constraints.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/py.typed +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/rag/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/rag/chunker.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/rag/context_manager.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/rag/embedder.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/rag/retriever.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/abc.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/contracts.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/factory.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/mock.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/providers/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/providers/elevenlabs.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/providers/gemini_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/providers/openai.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/realtime/websocket_client.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/security/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/security/encryption.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/security/file_validator.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/security/injection.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/security/rate_limit.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/server/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/server/app.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/server/auth.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/server/lifecycle.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/server/models.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/server/streaming.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/services/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/services/capability_catalog.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/services/document_extractor.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/services/error_handler.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/services/knowledge_service.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/utils/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/utils/config.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/utils/image.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/utils/pdf.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/utils/secret_scrub.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/src/eq_chatbot_core/utils/url_validation.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/.env.example +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/INTEGRATION_TESTS.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/conftest.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_ionos_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_litellm_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_local_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_mammouth_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_mcp_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_melious_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_openai_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_openrouter_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_privatemode_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_realtime_elevenlabs.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_realtime_gemini_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/integration/test_realtime_openai_live.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/model_registry.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/conftest.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_contracts.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_factory.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_import_guard.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_mock.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_pyproject.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_realtime_elevenlabs.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_realtime_gemini.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_realtime_openai.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/realtime/test_websocket_client.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/server/__init__.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/server/test_app.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/server/test_auth.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/server/test_cli_serve.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/server/test_lifecycle.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/server/test_streaming.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_anthropic.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_anthropic_temperature_transport.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_capability_catalog.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_chunker.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_cli_api_key.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_cli_chat.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_cli_image.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_cli_listing_assets.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_config.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_context_manager.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_document_extractor.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_embedder.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_encryption.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_error_handler.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_exceptions.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_factory.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_file_validator.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_gpt5_temperature.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_injection.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_ionos.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_knowledge_service.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_langdock.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_langdock_agent_errors.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_langdock_agent_streaming.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_langdock_backends.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_langdock_google_models.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_langdock_http_error_detail.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_list_models_schema.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_litellm.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_local.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_mammouth.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_mcp.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_melious.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_openai.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_openai_image.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_openrouter.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_openrouter_error_handling.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_openrouter_image.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_pdf.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_privatemode.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_rate_limit.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_retriever.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_security_hardening.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_stream_accumulator.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_temperature_constraints.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_tool_normalization.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_url_validation.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_utils_image.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/tests/unit/test_websocket_is_connected.py +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/usage/AGENT.md +0 -0
- {eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/uv.lock +0 -0
|
@@ -5,6 +5,112 @@ 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.2.1] - 2026-08-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **`.xlsx` conversion failed with an error about pandas.** The `[docs]` extra pulls
|
|
13
|
+
`markitdown[xlsx]`, which asks for a bare `openpyxl` and a bare `pandas` - no version on
|
|
14
|
+
either. The floor `openpyxl>=3.1.5` exists only inside pandas' own `excel` extra, and
|
|
15
|
+
markitdown does not request that extra, so nothing in the chain ever states it. A resolver
|
|
16
|
+
is therefore free to leave an older `openpyxl` in place, and Odoo pins exactly 3.1.2, so the
|
|
17
|
+
combination is not hypothetical - it is the normal case inside an Odoo install. Every
|
|
18
|
+
spreadsheet ended in:
|
|
19
|
+
|
|
20
|
+
XlsxConverter threw ImportError with message: Pandas requires version '3.1.5' or
|
|
21
|
+
newer of 'openpyxl' (version '3.1.2' currently installed).
|
|
22
|
+
|
|
23
|
+
Downstream that surfaces as "no text could be extracted", which names neither the library
|
|
24
|
+
nor the version. The `[docs]` extra now declares `openpyxl>=3.1.5,<4.0.0` itself.
|
|
25
|
+
|
|
26
|
+
Only `.xlsx` was affected - `.docx` goes through mammoth, `.pptx` through python-pptx and
|
|
27
|
+
`.pdf` through pymupdf, none of which route via pandas. Verified against all ten supported
|
|
28
|
+
extensions after the change.
|
|
29
|
+
|
|
30
|
+
## [3.2.0] - 2026-08-23
|
|
31
|
+
|
|
32
|
+
### Breaking
|
|
33
|
+
|
|
34
|
+
- **`anthropic` floor raised to >= 1.0.0; `httpx` is no longer a core dependency.**
|
|
35
|
+
The Anthropic SDK moved to `httpx2` in 1.0.0 and now rejects an `httpx` client outright
|
|
36
|
+
(`TypeError: Expected an instance of httpx2.Client`). Since `pyproject.toml` allowed
|
|
37
|
+
`<2.0.0`, a `pip install -U` would have silently broken the Anthropic provider. Both SDK
|
|
38
|
+
clients run on `httpx2` now, and the separate `httpx>=0.27,<1` dependency is gone — it
|
|
39
|
+
existed solely because of that one incompatibility.
|
|
40
|
+
|
|
41
|
+
The same SDK release **removed** `temperature`, `top_p` and `top_k` from `messages.create()`
|
|
42
|
+
and `messages.stream()`; passing one is a `TypeError`, not a warning. The SDK notes call this
|
|
43
|
+
"some minor breaking changes" — in practice every temperature-setting call failed. The new
|
|
44
|
+
helper `providers.temperature_constraints.apply_anthropic_temperature()` clamps the value and
|
|
45
|
+
routes it into `extra_body`. **Never write `params["temperature"]` for an Anthropic call again.**
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- **GPT-5 temperature support is not uniform — every call to `gpt-5`, `gpt-5.5` and the whole
|
|
50
|
+
current `gpt-5.6` tier failed with HTTP 400.** The constraint table carried a single permissive
|
|
51
|
+
`gpt-5` prefix declaring the entire family temperature-capable. Measured live on 23.08.2026:
|
|
52
|
+
`gpt-5` and `gpt-5-mini` refuse ("Only the default (1) value is supported"), `gpt-5.1`/`5.2`/`5.4`
|
|
53
|
+
accept, `gpt-5.5` and `gpt-5.6` refuse again. The generic prefix now says **no** and the
|
|
54
|
+
accepting generations are listed individually, so an untested future generation inherits "no
|
|
55
|
+
temperature" — omitting it never breaks, sending it does.
|
|
56
|
+
|
|
57
|
+
- **`get_temperature_constraints()` fell through to the permissive default for a prefixed model.**
|
|
58
|
+
`openai/gpt-5.6-luna` matched no entry, got 0.0-2.0, and was therefore sent a parameter the model
|
|
59
|
+
rejects. The function now strips the provider prefix itself instead of trusting every caller to.
|
|
60
|
+
|
|
61
|
+
- **LangDock agents really stream now.** `_agent_stream_completion` sent `"stream": false` and
|
|
62
|
+
yielded the finished answer as a single chunk — no streaming, and LangDock aborts non-streaming
|
|
63
|
+
requests after 100 seconds with HTTP 524, which an agent with tools or knowledge search reaches
|
|
64
|
+
easily. Both agent paths now go through `_agent_request_events()` and the AI SDK 5 data-stream
|
|
65
|
+
protocol; the synchronous path streams internally and assembles the answer itself. The parser
|
|
66
|
+
splits on the `data: ` marker rather than on line boundaries (LangDock glues events together) and
|
|
67
|
+
skips unparseable blocks instead of letting one kill a running answer.
|
|
68
|
+
|
|
69
|
+
- **The LangDock Google backend was entirely broken.** `list_models()` served a hand-maintained
|
|
70
|
+
catalogue (`gemini-2.5-flash`, `gemini-2.5-pro`) the gateway had retired — including the backend
|
|
71
|
+
default model, so every call without an explicit model ended in 400. The list now comes live from
|
|
72
|
+
the same endpoint the error came from. On top of that the streaming path silently yielded
|
|
73
|
+
**nothing**: the parser looks for SSE lines, but without `?alt=sse` LangDock answers with a JSON
|
|
74
|
+
array — no match, no chunks, no error. The parameter is now set.
|
|
75
|
+
|
|
76
|
+
- **Google and Codestral errors swallowed their own cause.** Both logged the response body and then
|
|
77
|
+
called `raise_for_status()`, so the caller saw only "Client error '400 Bad Request'" while the
|
|
78
|
+
actual reason — a retired model, a missing entitlement — sat in a log line. The shared
|
|
79
|
+
`_raise_http_error()` now appends the body without losing the typed mapping (401 stays
|
|
80
|
+
`AuthenticationError`, 429 `RateLimitError`).
|
|
81
|
+
|
|
82
|
+
- **The Agent API's HTTP 400 is translated.** It covers three entirely different cases: agent
|
|
83
|
+
unknown, agent not shared with the API key, or no model resolvable at all. The last happens when
|
|
84
|
+
the agent's model is set to "Auto" in LangDock — the auto-router works only in the chat UI, and a
|
|
85
|
+
top-level `model` demonstrably does not override it. The message now names the remedy in plain
|
|
86
|
+
words.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- **Every default model raised to the current generation.** Four were unusable or outdated:
|
|
91
|
+
`anthropic` pointed at `claude-sonnet-4-20250514` and `melious` at `minimax-428b-m3` — both
|
|
92
|
+
withdrawn — while `openai`, `mammouth` and `openrouter` still named `gpt-4o`. Now:
|
|
93
|
+
`gpt-5.6-luna`, `claude-sonnet-5`, `openai/gpt-5.6-luna`, `nemotron-3-nano-30b-a3b`. Three of
|
|
94
|
+
LangDock's four backend defaults were dead (`gpt-4o`, `claude-sonnet-4-20250514`,
|
|
95
|
+
`gemini-2.5-flash`).
|
|
96
|
+
|
|
97
|
+
A default model is the one unavoidable constant — everything else is resolved live. The new live
|
|
98
|
+
guards `TestProviderDefaultsAreLive` and `TestLangDockDefaultsAreLive` fail the moment a provider
|
|
99
|
+
stops serving one, and additionally check that it actually answers: being listed is not enough.
|
|
100
|
+
|
|
101
|
+
- **Dependency floors raised to the current release** (21 entries), among them
|
|
102
|
+
`sentence-transformers` 3 -> 6, `websockets` 13 -> 17.0.1, `pytest-asyncio` 0.24 -> 1.4,
|
|
103
|
+
`pytest` 8 -> 9.1.1, `mypy` 1.15 -> 2.3.1, `pytest-cov` 6 -> 7.1, `qdrant-client` 1.12 -> 1.19,
|
|
104
|
+
`fastapi` 0.115 -> 0.141, `uvicorn` 0.32 -> 0.52. An old floor is an open vulnerability waiting
|
|
105
|
+
for a fresh install. The suite runs green on all new majors without a code change.
|
|
106
|
+
|
|
107
|
+
- **Live coverage now spans all LangDock backends.** Only `openai` and `anthropic` were tested;
|
|
108
|
+
the Google backend speaks an entirely different protocol and was never touched live — which is
|
|
109
|
+
precisely why its defect went unnoticed. The Codestral path has no coverage any more: Mistral is
|
|
110
|
+
not of interest via LangDock.
|
|
111
|
+
|
|
112
|
+
**Test suite:** 1858 unit tests, 51 live tests (0 failures), mypy `--strict` clean.
|
|
113
|
+
|
|
8
114
|
## [3.1.1] - 2026-08-20
|
|
9
115
|
|
|
10
116
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: eq-chatbot-core
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.1
|
|
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'
|
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## Version 3.2.1 (24.08.2026)
|
|
4
|
+
|
|
5
|
+
### [FIX]
|
|
6
|
+
|
|
7
|
+
- **Die Umwandlung von `.xlsx` scheiterte mit einer Meldung über pandas.** Das `[docs]`-Extra
|
|
8
|
+
zieht `markitdown[xlsx]`, und das verlangt schlicht „openpyxl" und „pandas" — ohne jede
|
|
9
|
+
Fassungsangabe. Die Untergrenze `openpyxl>=3.1.5` steht allein im `excel`-Extra von pandas,
|
|
10
|
+
das markitdown nicht anfordert; in der ganzen Kette nennt sie also niemand. Ein Auflöser darf
|
|
11
|
+
damit eine ältere Fassung stehen lassen, und Odoo legt sich genau auf 3.1.2 fest — die
|
|
12
|
+
Kombination ist demnach kein Sonderfall, sondern der Regelfall in einer Odoo-Installation.
|
|
13
|
+
Jede Tabellenkalkulation endete mit:
|
|
14
|
+
|
|
15
|
+
XlsxConverter threw ImportError with message: Pandas requires version '3.1.5' or
|
|
16
|
+
newer of 'openpyxl' (version '3.1.2' currently installed).
|
|
17
|
+
|
|
18
|
+
Beim Aufrufer kommt davon „Es konnte kein Text extrahiert werden" an — eine Meldung, die
|
|
19
|
+
weder die Bibliothek noch die Fassung nennt. Das `[docs]`-Extra verlangt jetzt selbst
|
|
20
|
+
`openpyxl>=3.1.5,<4.0.0`.
|
|
21
|
+
|
|
22
|
+
Betroffen war ausschließlich `.xlsx`: `.docx` läuft über mammoth, `.pptx` über python-pptx
|
|
23
|
+
und `.pdf` über pymupdf, keines davon über pandas. Nach der Änderung gegen alle zehn
|
|
24
|
+
unterstützten Endungen geprüft.
|
|
25
|
+
|
|
3
26
|
## Version 3.2.0 (23.08.2026)
|
|
4
27
|
|
|
5
28
|
### ⚠️ Breaking
|
|
@@ -103,6 +103,13 @@ docs = [
|
|
|
103
103
|
# Document-to-Markdown extraction for knowledge ingestion (services/document_extractor.py)
|
|
104
104
|
"markitdown[docx,pdf,pptx,xlsx]>=0.1.7,<0.2.0",
|
|
105
105
|
"pymupdf>=1.28.2,<2.0.0", # Embedded-image extraction from PDFs
|
|
106
|
+
# Stated here because nothing else states it. markitdown's [xlsx] extra asks for
|
|
107
|
+
# a bare "openpyxl" and a bare "pandas"; the floor openpyxl>=3.1.5 lives only in
|
|
108
|
+
# pandas' own "excel" extra, which markitdown does not request. So a resolver is
|
|
109
|
+
# free to leave an older openpyxl in place - and Odoo pins exactly 3.1.2 - after
|
|
110
|
+
# which every .xlsx conversion dies with "Pandas requires version '3.1.5' or
|
|
111
|
+
# newer of 'openpyxl'". The consumer sees "no text could be extracted".
|
|
112
|
+
"openpyxl>=3.1.5,<4.0.0",
|
|
106
113
|
]
|
|
107
114
|
image = [
|
|
108
115
|
# Floor 12.3.0 excludes CVE-2026-59205 (ImageCmsTransform buffer overflow),
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
# Test Report - 2026-08-
|
|
1
|
+
# Test Report - 2026-08-24 15:08:24
|
|
2
2
|
|
|
3
|
-
**eq_chatbot_core v3.
|
|
3
|
+
**eq_chatbot_core v3.2.1** | 10.66s | Python 3.13.12 | macOS-26.6.2-arm64-arm-64bit-Mach-O
|
|
4
4
|
|
|
5
|
-
> **Result: ALL PASSED -
|
|
5
|
+
> **Result: ALL PASSED - 1861 tests OK, 5 expected failures**
|
|
6
6
|
|
|
7
|
-
Command: `/Users/picard/gitbase/PyPi-Projects/eq_chatbot_core/.venv/lib/python3.13/site-packages/pytest/__main__.py tests/unit/ -q --no-header
|
|
7
|
+
Command: `/Users/picard/gitbase/PyPi-Projects/eq_chatbot_core/.venv/lib/python3.13/site-packages/pytest/__main__.py tests/unit/ -q --no-header`
|
|
8
8
|
|
|
9
9
|
## Summary
|
|
10
10
|
|
|
11
11
|
| Status | Count |
|
|
12
12
|
|--------|-------|
|
|
13
|
-
| Passed |
|
|
13
|
+
| Passed | 1861 |
|
|
14
14
|
| Failed | 0 |
|
|
15
15
|
| XFailed (expected) | 5 |
|
|
16
|
-
| **Total** | **
|
|
16
|
+
| **Total** | **1866** |
|
|
17
17
|
|
|
18
18
|
## Configuration Status
|
|
19
19
|
|
|
@@ -49,24 +49,24 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
49
49
|
| Module | Test Model | Passed | Failed | Skipped | XFailed | Total | Duration |
|
|
50
50
|
|--------|------------|--------|--------|---------|---------|-------|----------|
|
|
51
51
|
| **Provider: OpenAI** | - | 47 | 0 | 0 | 0 | 47 | 0.09s |
|
|
52
|
-
| **Provider: Anthropic** | - | 51 | 0 | 0 | 0 | 51 | 0.
|
|
53
|
-
| **Provider: LangDock** | - | 60 | 0 | 0 | 0 | 60 | 0.
|
|
54
|
-
| **Provider: OpenRouter** | - | 38 | 0 | 0 | 0 | 38 | 0.
|
|
55
|
-
| **Provider: Mammouth AI** | - | 41 | 0 | 0 | 0 | 41 | 0.
|
|
52
|
+
| **Provider: Anthropic** | - | 51 | 0 | 0 | 0 | 51 | 0.11s |
|
|
53
|
+
| **Provider: LangDock** | - | 60 | 0 | 0 | 0 | 60 | 0.08s |
|
|
54
|
+
| **Provider: OpenRouter** | - | 38 | 0 | 0 | 0 | 38 | 0.06s |
|
|
55
|
+
| **Provider: Mammouth AI** | - | 41 | 0 | 0 | 0 | 41 | 0.06s |
|
|
56
56
|
| **Provider: LiteLLM Gateway** | - | 30 | 0 | 0 | 0 | 30 | 0.02s |
|
|
57
|
-
| **Provider: IONOS AI Model Hub** | - | 27 | 0 | 0 | 0 | 27 | 0.
|
|
58
|
-
| **Provider: Melious.ai (sovereign EU)** | - | 28 | 0 | 0 | 0 | 28 | 0.
|
|
57
|
+
| **Provider: IONOS AI Model Hub** | - | 27 | 0 | 0 | 0 | 27 | 0.08s |
|
|
58
|
+
| **Provider: Melious.ai (sovereign EU)** | - | 28 | 0 | 0 | 0 | 28 | 0.04s |
|
|
59
59
|
| **Provider: Privatemode.ai (end-to-end encrypted)** | - | 29 | 0 | 0 | 0 | 29 | 0.02s |
|
|
60
|
-
| **Provider: Local (LM Studio / Ollama)** | - | 35 | 0 | 0 | 0 | 35 | 0.
|
|
61
|
-
| **Security** | - | 423 | 0 | 0 | 5 | 428 | 0.
|
|
62
|
-
| **RAG Pipeline** | - | 117 | 0 | 0 | 0 | 117 | 0.
|
|
63
|
-
| **Services & Core** | - | 166 | 0 | 0 | 0 | 166 | 0.
|
|
64
|
-
| **MCP Client** | - | 99 | 0 | 0 | 0 | 99 | 1.
|
|
65
|
-
| **Other** | - |
|
|
60
|
+
| **Provider: Local (LM Studio / Ollama)** | - | 35 | 0 | 0 | 0 | 35 | 0.04s |
|
|
61
|
+
| **Security** | - | 423 | 0 | 0 | 5 | 428 | 0.05s |
|
|
62
|
+
| **RAG Pipeline** | - | 117 | 0 | 0 | 0 | 117 | 0.42s |
|
|
63
|
+
| **Services & Core** | - | 166 | 0 | 0 | 0 | 166 | 0.13s |
|
|
64
|
+
| **MCP Client** | - | 99 | 0 | 0 | 0 | 99 | 1.53s |
|
|
65
|
+
| **Other** | - | 670 | 0 | 0 | 0 | 670 | 4.26s |
|
|
66
66
|
|
|
67
67
|
## Detailed Results
|
|
68
68
|
|
|
69
|
-
### Unit Tests (
|
|
69
|
+
### Unit Tests (1861 passed, 5 xfailed)
|
|
70
70
|
|
|
71
71
|
#### Provider: OpenAI (47 passed) - 0.09s
|
|
72
72
|
|
|
@@ -120,7 +120,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
120
120
|
| `unit/test_openai.py::TestOpenAIProviderProperties::test_reasoning_model_no_temperature` | PASSED | <0.01s |
|
|
121
121
|
| `unit/test_openai.py::TestOpenAIProviderProperties::test_gpt41_temperature_passthrough` | PASSED | <0.01s |
|
|
122
122
|
|
|
123
|
-
#### Provider: Anthropic (51 passed) - 0.
|
|
123
|
+
#### Provider: Anthropic (51 passed) - 0.11s
|
|
124
124
|
|
|
125
125
|
| Test | Status | Duration |
|
|
126
126
|
|------|--------|----------|
|
|
@@ -130,7 +130,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
130
130
|
| `unit/test_anthropic.py::TestAnthropicProviderInit::test_private_range_blocked` | PASSED | <0.01s |
|
|
131
131
|
| `unit/test_anthropic.py::TestAnthropicProviderInit::test_non_http_scheme_blocked` | PASSED | <0.01s |
|
|
132
132
|
| `unit/test_anthropic.py::TestAnthropicProviderInit::test_lazy_client_initialization` | PASSED | <0.01s |
|
|
133
|
-
| `unit/test_anthropic.py::TestAnthropicProviderInit::test_client_property_creates_client` | PASSED | 0.
|
|
133
|
+
| `unit/test_anthropic.py::TestAnthropicProviderInit::test_client_property_creates_client` | PASSED | 0.07s |
|
|
134
134
|
| `unit/test_anthropic.py::TestAnthropicProviderInit::test_client_reuses_instance` | PASSED | <0.01s |
|
|
135
135
|
| `unit/test_anthropic.py::TestSystemPromptExtraction::test_extract_single_system_prompt` | PASSED | <0.01s |
|
|
136
136
|
| `unit/test_anthropic.py::TestSystemPromptExtraction::test_extract_multiple_system_prompts` | PASSED | <0.01s |
|
|
@@ -176,7 +176,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
176
176
|
| `unit/test_anthropic.py::TestAnthropicProviderProperties::test_claude_temperature_clamped_to_max` | PASSED | <0.01s |
|
|
177
177
|
| `unit/test_anthropic.py::TestAnthropicProviderProperties::test_repr` | PASSED | <0.01s |
|
|
178
178
|
|
|
179
|
-
#### Provider: LangDock (60 passed) - 0.
|
|
179
|
+
#### Provider: LangDock (60 passed) - 0.08s
|
|
180
180
|
|
|
181
181
|
| Test | Status | Duration |
|
|
182
182
|
|------|--------|----------|
|
|
@@ -204,7 +204,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
204
204
|
| `unit/test_langdock.py::TestLangDockTokenAPI::test_gpt5_uses_new_api` | PASSED | <0.01s |
|
|
205
205
|
| `unit/test_langdock.py::TestLangDockTokenAPI::test_reasoning_models_use_new_api` | PASSED | <0.01s |
|
|
206
206
|
| `unit/test_langdock.py::TestLangDockTokenAPI::test_gpt4_turbo_uses_legacy_api` | PASSED | <0.01s |
|
|
207
|
-
| `unit/test_langdock.py::TestLangDockOpenAIChatCompletion::test_simple_completion` | PASSED |
|
|
207
|
+
| `unit/test_langdock.py::TestLangDockOpenAIChatCompletion::test_simple_completion` | PASSED | 0.05s |
|
|
208
208
|
| `unit/test_langdock.py::TestLangDockOpenAIChatCompletion::test_completion_with_temperature` | PASSED | <0.01s |
|
|
209
209
|
| `unit/test_langdock.py::TestLangDockOpenAIChatCompletion::test_completion_without_temperature_for_reasoning` | PASSED | <0.01s |
|
|
210
210
|
| `unit/test_langdock.py::TestLangDockOpenAIChatCompletion::test_completion_with_reasoning_effort` | PASSED | <0.01s |
|
|
@@ -241,7 +241,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
241
241
|
| `unit/test_langdock.py::TestLangDockSSRFGuard::test_localhost_base_url_accepted` | PASSED | <0.01s |
|
|
242
242
|
| `unit/test_langdock.py::TestLangDockSSRFGuard::test_default_base_url_skips_validation` | PASSED | <0.01s |
|
|
243
243
|
|
|
244
|
-
#### Provider: OpenRouter (38 passed) - 0.
|
|
244
|
+
#### Provider: OpenRouter (38 passed) - 0.06s
|
|
245
245
|
|
|
246
246
|
| Test | Status | Duration |
|
|
247
247
|
|------|--------|----------|
|
|
@@ -275,7 +275,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
275
275
|
| `unit/test_openrouter.py::TestOpenRouterErrorHandling::test_rate_limit_error` | PASSED | <0.01s |
|
|
276
276
|
| `unit/test_openrouter.py::TestOpenRouterErrorHandling::test_authentication_error` | PASSED | <0.01s |
|
|
277
277
|
| `unit/test_openrouter.py::TestOpenRouterErrorHandling::test_context_length_error` | PASSED | <0.01s |
|
|
278
|
-
| `unit/test_openrouter.py::TestOpenRouterErrorHandling::test_generic_error` | PASSED |
|
|
278
|
+
| `unit/test_openrouter.py::TestOpenRouterErrorHandling::test_generic_error` | PASSED | 0.05s |
|
|
279
279
|
| `unit/test_openrouter.py::TestOpenRouterContextManager::test_close_client` | PASSED | <0.01s |
|
|
280
280
|
| `unit/test_openrouter.py::TestOpenRouterContextManager::test_context_manager` | PASSED | <0.01s |
|
|
281
281
|
| `unit/test_openrouter.py::TestOpenRouterFactoryIntegration::test_get_provider_returns_openrouter` | PASSED | <0.01s |
|
|
@@ -284,7 +284,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
284
284
|
| `unit/test_openrouter.py::TestOpenRouterSSRFGuard::test_localhost_base_url_accepted` | PASSED | <0.01s |
|
|
285
285
|
| `unit/test_openrouter.py::TestOpenRouterSSRFGuard::test_default_base_url_skips_validation` | PASSED | <0.01s |
|
|
286
286
|
|
|
287
|
-
#### Provider: Mammouth AI (41 passed) - 0.
|
|
287
|
+
#### Provider: Mammouth AI (41 passed) - 0.06s
|
|
288
288
|
|
|
289
289
|
| Test | Status | Duration |
|
|
290
290
|
|------|--------|----------|
|
|
@@ -321,7 +321,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
321
321
|
| `unit/test_mammouth.py::TestMammouthErrorHandling::test_authentication_error` | PASSED | <0.01s |
|
|
322
322
|
| `unit/test_mammouth.py::TestMammouthErrorHandling::test_overloaded_error` | PASSED | <0.01s |
|
|
323
323
|
| `unit/test_mammouth.py::TestMammouthErrorHandling::test_context_length_error` | PASSED | <0.01s |
|
|
324
|
-
| `unit/test_mammouth.py::TestMammouthErrorHandling::test_generic_error` | PASSED |
|
|
324
|
+
| `unit/test_mammouth.py::TestMammouthErrorHandling::test_generic_error` | PASSED | 0.05s |
|
|
325
325
|
| `unit/test_mammouth.py::TestMammouthContextManager::test_close_client` | PASSED | <0.01s |
|
|
326
326
|
| `unit/test_mammouth.py::TestMammouthContextManager::test_context_manager` | PASSED | <0.01s |
|
|
327
327
|
| `unit/test_mammouth.py::TestMammouthFactoryIntegration::test_get_provider_returns_mammouth` | PASSED | <0.01s |
|
|
@@ -365,7 +365,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
365
365
|
| `unit/test_litellm.py::TestLiteLLMContextManager::test_close_closes_client` | PASSED | <0.01s |
|
|
366
366
|
| `unit/test_litellm.py::TestLiteLLMContextManager::test_context_manager` | PASSED | <0.01s |
|
|
367
367
|
|
|
368
|
-
#### Provider: IONOS AI Model Hub (27 passed) - 0.
|
|
368
|
+
#### Provider: IONOS AI Model Hub (27 passed) - 0.08s
|
|
369
369
|
|
|
370
370
|
| Test | Status | Duration |
|
|
371
371
|
|------|--------|----------|
|
|
@@ -382,7 +382,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
382
382
|
| `unit/test_ionos.py::TestIonosProviderProperties::test_default_model_override` | PASSED | <0.01s |
|
|
383
383
|
| `unit/test_ionos.py::TestIonosChatCompletion::test_simple_completion` | PASSED | <0.01s |
|
|
384
384
|
| `unit/test_ionos.py::TestIonosChatCompletion::test_uses_default_model` | PASSED | <0.01s |
|
|
385
|
-
| `unit/test_ionos.py::TestIonosChatCompletion::test_explicit_model_and_max_tokens` | PASSED |
|
|
385
|
+
| `unit/test_ionos.py::TestIonosChatCompletion::test_explicit_model_and_max_tokens` | PASSED | 0.04s |
|
|
386
386
|
| `unit/test_ionos.py::TestIonosChatCompletion::test_tools_passed_through` | PASSED | <0.01s |
|
|
387
387
|
| `unit/test_ionos.py::TestIonosChatCompletion::test_temperature_clamped` | PASSED | <0.01s |
|
|
388
388
|
| `unit/test_ionos.py::TestIonosChatCompletion::test_tool_calls_parsed` | PASSED | <0.01s |
|
|
@@ -397,7 +397,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
397
397
|
| `unit/test_ionos.py::TestIonosContextManager::test_close_closes_client` | PASSED | <0.01s |
|
|
398
398
|
| `unit/test_ionos.py::TestIonosContextManager::test_context_manager` | PASSED | <0.01s |
|
|
399
399
|
|
|
400
|
-
#### Provider: Melious.ai (sovereign EU) (28 passed) - 0.
|
|
400
|
+
#### Provider: Melious.ai (sovereign EU) (28 passed) - 0.04s
|
|
401
401
|
|
|
402
402
|
| Test | Status | Duration |
|
|
403
403
|
|------|--------|----------|
|
|
@@ -464,12 +464,12 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
464
464
|
| `unit/test_privatemode.py::TestPrivatemodeErrorHandling::test_rate_limit_mapped` | PASSED | <0.01s |
|
|
465
465
|
| `unit/test_privatemode.py::TestPrivatemodeErrorHandling::test_generic_error_mapped` | PASSED | <0.01s |
|
|
466
466
|
|
|
467
|
-
#### Provider: Local (LM Studio / Ollama) (35 passed) - 0.
|
|
467
|
+
#### Provider: Local (LM Studio / Ollama) (35 passed) - 0.04s
|
|
468
468
|
|
|
469
469
|
| Test | Status | Duration |
|
|
470
470
|
|------|--------|----------|
|
|
471
471
|
| `unit/test_local.py::TestLocalLLMProviderInit::test_default_initialization` | PASSED | <0.01s |
|
|
472
|
-
| `unit/test_local.py::TestLocalLLMProviderInit::test_custom_base_url` | PASSED | 0.
|
|
472
|
+
| `unit/test_local.py::TestLocalLLMProviderInit::test_custom_base_url` | PASSED | <0.01s |
|
|
473
473
|
| `unit/test_local.py::TestLocalLLMProviderInit::test_ollama_url` | PASSED | <0.01s |
|
|
474
474
|
| `unit/test_local.py::TestLocalLLMProviderInit::test_lm_studio_url` | PASSED | <0.01s |
|
|
475
475
|
| `unit/test_local.py::TestLocalLLMProviderInit::test_custom_timeout` | PASSED | <0.01s |
|
|
@@ -504,7 +504,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
504
504
|
| `unit/test_local.py::TestLocalLLMProviderClient::test_client_reuses_instance` | PASSED | <0.01s |
|
|
505
505
|
| `unit/test_local.py::TestLocalLLMProviderClient::test_client_includes_auth_header` | PASSED | <0.01s |
|
|
506
506
|
|
|
507
|
-
#### Security (423 passed, 5 xfailed) - 0.
|
|
507
|
+
#### Security (423 passed, 5 xfailed) - 0.05s
|
|
508
508
|
|
|
509
509
|
| Test | Status | Duration | Detail |
|
|
510
510
|
|------|--------|----------|--------|
|
|
@@ -937,7 +937,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
937
937
|
| `unit/test_rate_limit.py::TestEnforceRateLimit::test_non_atomic_records_usage_when_allowed` | PASSED | <0.01s | |
|
|
938
938
|
| `unit/test_rate_limit.py::TestEnforceRateLimit::test_non_atomic_does_not_record_when_denied` | PASSED | <0.01s | |
|
|
939
939
|
|
|
940
|
-
#### RAG Pipeline (117 passed) - 0.
|
|
940
|
+
#### RAG Pipeline (117 passed) - 0.42s
|
|
941
941
|
|
|
942
942
|
| Test | Status | Duration |
|
|
943
943
|
|------|--------|----------|
|
|
@@ -1015,7 +1015,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1015
1015
|
| `unit/test_knowledge_service.py::TestKnowledgeExporter::test_export_to_langdock_filenames_cannot_escape_temp_dir` | PASSED | <0.01s |
|
|
1016
1016
|
| `unit/test_knowledge_service.py::TestKnowledgeExporter::test_empty_records` | PASSED | <0.01s |
|
|
1017
1017
|
| `unit/test_knowledge_service.py::TestExportRecord::test_create_export_record` | PASSED | <0.01s |
|
|
1018
|
-
| `unit/test_retriever.py::TestRetrieveSuccess::test_retrieve_returns_retrieval_results` | PASSED | 0.
|
|
1018
|
+
| `unit/test_retriever.py::TestRetrieveSuccess::test_retrieve_returns_retrieval_results` | PASSED | 0.41s |
|
|
1019
1019
|
| `unit/test_retriever.py::TestRetrieveSuccess::test_retrieve_maps_payload_fields_correctly` | PASSED | <0.01s |
|
|
1020
1020
|
| `unit/test_retriever.py::TestRetrieveSuccess::test_retrieve_calls_embedder_with_query` | PASSED | <0.01s |
|
|
1021
1021
|
| `unit/test_retriever.py::TestRetrieveSuccess::test_retrieve_calls_qdrant_search` | PASSED | <0.01s |
|
|
@@ -1059,7 +1059,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1059
1059
|
| `unit/test_retriever.py::TestUpsert::test_upsert_qdrant_failure_raises_connection_error` | PASSED | <0.01s |
|
|
1060
1060
|
| `unit/test_retriever.py::TestUpsert::test_upsert_handles_missing_optional_fields` | PASSED | <0.01s |
|
|
1061
1061
|
|
|
1062
|
-
#### Services & Core (166 passed) - 0.
|
|
1062
|
+
#### Services & Core (166 passed) - 0.13s
|
|
1063
1063
|
|
|
1064
1064
|
| Test | Status | Duration |
|
|
1065
1065
|
|------|--------|----------|
|
|
@@ -1157,8 +1157,8 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1157
1157
|
| `unit/test_factory.py::TestFactoryCloudProviders::test_get_anthropic_provider` | PASSED | <0.01s |
|
|
1158
1158
|
| `unit/test_factory.py::TestFactoryCloudProviders::test_get_langdock_provider` | PASSED | <0.01s |
|
|
1159
1159
|
| `unit/test_factory.py::TestFactoryCloudProviders::test_get_openrouter_provider` | PASSED | <0.01s |
|
|
1160
|
-
| `unit/test_factory.py::TestFactoryCloudProviders::test_get_ionos_provider` | PASSED |
|
|
1161
|
-
| `unit/test_factory.py::TestFactoryCloudProviders::test_get_melious_provider` | PASSED | 0.
|
|
1160
|
+
| `unit/test_factory.py::TestFactoryCloudProviders::test_get_ionos_provider` | PASSED | 0.06s |
|
|
1161
|
+
| `unit/test_factory.py::TestFactoryCloudProviders::test_get_melious_provider` | PASSED | 0.04s |
|
|
1162
1162
|
| `unit/test_factory.py::TestFactoryCloudProviders::test_provider_name_case_insensitive` | PASSED | <0.01s |
|
|
1163
1163
|
| `unit/test_factory.py::TestFactoryCloudProviders::test_custom_base_url` | PASSED | <0.01s |
|
|
1164
1164
|
| `unit/test_factory.py::TestFactoryCloudProviders::test_custom_base_url_ssrf_blocked` | PASSED | <0.01s |
|
|
@@ -1167,7 +1167,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1167
1167
|
| `unit/test_factory.py::TestFactoryLocalProviders::test_get_lm_studio_alias` | PASSED | <0.01s |
|
|
1168
1168
|
| `unit/test_factory.py::TestFactoryLocalProviders::test_get_lmstudio_alias` | PASSED | <0.01s |
|
|
1169
1169
|
| `unit/test_factory.py::TestFactoryLocalProviders::test_get_ollama_alias` | PASSED | <0.01s |
|
|
1170
|
-
| `unit/test_factory.py::TestFactoryLocalProviders::test_local_alias_custom_base_url_override` | PASSED | 0.
|
|
1170
|
+
| `unit/test_factory.py::TestFactoryLocalProviders::test_local_alias_custom_base_url_override` | PASSED | <0.01s |
|
|
1171
1171
|
| `unit/test_factory.py::TestFactoryLocalProviders::test_local_provider_with_api_key` | PASSED | <0.01s |
|
|
1172
1172
|
| `unit/test_factory.py::TestFactoryLocalProviders::test_local_alias_case_insensitive` | PASSED | <0.01s |
|
|
1173
1173
|
| `unit/test_factory.py::TestFactoryErrors::test_unknown_provider_raises_error` | PASSED | <0.01s |
|
|
@@ -1230,7 +1230,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1230
1230
|
| `unit/test_temperature_constraints.py::TestClampWithPrefixStrip::test_openrouter_o3_returns_none` | PASSED | <0.01s |
|
|
1231
1231
|
| `unit/test_temperature_constraints.py::TestClampWithPrefixStrip::test_openrouter_unknown_passthrough` | PASSED | <0.01s |
|
|
1232
1232
|
|
|
1233
|
-
#### MCP Client (99 passed) - 1.
|
|
1233
|
+
#### MCP Client (99 passed) - 1.53s
|
|
1234
1234
|
|
|
1235
1235
|
| Test | Status | Duration |
|
|
1236
1236
|
|------|--------|----------|
|
|
@@ -1254,12 +1254,12 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1254
1254
|
| `unit/test_mcp.py::TestMCPClientRequests::test_send_request_success` | PASSED | 0.05s |
|
|
1255
1255
|
| `unit/test_mcp.py::TestMCPClientRequests::test_send_request_timeout` | PASSED | 1.01s |
|
|
1256
1256
|
| `unit/test_mcp.py::TestMCPClientRequests::test_send_request_http_error` | PASSED | <0.01s |
|
|
1257
|
-
| `unit/test_mcp.py::TestMCPClientRequests::test_send_request_increments_id` | PASSED | 0.
|
|
1258
|
-
| `unit/test_mcp.py::TestMCPClientToolOperations::test_list_tools_success` | PASSED | 0.
|
|
1257
|
+
| `unit/test_mcp.py::TestMCPClientRequests::test_send_request_increments_id` | PASSED | 0.05s |
|
|
1258
|
+
| `unit/test_mcp.py::TestMCPClientToolOperations::test_list_tools_success` | PASSED | 0.05s |
|
|
1259
1259
|
| `unit/test_mcp.py::TestMCPClientToolOperations::test_list_tools_empty` | PASSED | 0.06s |
|
|
1260
1260
|
| `unit/test_mcp.py::TestMCPClientToolOperations::test_call_tool_success` | PASSED | 0.06s |
|
|
1261
1261
|
| `unit/test_mcp.py::TestMCPClientToolOperations::test_call_tool_error` | PASSED | 0.06s |
|
|
1262
|
-
| `unit/test_mcp.py::TestMCPClientToolOperations::test_get_tool_schema_found` | PASSED | 0.
|
|
1262
|
+
| `unit/test_mcp.py::TestMCPClientToolOperations::test_get_tool_schema_found` | PASSED | 0.06s |
|
|
1263
1263
|
| `unit/test_mcp.py::TestMCPClientToolOperations::test_get_tool_schema_not_found` | PASSED | 0.05s |
|
|
1264
1264
|
| `unit/test_mcp.py::TestMCPClientToolOperations::test_call_tool_extracts_text_content` | PASSED | 0.06s |
|
|
1265
1265
|
| `unit/test_mcp.py::TestMCPClientContextManager::test_context_manager_enter_exit` | PASSED | <0.01s |
|
|
@@ -1334,7 +1334,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1334
1334
|
| `unit/test_mcp.py::TestDNSRebindingProtection::test_mcpclient_pins_base_url_on_init` | PASSED | <0.01s |
|
|
1335
1335
|
| `unit/test_mcp.py::TestDNSRebindingProtection::test_mcpclient_pins_endpoint_from_sse_event` | PASSED | <0.01s |
|
|
1336
1336
|
|
|
1337
|
-
#### Other (
|
|
1337
|
+
#### Other (670 passed) - 4.26s
|
|
1338
1338
|
|
|
1339
1339
|
| Test | Status | Duration |
|
|
1340
1340
|
|------|--------|----------|
|
|
@@ -1528,7 +1528,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1528
1528
|
| `unit/realtime/test_realtime_openai.py::TestConnectLifecycle::test_implements_contract` | PASSED | <0.01s |
|
|
1529
1529
|
| `unit/realtime/test_realtime_openai.py::TestCloseLifecycle::test_close_does_not_raise_when_not_connected` | PASSED | <0.01s |
|
|
1530
1530
|
| `unit/realtime/test_websocket_client.py::test_connect_with_backoff_3_failures_then_success` | PASSED | <0.01s |
|
|
1531
|
-
| `unit/realtime/test_websocket_client.py::test_connect_with_backoff_all_failures_raises` | PASSED | 1.
|
|
1531
|
+
| `unit/realtime/test_websocket_client.py::test_connect_with_backoff_all_failures_raises` | PASSED | 1.62s |
|
|
1532
1532
|
| `unit/realtime/test_websocket_client.py::test_realtime_closed_error_fields` | PASSED | <0.01s |
|
|
1533
1533
|
| `unit/realtime/test_websocket_client.py::test_realtime_rate_limit_error` | PASSED | <0.01s |
|
|
1534
1534
|
| `unit/realtime/test_websocket_client.py::test_error_hierarchy` | PASSED | <0.01s |
|
|
@@ -1604,7 +1604,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1604
1604
|
| `unit/test_capability_catalog.py::TestProviderScoping::test_provider_hint_disambiguates` | PASSED | <0.01s |
|
|
1605
1605
|
| `unit/test_capability_catalog.py::TestMetadataExposed::test_meta_and_providers_available` | PASSED | <0.01s |
|
|
1606
1606
|
| `unit/test_capability_catalog.py::TestSnapshotAndRemote::test_from_snapshot_loads_known_model` | PASSED | <0.01s |
|
|
1607
|
-
| `unit/test_capability_catalog.py::TestSnapshotAndRemote::test_from_remote_falls_back_to_snapshot` | PASSED |
|
|
1607
|
+
| `unit/test_capability_catalog.py::TestSnapshotAndRemote::test_from_remote_falls_back_to_snapshot` | PASSED | 0.09s |
|
|
1608
1608
|
| `unit/test_cli_api_key.py::TestResolveApiKey::test_explicit_flag_wins_over_everything` | PASSED | <0.01s |
|
|
1609
1609
|
| `unit/test_cli_api_key.py::TestResolveApiKey::test_provider_specific_env_used_when_no_flag` | PASSED | <0.01s |
|
|
1610
1610
|
| `unit/test_cli_api_key.py::TestResolveApiKey::test_provider_specific_env_wins_over_generic` | PASSED | <0.01s |
|
|
@@ -1638,7 +1638,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1638
1638
|
| `unit/test_cli_image.py::TestImageCommand::test_prompt_file` | PASSED | <0.01s |
|
|
1639
1639
|
| `unit/test_cli_image.py::TestImageCommand::test_custom_model_forwarded` | PASSED | <0.01s |
|
|
1640
1640
|
| `unit/test_cli_image.py::TestImageCommand::test_openrouter_provider_accepted` | PASSED | <0.01s |
|
|
1641
|
-
| `unit/test_cli_image.py::TestImageCommand::test_fit_option_resizes_image` | PASSED | 0.
|
|
1641
|
+
| `unit/test_cli_image.py::TestImageCommand::test_fit_option_resizes_image` | PASSED | 0.02s |
|
|
1642
1642
|
| `unit/test_cli_listing_assets.py::TestListingAssetsCommand::test_successful_batch_creates_files` | PASSED | <0.01s |
|
|
1643
1643
|
| `unit/test_cli_listing_assets.py::TestListingAssetsCommand::test_dest_defaults_to_recipe_directory` | PASSED | <0.01s |
|
|
1644
1644
|
| `unit/test_cli_listing_assets.py::TestListingAssetsCommand::test_provider_called_once_for_batch` | PASSED | <0.01s |
|
|
@@ -1694,6 +1694,9 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1694
1694
|
| `unit/test_config.py::TestConfigCLI::test_config_show_masks_keys` | PASSED | <0.01s |
|
|
1695
1695
|
| `unit/test_config.py::TestConfigIntegration::test_test_provider_uses_config_key` | PASSED | <0.01s |
|
|
1696
1696
|
| `unit/test_config.py::test_module_exposes_cli_resolvers` | PASSED | <0.01s |
|
|
1697
|
+
| `unit/test_docs_extra_pyproject.py::test_docs_extra_declares_openpyxl` | PASSED | <0.01s |
|
|
1698
|
+
| `unit/test_docs_extra_pyproject.py::test_the_floor_is_high_enough_for_pandas` | PASSED | <0.01s |
|
|
1699
|
+
| `unit/test_docs_extra_pyproject.py::test_the_extra_still_fences_off_the_next_major` | PASSED | <0.01s |
|
|
1697
1700
|
| `unit/test_document_extractor.py::TestPlainTextExtraction::test_markdown_passthrough` | PASSED | <0.01s |
|
|
1698
1701
|
| `unit/test_document_extractor.py::TestPlainTextExtraction::test_txt_passthrough` | PASSED | <0.01s |
|
|
1699
1702
|
| `unit/test_document_extractor.py::TestPlainTextExtraction::test_latin1_fallback_warns` | PASSED | <0.01s |
|
|
@@ -1703,7 +1706,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1703
1706
|
| `unit/test_document_extractor.py::TestGuards::test_non_bytes_rejected` | PASSED | <0.01s |
|
|
1704
1707
|
| `unit/test_document_extractor.py::TestGuards::test_supported_extensions_always_include_plain_text` | PASSED | <0.01s |
|
|
1705
1708
|
| `unit/test_document_extractor.py::TestRichFormats::test_missing_markitdown_yields_warning_not_crash` | PASSED | <0.01s |
|
|
1706
|
-
| `unit/test_document_extractor.py::TestRichFormats::test_html_extraction` | PASSED | 0.
|
|
1709
|
+
| `unit/test_document_extractor.py::TestRichFormats::test_html_extraction` | PASSED | 0.05s |
|
|
1707
1710
|
| `unit/test_embedder.py::TestOpenAIEmbedder::test_unknown_model_raises` | PASSED | <0.01s |
|
|
1708
1711
|
| `unit/test_embedder.py::TestOpenAIEmbedder::test_dimensions_from_catalog` | PASSED | <0.01s |
|
|
1709
1712
|
| `unit/test_embedder.py::TestLangDockEmbedder::test_region_sets_base_url` | PASSED | <0.01s |
|
|
@@ -1879,17 +1882,17 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1879
1882
|
| `unit/test_openrouter_image.py::TestOpenRouterImageGeneration::test_generate_image_custom_model` | PASSED | <0.01s |
|
|
1880
1883
|
| `unit/test_openrouter_image.py::TestOpenRouterImageGeneration::test_generate_image_invalid_data_url_raises_error` | PASSED | <0.01s |
|
|
1881
1884
|
| `unit/test_pdf.py::TestAvailability::test_available_when_pymupdf_installed` | PASSED | <0.01s |
|
|
1882
|
-
| `unit/test_pdf.py::TestConversion::test_single_page_returns_one_png` | PASSED | 0.
|
|
1885
|
+
| `unit/test_pdf.py::TestConversion::test_single_page_returns_one_png` | PASSED | 0.04s |
|
|
1883
1886
|
| `unit/test_pdf.py::TestConversion::test_jpeg_format_selected` | PASSED | 0.03s |
|
|
1884
|
-
| `unit/test_pdf.py::TestConversion::test_all_pages_converted` | PASSED | 0.
|
|
1887
|
+
| `unit/test_pdf.py::TestConversion::test_all_pages_converted` | PASSED | 0.07s |
|
|
1885
1888
|
| `unit/test_pdf.py::TestConversion::test_max_pages_truncates` | PASSED | 0.05s |
|
|
1886
1889
|
| `unit/test_pdf.py::TestConversion::test_higher_dpi_produces_larger_image` | PASSED | 0.10s |
|
|
1887
1890
|
| `unit/test_pdf.py::TestConversion::test_corrupt_pdf_returns_empty_list_instead_of_raising` | PASSED | <0.01s |
|
|
1888
1891
|
| `unit/test_pdf.py::TestInputValidation::test_invalid_format_rejected` | PASSED | <0.01s |
|
|
1889
|
-
| `unit/test_pdf.py::TestInputValidation::test_oversized_input_rejected` | PASSED |
|
|
1890
|
-
| `unit/test_pdf.py::TestResourceClamping::test_page_count_clamped_to_hard_limit` | PASSED | 1.
|
|
1892
|
+
| `unit/test_pdf.py::TestInputValidation::test_oversized_input_rejected` | PASSED | 0.01s |
|
|
1893
|
+
| `unit/test_pdf.py::TestResourceClamping::test_page_count_clamped_to_hard_limit` | PASSED | 1.07s |
|
|
1891
1894
|
| `unit/test_pdf.py::TestResourceClamping::test_zero_max_pages_still_renders_one_page` | PASSED | 0.02s |
|
|
1892
|
-
| `unit/test_pdf.py::TestResourceClamping::test_excessive_dpi_clamped` | PASSED | 0.
|
|
1895
|
+
| `unit/test_pdf.py::TestResourceClamping::test_excessive_dpi_clamped` | PASSED | 0.69s |
|
|
1893
1896
|
| `unit/test_pdf.py::TestResourceClamping::test_zero_dpi_clamped_to_minimum` | PASSED | <0.01s |
|
|
1894
1897
|
| `unit/test_pdf.py::TestBase64Wrapper::test_returns_decodable_base64` | PASSED | 0.02s |
|
|
1895
1898
|
| `unit/test_pdf.py::TestBase64Wrapper::test_matches_raw_conversion` | PASSED | 0.09s |
|
|
@@ -1971,7 +1974,7 @@ Resolved live from `tests/model_registry.py` against each provider's `list_model
|
|
|
1971
1974
|
| `unit/test_url_validation.py::TestValidatingTransport::test_unresolvable_host_blocked` | PASSED | <0.01s |
|
|
1972
1975
|
| `unit/test_url_validation.py::TestValidatingTransport::test_lan_mode_allows_private_but_not_metadata` | PASSED | <0.01s |
|
|
1973
1976
|
| `unit/test_url_validation.py::TestClientLibraryChoice::test_default_transport_is_built_against_httpx2` | PASSED | <0.01s |
|
|
1974
|
-
| `unit/test_url_validation.py::TestClientLibraryChoice::test_transport_can_still_be_built_against_httpx` | PASSED |
|
|
1977
|
+
| `unit/test_url_validation.py::TestClientLibraryChoice::test_transport_can_still_be_built_against_httpx` | PASSED | 0.01s |
|
|
1975
1978
|
| `unit/test_url_validation.py::TestClientLibraryChoice::test_validating_transport_honours_the_same_choice` | PASSED | <0.01s |
|
|
1976
1979
|
| `unit/test_url_validation.py::TestClientLibraryChoice::test_guard_still_fires_on_the_httpx_variant` | PASSED | <0.01s |
|
|
1977
1980
|
| `unit/test_url_validation.py::TestClientLibraryChoice::test_anthropic_provider_builds_an_httpx2_client` | PASSED | <0.01s |
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Static check that the [docs] extra states the openpyxl floor itself.
|
|
2
|
+
|
|
3
|
+
Nothing else in the chain does. `markitdown[xlsx]` asks for a bare `openpyxl` and
|
|
4
|
+
a bare `pandas`; the floor `openpyxl>=3.1.5` lives only in pandas' own `excel`
|
|
5
|
+
extra, which markitdown does not request. So a resolver may leave an older
|
|
6
|
+
openpyxl in place - and Odoo pins exactly 3.1.2 - after which every `.xlsx`
|
|
7
|
+
conversion dies with "Pandas requires version '3.1.5' or newer of 'openpyxl'",
|
|
8
|
+
reaching the caller as "no text could be extracted".
|
|
9
|
+
|
|
10
|
+
Guarded by a test because the declaration looks redundant: markitdown already
|
|
11
|
+
brings openpyxl in, so the line invites deletion during a tidy-up. It is not
|
|
12
|
+
redundant, it is the only place the version is stated.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import tomllib
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
|
|
20
|
+
PYPROJECT = Path(__file__).parent.parent.parent / "pyproject.toml"
|
|
21
|
+
# The version pandas declares for its Excel support. Raising this is fine;
|
|
22
|
+
# dropping below it reopens the defect.
|
|
23
|
+
REQUIRED_FLOOR = (3, 1, 5)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _docs_extra() -> list[str]:
|
|
27
|
+
with open(PYPROJECT, "rb") as handle:
|
|
28
|
+
data = tomllib.load(handle)
|
|
29
|
+
extras = data.get("project", {}).get("optional-dependencies", {})
|
|
30
|
+
assert "docs" in extras, "Missing [docs] extra in pyproject.toml"
|
|
31
|
+
return extras["docs"]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.mark.unit
|
|
35
|
+
def test_docs_extra_declares_openpyxl() -> None:
|
|
36
|
+
entries = [d for d in _docs_extra() if d.replace("-", "_").startswith("openpyxl")]
|
|
37
|
+
assert entries, (
|
|
38
|
+
"[docs] must declare openpyxl itself - markitdown[xlsx] requires it without a "
|
|
39
|
+
"version, and the >=3.1.5 floor pandas needs is stated nowhere else in the chain"
|
|
40
|
+
)
|
|
41
|
+
assert len(entries) == 1, f"Expected exactly one openpyxl entry, got: {entries}"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.mark.unit
|
|
45
|
+
def test_the_floor_is_high_enough_for_pandas() -> None:
|
|
46
|
+
"""Asserted by intent: raising the floor is fine, dropping under it is not."""
|
|
47
|
+
entry = next(d for d in _docs_extra() if d.startswith("openpyxl"))
|
|
48
|
+
floor_text = entry.split(">=", 1)[1].split(",", 1)[0].strip()
|
|
49
|
+
floor = tuple(int(part) for part in floor_text.split("."))
|
|
50
|
+
|
|
51
|
+
assert floor >= REQUIRED_FLOOR, (
|
|
52
|
+
f"openpyxl floor {floor_text} is below the {'.'.join(map(str, REQUIRED_FLOOR))} "
|
|
53
|
+
"that pandas requires for .xlsx - spreadsheets would fail at conversion time"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.mark.unit
|
|
58
|
+
def test_the_extra_still_fences_off_the_next_major() -> None:
|
|
59
|
+
entry = next(d for d in _docs_extra() if d.startswith("openpyxl"))
|
|
60
|
+
|
|
61
|
+
assert "<4" in entry, f"openpyxl entry should cap the next major: {entry}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{eq_chatbot_core-3.2.0 → eq_chatbot_core-3.2.1}/.planning/phases/00-codebase-cleanup/00-01-PLAN.md
RENAMED
|
File without changes
|
|
File without changes
|