abstractcore 2.4.5__tar.gz → 2.4.7__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 (165) hide show
  1. {abstractcore-2.4.5 → abstractcore-2.4.7}/PKG-INFO +108 -12
  2. {abstractcore-2.4.5 → abstractcore-2.4.7}/README.md +98 -8
  3. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/__init__.py +5 -1
  4. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/assets/session_schema.json +1 -1
  5. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/core/interface.py +7 -0
  6. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/core/session.py +28 -3
  7. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/core/types.py +25 -1
  8. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/anthropic_provider.py +20 -2
  9. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/base.py +24 -0
  10. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/huggingface_provider.py +44 -18
  11. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/lmstudio_provider.py +17 -4
  12. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/mlx_provider.py +36 -14
  13. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/mock_provider.py +17 -7
  14. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/ollama_provider.py +16 -4
  15. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/openai_provider.py +18 -5
  16. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/common_tools.py +651 -1
  17. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/utils/version.py +1 -1
  18. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore.egg-info/PKG-INFO +108 -12
  19. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore.egg-info/SOURCES.txt +2 -0
  20. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore.egg-info/requires.txt +10 -3
  21. {abstractcore-2.4.5 → abstractcore-2.4.7}/pyproject.toml +11 -3
  22. abstractcore-2.4.7/tests/test_seed_determinism.py +354 -0
  23. abstractcore-2.4.7/tests/test_seed_temperature_basic.py +189 -0
  24. {abstractcore-2.4.5 → abstractcore-2.4.7}/LICENSE +0 -0
  25. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/apps/__init__.py +0 -0
  26. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/apps/__main__.py +0 -0
  27. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/apps/app_config_utils.py +0 -0
  28. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/apps/extractor.py +0 -0
  29. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/apps/judge.py +0 -0
  30. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/apps/summarizer.py +0 -0
  31. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/architectures/__init__.py +0 -0
  32. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/architectures/detection.py +0 -0
  33. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/architectures/enums.py +0 -0
  34. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/assets/architecture_formats.json +0 -0
  35. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/assets/model_capabilities.json +0 -0
  36. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/cli/__init__.py +0 -0
  37. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/cli/main.py +0 -0
  38. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/cli/vision_config.py +0 -0
  39. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/core/__init__.py +0 -0
  40. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/core/enums.py +0 -0
  41. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/core/factory.py +0 -0
  42. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/core/retry.py +0 -0
  43. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/embeddings/__init__.py +0 -0
  44. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/embeddings/manager.py +0 -0
  45. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/embeddings/models.py +0 -0
  46. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/events/__init__.py +0 -0
  47. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/exceptions/__init__.py +0 -0
  48. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/__init__.py +0 -0
  49. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/auto_handler.py +0 -0
  50. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/base.py +0 -0
  51. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/capabilities.py +0 -0
  52. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/handlers/__init__.py +0 -0
  53. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/handlers/anthropic_handler.py +0 -0
  54. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/handlers/local_handler.py +0 -0
  55. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/handlers/openai_handler.py +0 -0
  56. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/processors/__init__.py +0 -0
  57. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/processors/image_processor.py +0 -0
  58. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/processors/office_processor.py +0 -0
  59. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/processors/pdf_processor.py +0 -0
  60. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/processors/text_processor.py +0 -0
  61. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/types.py +0 -0
  62. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/utils/__init__.py +0 -0
  63. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/utils/image_scaler.py +0 -0
  64. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/media/vision_fallback.py +0 -0
  65. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/processing/__init__.py +0 -0
  66. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/processing/basic_extractor.py +0 -0
  67. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/processing/basic_judge.py +0 -0
  68. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/processing/basic_summarizer.py +0 -0
  69. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/__init__.py +0 -0
  70. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/registry.py +0 -0
  71. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/providers/streaming.py +0 -0
  72. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/server/__init__.py +0 -0
  73. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/server/app.py +0 -0
  74. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/structured/__init__.py +0 -0
  75. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/structured/handler.py +0 -0
  76. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/structured/retry.py +0 -0
  77. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/__init__.py +0 -0
  78. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/core.py +0 -0
  79. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/handler.py +0 -0
  80. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/parser.py +0 -0
  81. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/registry.py +0 -0
  82. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/syntax_rewriter.py +0 -0
  83. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/tools/tag_rewriter.py +0 -0
  84. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/utils/__init__.py +0 -0
  85. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/utils/cli.py +0 -0
  86. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/utils/message_preprocessor.py +0 -0
  87. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/utils/self_fixes.py +0 -0
  88. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/utils/structured_logging.py +0 -0
  89. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore/utils/token_utils.py +0 -0
  90. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore.egg-info/dependency_links.txt +0 -0
  91. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore.egg-info/entry_points.txt +0 -0
  92. {abstractcore-2.4.5 → abstractcore-2.4.7}/abstractcore.egg-info/top_level.txt +0 -0
  93. {abstractcore-2.4.5 → abstractcore-2.4.7}/setup.cfg +0 -0
  94. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_agentic_cli_compatibility.py +0 -0
  95. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_all_specified_providers.py +0 -0
  96. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_basic_session.py +0 -0
  97. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_basic_summarizer.py +0 -0
  98. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_cli_media.py +0 -0
  99. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_complete_integration.py +0 -0
  100. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_comprehensive_events.py +0 -0
  101. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_consistency.py +0 -0
  102. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_core_components.py +0 -0
  103. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_critical_streaming_tool_fix.py +0 -0
  104. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_debug_server.py +0 -0
  105. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_direct_vs_server.py +0 -0
  106. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings.py +0 -0
  107. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings_integration.py +0 -0
  108. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings_llm_integration.py +0 -0
  109. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings_matrix_operations.py +0 -0
  110. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings_no_mock.py +0 -0
  111. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings_real.py +0 -0
  112. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings_semantic_validation.py +0 -0
  113. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_embeddings_simple.py +0 -0
  114. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_enhanced_prompt.py +0 -0
  115. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_environment_variable_tool_call_tags.py +0 -0
  116. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_factory.py +0 -0
  117. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_final_accuracy.py +0 -0
  118. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_final_comprehensive.py +0 -0
  119. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_final_graceful_errors.py +0 -0
  120. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_fixed_media.py +0 -0
  121. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_fixed_prompt.py +0 -0
  122. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_graceful_fallback.py +0 -0
  123. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_import_debug.py +0 -0
  124. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_integrated_functionality.py +0 -0
  125. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_lmstudio_context.py +0 -0
  126. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_media_import.py +0 -0
  127. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_media_server.py +0 -0
  128. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_ollama_tool_role_fix.py +0 -0
  129. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_openai_conversion_manual.py +0 -0
  130. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_openai_format_bug.py +0 -0
  131. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_openai_format_conversion.py +0 -0
  132. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_openai_media_integration.py +0 -0
  133. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_progressive_complexity.py +0 -0
  134. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_provider_basic_session.py +0 -0
  135. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_provider_connectivity.py +0 -0
  136. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_provider_simple_generation.py +0 -0
  137. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_provider_streaming.py +0 -0
  138. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_provider_token_translation.py +0 -0
  139. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_provider_tool_detection.py +0 -0
  140. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_providers.py +0 -0
  141. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_providers_comprehensive.py +0 -0
  142. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_providers_simple.py +0 -0
  143. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_real_models_comprehensive.py +0 -0
  144. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_retry_observability.py +0 -0
  145. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_retry_strategy.py +0 -0
  146. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_sensory_prompting.py +0 -0
  147. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_server_debug.py +0 -0
  148. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_server_embeddings_real.py +0 -0
  149. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_server_integration.py +0 -0
  150. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_stream_tool_calling.py +0 -0
  151. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_streaming_enhancements.py +0 -0
  152. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_streaming_tag_rewriting.py +0 -0
  153. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_structured_integration.py +0 -0
  154. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_structured_output.py +0 -0
  155. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_syntax_rewriter.py +0 -0
  156. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_text_only_model_experience.py +0 -0
  157. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_tool_calling.py +0 -0
  158. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_tool_execution_separation.py +0 -0
  159. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_unified_streaming.py +0 -0
  160. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_unload_memory.py +0 -0
  161. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_user_scenario_validation.py +0 -0
  162. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_vision_accuracy.py +0 -0
  163. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_vision_comprehensive.py +0 -0
  164. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_vision_fallback_improvement.py +0 -0
  165. {abstractcore-2.4.5 → abstractcore-2.4.7}/tests/test_wrong_model_fallback.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: abstractcore
3
- Version: 2.4.5
3
+ Version: 2.4.7
4
4
  Summary: Unified interface to all LLM providers with essential infrastructure for tool calling, streaming, and model management
5
5
  Author-email: Laurent-Philippe Albou <contact@abstractcore.ai>
6
6
  Maintainer-email: Laurent-Philippe Albou <contact@abstractcore.ai>
@@ -29,6 +29,7 @@ License-File: LICENSE
29
29
  Requires-Dist: pydantic<3.0.0,>=2.0.0
30
30
  Requires-Dist: httpx<1.0.0,>=0.24.0
31
31
  Requires-Dist: tiktoken<1.0.0,>=0.5.0
32
+ Requires-Dist: requests<3.0.0,>=2.25.0
32
33
  Provides-Extra: openai
33
34
  Requires-Dist: openai<2.0.0,>=1.0.0; extra == "openai"
34
35
  Provides-Extra: anthropic
@@ -46,6 +47,11 @@ Provides-Extra: embeddings
46
47
  Requires-Dist: sentence-transformers<4.0.0,>=2.7.0; extra == "embeddings"
47
48
  Requires-Dist: numpy<2.0.0,>=1.20.0; extra == "embeddings"
48
49
  Provides-Extra: processing
50
+ Provides-Extra: tools
51
+ Requires-Dist: beautifulsoup4<5.0.0,>=4.12.0; extra == "tools"
52
+ Requires-Dist: lxml<6.0.0,>=4.9.0; extra == "tools"
53
+ Requires-Dist: duckduckgo-search<4.0.0,>=3.8.0; extra == "tools"
54
+ Requires-Dist: psutil<6.0.0,>=5.9.0; extra == "tools"
49
55
  Provides-Extra: media
50
56
  Requires-Dist: Pillow<12.0.0,>=10.0.0; extra == "media"
51
57
  Requires-Dist: pymupdf4llm<1.0.0,>=0.0.20; extra == "media"
@@ -60,9 +66,9 @@ Requires-Dist: abstractcore[huggingface]; extra == "heavy-providers"
60
66
  Provides-Extra: all-providers
61
67
  Requires-Dist: abstractcore[anthropic,embeddings,huggingface,lmstudio,mlx,ollama,openai]; extra == "all-providers"
62
68
  Provides-Extra: all
63
- Requires-Dist: abstractcore[anthropic,dev,docs,embeddings,huggingface,lmstudio,media,mlx,ollama,openai,processing,server,test]; extra == "all"
69
+ Requires-Dist: abstractcore[anthropic,dev,docs,embeddings,huggingface,lmstudio,media,mlx,ollama,openai,processing,server,test,tools]; extra == "all"
64
70
  Provides-Extra: lightweight
65
- Requires-Dist: abstractcore[anthropic,embeddings,lmstudio,media,ollama,openai,processing,server]; extra == "lightweight"
71
+ Requires-Dist: abstractcore[anthropic,embeddings,lmstudio,media,ollama,openai,processing,server,tools]; extra == "lightweight"
66
72
  Provides-Extra: dev
67
73
  Requires-Dist: pytest>=7.0.0; extra == "dev"
68
74
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -89,7 +95,7 @@ Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
89
95
  Requires-Dist: mkdocstrings[python]>=0.22.0; extra == "docs"
90
96
  Requires-Dist: mkdocs-autorefs>=0.4.0; extra == "docs"
91
97
  Provides-Extra: full-dev
92
- Requires-Dist: abstractcore[all-providers,dev,docs,test]; extra == "full-dev"
98
+ Requires-Dist: abstractcore[all-providers,dev,docs,test,tools]; extra == "full-dev"
93
99
  Dynamic: license-file
94
100
 
95
101
  # AbstractCore
@@ -122,6 +128,21 @@ response = llm.generate("What is the capital of France?")
122
128
  print(response.content)
123
129
  ```
124
130
 
131
+ ### Deterministic Generation
132
+
133
+ ```python
134
+ from abstractcore import create_llm
135
+
136
+ # Deterministic outputs with seed + temperature=0
137
+ llm = create_llm("openai", model="gpt-3.5-turbo", seed=42, temperature=0.0)
138
+
139
+ # These will produce identical outputs
140
+ response1 = llm.generate("Write exactly 3 words about coding")
141
+ response2 = llm.generate("Write exactly 3 words about coding")
142
+ print(f"Response 1: {response1.content}") # "Innovative, challenging, rewarding."
143
+ print(f"Response 2: {response2.content}") # "Innovative, challenging, rewarding."
144
+ ```
145
+
125
146
  ### Tool Calling
126
147
 
127
148
  ```python
@@ -140,6 +161,78 @@ response = llm.generate(
140
161
  print(response.content)
141
162
  ```
142
163
 
164
+ ### Response Object (GenerateResponse)
165
+
166
+ Every LLM generation returns a **GenerateResponse** object with consistent structure across all providers:
167
+
168
+ ```python
169
+ from abstractcore import create_llm
170
+
171
+ llm = create_llm("openai", model="gpt-4o-mini")
172
+ response = llm.generate("Explain quantum computing in simple terms")
173
+
174
+ # Core response data
175
+ print(f"Content: {response.content}") # Generated text
176
+ print(f"Model: {response.model}") # Model used
177
+ print(f"Finish reason: {response.finish_reason}") # Why generation stopped
178
+
179
+ # Consistent token access across ALL providers (NEW in v2.4.7)
180
+ print(f"Input tokens: {response.input_tokens}") # Always available
181
+ print(f"Output tokens: {response.output_tokens}") # Always available
182
+ print(f"Total tokens: {response.total_tokens}") # Always available
183
+
184
+ # Generation time tracking (NEW in v2.4.7)
185
+ print(f"Generation time: {response.gen_time}ms") # Always available (rounded to 1 decimal)
186
+
187
+ # Advanced access
188
+ print(f"Tool calls: {response.tool_calls}") # Tools executed (if any)
189
+ print(f"Raw usage: {response.usage}") # Provider-specific token data
190
+ print(f"Metadata: {response.metadata}") # Additional context
191
+
192
+ # Comprehensive summary
193
+ print(f"Summary: {response.get_summary()}") # "Model: gpt-4o-mini | Tokens: 117 | Time: 1234.5ms"
194
+ ```
195
+
196
+ **Token Count Sources:**
197
+ - **Provider APIs**: OpenAI, Anthropic, LMStudio (native API token counts)
198
+ - **AbstractCore Calculation**: MLX, HuggingFace, Mock (using `token_utils.py`)
199
+ - **Mixed Sources**: Ollama (combination of provider and calculated tokens)
200
+
201
+ **Backward Compatibility**: Legacy `prompt_tokens` and `completion_tokens` keys remain available in `response.usage` dictionary.
202
+
203
+ ### Built-in Tools
204
+
205
+ AbstractCore includes a comprehensive set of ready-to-use tools for common tasks:
206
+
207
+ ```python
208
+ from abstractcore.tools.common_tools import fetch_url, search_files, read_file
209
+
210
+ # Intelligent web content fetching with automatic parsing
211
+ result = fetch_url("https://api.github.com/repos/python/cpython")
212
+ # Automatically detects JSON, HTML, images, PDFs, etc. and provides structured analysis
213
+
214
+ # File system operations
215
+ files = search_files("def.*fetch", ".", file_pattern="*.py") # Find function definitions
216
+ content = read_file("config.json") # Read file contents
217
+
218
+ # Use with any LLM
219
+ llm = create_llm("anthropic", model="claude-3-5-haiku-latest")
220
+ response = llm.generate(
221
+ "Analyze this API response and summarize the key information",
222
+ tools=[fetch_url]
223
+ )
224
+ ```
225
+
226
+ **Available Tools:**
227
+ - `fetch_url` - Intelligent web content fetching with automatic content type detection and parsing
228
+ - `search_files` - Search for text patterns inside files using regex
229
+ - `list_files` - Find and list files by names/paths using glob patterns
230
+ - `read_file` - Read file contents with optional line range selection
231
+ - `write_file` - Write content to files with directory creation
232
+ - `edit_file` - Edit files using pattern matching and replacement
233
+ - `web_search` - Search the web using DuckDuckGo
234
+ - `execute_command` - Execute shell commands safely with security controls
235
+
143
236
  ### Session Management
144
237
 
145
238
  ```python
@@ -223,19 +316,22 @@ response = llm.generate(
223
316
  - **Session Management**: Persistent conversations with metadata, analytics, and complete serialization
224
317
  - **Structured Responses**: Clean, predictable output formats with Pydantic
225
318
  - **Streaming Support**: Real-time token generation for interactive experiences
319
+ - **Consistent Token Terminology**: Unified `input_tokens`, `output_tokens`, `total_tokens` across all providers
226
320
  - **Embeddings**: Built-in support for semantic search and RAG applications
227
321
  - **Universal Server**: Optional OpenAI-compatible API server with `/v1/responses` endpoint
228
322
 
229
323
  ## Supported Providers
230
324
 
231
- | Provider | Status | Setup |
232
- |----------|--------|-------|
233
- | **OpenAI** | Full | [Get API key](docs/prerequisites.md#openai-setup) |
234
- | **Anthropic** | Full | [Get API key](docs/prerequisites.md#anthropic-setup) |
235
- | **Ollama** | Full | [Install guide](docs/prerequisites.md#ollama-setup) |
236
- | **LMStudio** | Full | [Install guide](docs/prerequisites.md#lmstudio-setup) |
237
- | **MLX** | Full | [Setup guide](docs/prerequisites.md#mlx-setup) |
238
- | **HuggingFace** | Full | [Setup guide](docs/prerequisites.md#huggingface-setup) |
325
+ | Provider | Status | SEED Support | Setup |
326
+ |----------|--------|-------------|-------|
327
+ | **OpenAI** | Full | ✅ Native | [Get API key](docs/prerequisites.md#openai-setup) |
328
+ | **Anthropic** | Full | ⚠️ Warning* | [Get API key](docs/prerequisites.md#anthropic-setup) |
329
+ | **Ollama** | Full | ✅ Native | [Install guide](docs/prerequisites.md#ollama-setup) |
330
+ | **LMStudio** | Full | ✅ Native | [Install guide](docs/prerequisites.md#lmstudio-setup) |
331
+ | **MLX** | Full | ✅ Native | [Setup guide](docs/prerequisites.md#mlx-setup) |
332
+ | **HuggingFace** | Full | ✅ Native | [Setup guide](docs/prerequisites.md#huggingface-setup) |
333
+
334
+ *Anthropic doesn't support seed parameters but issues a warning when provided. Use `temperature=0.0` for more consistent outputs.
239
335
 
240
336
  ## Server Mode (Optional HTTP REST API)
241
337
 
@@ -28,6 +28,21 @@ response = llm.generate("What is the capital of France?")
28
28
  print(response.content)
29
29
  ```
30
30
 
31
+ ### Deterministic Generation
32
+
33
+ ```python
34
+ from abstractcore import create_llm
35
+
36
+ # Deterministic outputs with seed + temperature=0
37
+ llm = create_llm("openai", model="gpt-3.5-turbo", seed=42, temperature=0.0)
38
+
39
+ # These will produce identical outputs
40
+ response1 = llm.generate("Write exactly 3 words about coding")
41
+ response2 = llm.generate("Write exactly 3 words about coding")
42
+ print(f"Response 1: {response1.content}") # "Innovative, challenging, rewarding."
43
+ print(f"Response 2: {response2.content}") # "Innovative, challenging, rewarding."
44
+ ```
45
+
31
46
  ### Tool Calling
32
47
 
33
48
  ```python
@@ -46,6 +61,78 @@ response = llm.generate(
46
61
  print(response.content)
47
62
  ```
48
63
 
64
+ ### Response Object (GenerateResponse)
65
+
66
+ Every LLM generation returns a **GenerateResponse** object with consistent structure across all providers:
67
+
68
+ ```python
69
+ from abstractcore import create_llm
70
+
71
+ llm = create_llm("openai", model="gpt-4o-mini")
72
+ response = llm.generate("Explain quantum computing in simple terms")
73
+
74
+ # Core response data
75
+ print(f"Content: {response.content}") # Generated text
76
+ print(f"Model: {response.model}") # Model used
77
+ print(f"Finish reason: {response.finish_reason}") # Why generation stopped
78
+
79
+ # Consistent token access across ALL providers (NEW in v2.4.7)
80
+ print(f"Input tokens: {response.input_tokens}") # Always available
81
+ print(f"Output tokens: {response.output_tokens}") # Always available
82
+ print(f"Total tokens: {response.total_tokens}") # Always available
83
+
84
+ # Generation time tracking (NEW in v2.4.7)
85
+ print(f"Generation time: {response.gen_time}ms") # Always available (rounded to 1 decimal)
86
+
87
+ # Advanced access
88
+ print(f"Tool calls: {response.tool_calls}") # Tools executed (if any)
89
+ print(f"Raw usage: {response.usage}") # Provider-specific token data
90
+ print(f"Metadata: {response.metadata}") # Additional context
91
+
92
+ # Comprehensive summary
93
+ print(f"Summary: {response.get_summary()}") # "Model: gpt-4o-mini | Tokens: 117 | Time: 1234.5ms"
94
+ ```
95
+
96
+ **Token Count Sources:**
97
+ - **Provider APIs**: OpenAI, Anthropic, LMStudio (native API token counts)
98
+ - **AbstractCore Calculation**: MLX, HuggingFace, Mock (using `token_utils.py`)
99
+ - **Mixed Sources**: Ollama (combination of provider and calculated tokens)
100
+
101
+ **Backward Compatibility**: Legacy `prompt_tokens` and `completion_tokens` keys remain available in `response.usage` dictionary.
102
+
103
+ ### Built-in Tools
104
+
105
+ AbstractCore includes a comprehensive set of ready-to-use tools for common tasks:
106
+
107
+ ```python
108
+ from abstractcore.tools.common_tools import fetch_url, search_files, read_file
109
+
110
+ # Intelligent web content fetching with automatic parsing
111
+ result = fetch_url("https://api.github.com/repos/python/cpython")
112
+ # Automatically detects JSON, HTML, images, PDFs, etc. and provides structured analysis
113
+
114
+ # File system operations
115
+ files = search_files("def.*fetch", ".", file_pattern="*.py") # Find function definitions
116
+ content = read_file("config.json") # Read file contents
117
+
118
+ # Use with any LLM
119
+ llm = create_llm("anthropic", model="claude-3-5-haiku-latest")
120
+ response = llm.generate(
121
+ "Analyze this API response and summarize the key information",
122
+ tools=[fetch_url]
123
+ )
124
+ ```
125
+
126
+ **Available Tools:**
127
+ - `fetch_url` - Intelligent web content fetching with automatic content type detection and parsing
128
+ - `search_files` - Search for text patterns inside files using regex
129
+ - `list_files` - Find and list files by names/paths using glob patterns
130
+ - `read_file` - Read file contents with optional line range selection
131
+ - `write_file` - Write content to files with directory creation
132
+ - `edit_file` - Edit files using pattern matching and replacement
133
+ - `web_search` - Search the web using DuckDuckGo
134
+ - `execute_command` - Execute shell commands safely with security controls
135
+
49
136
  ### Session Management
50
137
 
51
138
  ```python
@@ -129,19 +216,22 @@ response = llm.generate(
129
216
  - **Session Management**: Persistent conversations with metadata, analytics, and complete serialization
130
217
  - **Structured Responses**: Clean, predictable output formats with Pydantic
131
218
  - **Streaming Support**: Real-time token generation for interactive experiences
219
+ - **Consistent Token Terminology**: Unified `input_tokens`, `output_tokens`, `total_tokens` across all providers
132
220
  - **Embeddings**: Built-in support for semantic search and RAG applications
133
221
  - **Universal Server**: Optional OpenAI-compatible API server with `/v1/responses` endpoint
134
222
 
135
223
  ## Supported Providers
136
224
 
137
- | Provider | Status | Setup |
138
- |----------|--------|-------|
139
- | **OpenAI** | Full | [Get API key](docs/prerequisites.md#openai-setup) |
140
- | **Anthropic** | Full | [Get API key](docs/prerequisites.md#anthropic-setup) |
141
- | **Ollama** | Full | [Install guide](docs/prerequisites.md#ollama-setup) |
142
- | **LMStudio** | Full | [Install guide](docs/prerequisites.md#lmstudio-setup) |
143
- | **MLX** | Full | [Setup guide](docs/prerequisites.md#mlx-setup) |
144
- | **HuggingFace** | Full | [Setup guide](docs/prerequisites.md#huggingface-setup) |
225
+ | Provider | Status | SEED Support | Setup |
226
+ |----------|--------|-------------|-------|
227
+ | **OpenAI** | Full | ✅ Native | [Get API key](docs/prerequisites.md#openai-setup) |
228
+ | **Anthropic** | Full | ⚠️ Warning* | [Get API key](docs/prerequisites.md#anthropic-setup) |
229
+ | **Ollama** | Full | ✅ Native | [Install guide](docs/prerequisites.md#ollama-setup) |
230
+ | **LMStudio** | Full | ✅ Native | [Install guide](docs/prerequisites.md#lmstudio-setup) |
231
+ | **MLX** | Full | ✅ Native | [Setup guide](docs/prerequisites.md#mlx-setup) |
232
+ | **HuggingFace** | Full | ✅ Native | [Setup guide](docs/prerequisites.md#huggingface-setup) |
233
+
234
+ *Anthropic doesn't support seed parameters but issues a warning when provided. Use `temperature=0.0` for more consistent outputs.
145
235
 
146
236
  ## Server Mode (Optional HTTP REST API)
147
237
 
@@ -44,6 +44,9 @@ except ImportError:
44
44
  from .processing import BasicSummarizer, SummaryStyle, SummaryLength, BasicExtractor
45
45
  _has_processing = True
46
46
 
47
+ # Tools module (core functionality)
48
+ from .tools import tool
49
+
47
50
  __all__ = [
48
51
  'create_llm',
49
52
  'BasicSession',
@@ -54,7 +57,8 @@ __all__ = [
54
57
  'MessageRole',
55
58
  'ModelNotFoundError',
56
59
  'ProviderAPIError',
57
- 'AuthenticationError'
60
+ 'AuthenticationError',
61
+ 'tool'
58
62
  ]
59
63
 
60
64
  if _has_embeddings:
@@ -109,7 +109,7 @@
109
109
  "tokens_before": { "type": "integer" },
110
110
  "tokens_after": { "type": "integer" },
111
111
  "compression_ratio": { "type": "number" },
112
- "generation_time_ms": { "type": "number" }
112
+ "gen_time": { "type": "number" }
113
113
  }
114
114
  }
115
115
  },
@@ -70,6 +70,8 @@ class AbstractCoreInterface(ABC):
70
70
  max_tokens: Optional[int] = None,
71
71
  max_input_tokens: Optional[int] = None,
72
72
  max_output_tokens: int = 2048,
73
+ temperature: float = 0.7,
74
+ seed: Optional[int] = None,
73
75
  debug: bool = False,
74
76
  **kwargs):
75
77
  self.model = model
@@ -79,6 +81,11 @@ class AbstractCoreInterface(ABC):
79
81
  self.max_tokens = max_tokens
80
82
  self.max_input_tokens = max_input_tokens
81
83
  self.max_output_tokens = max_output_tokens
84
+
85
+ # Unified generation parameters
86
+ self.temperature = temperature
87
+ self.seed = seed
88
+
82
89
  self.debug = debug
83
90
 
84
91
  # Validate token parameters
@@ -32,8 +32,23 @@ class BasicSession:
32
32
  tool_timeout: Optional[float] = None,
33
33
  recovery_timeout: Optional[float] = None,
34
34
  auto_compact: bool = False,
35
- auto_compact_threshold: int = 6000):
36
- """Initialize basic session"""
35
+ auto_compact_threshold: int = 6000,
36
+ temperature: Optional[float] = None,
37
+ seed: Optional[int] = None):
38
+ """Initialize basic session
39
+
40
+ Args:
41
+ provider: LLM provider instance
42
+ system_prompt: System prompt for the session
43
+ tools: List of available tools
44
+ timeout: HTTP request timeout
45
+ tool_timeout: Tool execution timeout
46
+ recovery_timeout: Circuit breaker recovery timeout
47
+ auto_compact: Enable automatic conversation compaction
48
+ auto_compact_threshold: Token threshold for auto-compaction
49
+ temperature: Default temperature for generation (0.0-1.0)
50
+ seed: Default seed for deterministic generation
51
+ """
37
52
 
38
53
  self.provider = provider
39
54
  self.id = str(uuid.uuid4())
@@ -45,6 +60,10 @@ class BasicSession:
45
60
  self.auto_compact_threshold = auto_compact_threshold
46
61
  self._original_session = None # Track if this is a compacted session
47
62
 
63
+ # Store session-level generation parameters
64
+ self.temperature = temperature
65
+ self.seed = seed
66
+
48
67
  # Optional analytics fields
49
68
  self.summary = None
50
69
  self.assessment = None
@@ -189,6 +208,12 @@ class BasicSession:
189
208
  # Extract media parameter explicitly (fix for media parameter passing)
190
209
  media = kwargs.pop('media', None)
191
210
 
211
+ # Add session-level parameters if not overridden in kwargs
212
+ if 'temperature' not in kwargs and self.temperature is not None:
213
+ kwargs['temperature'] = self.temperature
214
+ if 'seed' not in kwargs and self.seed is not None:
215
+ kwargs['seed'] = self.seed
216
+
192
217
  # Call provider
193
218
  response = self.provider.generate(
194
219
  prompt=prompt,
@@ -735,7 +760,7 @@ class BasicSession:
735
760
  "tokens_before": original_tokens,
736
761
  "tokens_after": self._estimate_tokens_for_summary(summary_result.summary),
737
762
  "compression_ratio": self._calculate_compression_ratio(original_tokens, summary_result.summary),
738
- "generation_time_ms": duration_ms
763
+ "gen_time": duration_ms
739
764
  }
740
765
  }
741
766
 
@@ -91,6 +91,7 @@ class GenerateResponse:
91
91
  usage: Optional[Dict[str, int]] = None
92
92
  tool_calls: Optional[List[Dict[str, Any]]] = None
93
93
  metadata: Optional[Dict[str, Any]] = None
94
+ gen_time: Optional[float] = None # Generation time in milliseconds
94
95
 
95
96
  def has_tool_calls(self) -> bool:
96
97
  """Check if response contains tool calls"""
@@ -109,6 +110,29 @@ class GenerateResponse:
109
110
  parts.append(f"Model: {self.model}")
110
111
  if self.usage:
111
112
  parts.append(f"Tokens: {self.usage.get('total_tokens', 'unknown')}")
113
+ if self.gen_time:
114
+ parts.append(f"Time: {self.gen_time:.1f}ms")
112
115
  if self.tool_calls:
113
116
  parts.append(f"Tools: {len(self.tool_calls)} executed")
114
- return " | ".join(parts)
117
+ return " | ".join(parts)
118
+
119
+ @property
120
+ def input_tokens(self) -> Optional[int]:
121
+ """Get input tokens with consistent terminology (prompt_tokens or input_tokens)."""
122
+ if not self.usage:
123
+ return None
124
+ return self.usage.get('input_tokens') or self.usage.get('prompt_tokens')
125
+
126
+ @property
127
+ def output_tokens(self) -> Optional[int]:
128
+ """Get output tokens with consistent terminology (completion_tokens or output_tokens)."""
129
+ if not self.usage:
130
+ return None
131
+ return self.usage.get('output_tokens') or self.usage.get('completion_tokens')
132
+
133
+ @property
134
+ def total_tokens(self) -> Optional[int]:
135
+ """Get total tokens."""
136
+ if not self.usage:
137
+ return None
138
+ return self.usage.get('total_tokens')
@@ -47,8 +47,7 @@ class AnthropicProvider(BaseProvider):
47
47
  # Initialize tool handler
48
48
  self.tool_handler = UniversalToolHandler(model)
49
49
 
50
- # Store configuration (remove duplicate max_tokens)
51
- self.temperature = kwargs.get("temperature", 0.7)
50
+ # Store provider-specific configuration
52
51
  self.top_p = kwargs.get("top_p", 1.0)
53
52
  self.top_k = kwargs.get("top_k", None)
54
53
 
@@ -132,6 +131,19 @@ class AnthropicProvider(BaseProvider):
132
131
  if kwargs.get("top_k") or self.top_k:
133
132
  call_params["top_k"] = kwargs.get("top_k", self.top_k)
134
133
 
134
+ # Handle seed parameter (Anthropic doesn't support seed natively)
135
+ seed_value = kwargs.get("seed", self.seed)
136
+ if seed_value is not None:
137
+ import warnings
138
+ warnings.warn(
139
+ f"Seed parameter ({seed_value}) is not supported by Anthropic Claude API. "
140
+ f"For deterministic outputs, use temperature=0.0 which may provide more consistent results, "
141
+ f"though true determinism is not guaranteed.",
142
+ UserWarning,
143
+ stacklevel=3
144
+ )
145
+ self.logger.warning(f"Seed {seed_value} requested but not supported by Anthropic API")
146
+
135
147
  # Handle structured output using the "tool trick"
136
148
  structured_tool_name = None
137
149
  if response_model and PYDANTIC_AVAILABLE:
@@ -174,8 +186,14 @@ class AnthropicProvider(BaseProvider):
174
186
  if stream:
175
187
  return self._stream_response(call_params, tools)
176
188
  else:
189
+ # Track generation time
190
+ start_time = time.time()
177
191
  response = self.client.messages.create(**call_params)
192
+ gen_time = round((time.time() - start_time) * 1000, 1)
193
+
178
194
  formatted = self._format_response(response)
195
+ # Add generation time to response
196
+ formatted.gen_time = gen_time
179
197
 
180
198
  # Handle tool execution for Anthropic responses
181
199
  if tools and (formatted.has_tool_calls() or
@@ -570,8 +570,32 @@ class BaseProvider(AbstractCoreInterface, ABC):
570
570
  result_kwargs = kwargs.copy()
571
571
  result_kwargs["max_output_tokens"] = effective_max_output
572
572
 
573
+ # Add unified generation parameters with fallback hierarchy: kwargs → instance → defaults
574
+ result_kwargs["temperature"] = result_kwargs.get("temperature", self.temperature)
575
+ if self.seed is not None:
576
+ result_kwargs["seed"] = result_kwargs.get("seed", self.seed)
577
+
573
578
  return result_kwargs
574
579
 
580
+ def _extract_generation_params(self, **kwargs) -> Dict[str, Any]:
581
+ """
582
+ Extract generation parameters with consistent fallback hierarchy.
583
+
584
+ Returns:
585
+ Dict containing temperature, seed, and other generation parameters
586
+ """
587
+ params = {}
588
+
589
+ # Temperature (always present)
590
+ params["temperature"] = kwargs.get("temperature", self.temperature)
591
+
592
+ # Seed (only if not None)
593
+ seed_value = kwargs.get("seed", self.seed)
594
+ if seed_value is not None:
595
+ params["seed"] = seed_value
596
+
597
+ return params
598
+
575
599
  def _get_provider_max_tokens_param(self, kwargs: Dict[str, Any]) -> int:
576
600
  """
577
601
  Extract the appropriate max tokens parameter for this provider.