abstractcore 2.4.9__py3-none-any.whl → 2.5.2__py3-none-any.whl

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 (31) hide show
  1. abstractcore/apps/__main__.py +8 -1
  2. abstractcore/apps/deepsearch.py +644 -0
  3. abstractcore/apps/intent.py +614 -0
  4. abstractcore/assets/model_capabilities.json +50 -34
  5. abstractcore/config/__init__.py +10 -0
  6. abstractcore/{cli → config}/main.py +13 -1
  7. abstractcore/config/manager.py +355 -0
  8. abstractcore/core/session.py +46 -1
  9. abstractcore/processing/__init__.py +5 -1
  10. abstractcore/processing/basic_deepsearch.py +2173 -0
  11. abstractcore/processing/basic_intent.py +690 -0
  12. abstractcore/providers/anthropic_provider.py +1 -0
  13. abstractcore/providers/base.py +1 -0
  14. abstractcore/providers/huggingface_provider.py +95 -4
  15. abstractcore/providers/lmstudio_provider.py +14 -0
  16. abstractcore/providers/mlx_provider.py +76 -2
  17. abstractcore/providers/ollama_provider.py +6 -2
  18. abstractcore/providers/openai_provider.py +1 -0
  19. abstractcore/providers/registry.py +6 -6
  20. abstractcore/structured/handler.py +161 -1
  21. abstractcore/tools/common_tools.py +98 -3
  22. abstractcore/utils/cli.py +114 -1
  23. abstractcore/utils/version.py +1 -1
  24. {abstractcore-2.4.9.dist-info → abstractcore-2.5.2.dist-info}/METADATA +38 -18
  25. {abstractcore-2.4.9.dist-info → abstractcore-2.5.2.dist-info}/RECORD +30 -25
  26. {abstractcore-2.4.9.dist-info → abstractcore-2.5.2.dist-info}/entry_points.txt +6 -2
  27. abstractcore/cli/__init__.py +0 -9
  28. /abstractcore/{cli → config}/vision_config.py +0 -0
  29. {abstractcore-2.4.9.dist-info → abstractcore-2.5.2.dist-info}/WHEEL +0 -0
  30. {abstractcore-2.4.9.dist-info → abstractcore-2.5.2.dist-info}/licenses/LICENSE +0 -0
  31. {abstractcore-2.4.9.dist-info → abstractcore-2.5.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,355 @@
1
+ """
2
+ AbstractCore Configuration Manager
3
+
4
+ Provides centralized configuration management for AbstractCore.
5
+ """
6
+
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+ from typing import Dict, Any, Optional, Tuple
11
+ from dataclasses import dataclass, asdict
12
+
13
+
14
+ @dataclass
15
+ class VisionConfig:
16
+ """Vision configuration settings."""
17
+ strategy: str = "disabled"
18
+ caption_provider: Optional[str] = None
19
+ caption_model: Optional[str] = None
20
+ fallback_chain: list = None
21
+ local_models_path: Optional[str] = None
22
+
23
+ def __post_init__(self):
24
+ if self.fallback_chain is None:
25
+ self.fallback_chain = []
26
+
27
+
28
+ @dataclass
29
+ class EmbeddingsConfig:
30
+ """Embeddings configuration settings."""
31
+ provider: Optional[str] = "huggingface"
32
+ model: Optional[str] = "all-minilm-l6-v2"
33
+
34
+
35
+ @dataclass
36
+ class AppDefaults:
37
+ """Per-application default configurations."""
38
+ cli_provider: Optional[str] = "huggingface"
39
+ cli_model: Optional[str] = "unsloth/Qwen3-4B-Instruct-2507-GGUF"
40
+ summarizer_provider: Optional[str] = "huggingface"
41
+ summarizer_model: Optional[str] = "unsloth/Qwen3-4B-Instruct-2507-GGUF"
42
+ extractor_provider: Optional[str] = "huggingface"
43
+ extractor_model: Optional[str] = "unsloth/Qwen3-4B-Instruct-2507-GGUF"
44
+ judge_provider: Optional[str] = "huggingface"
45
+ judge_model: Optional[str] = "unsloth/Qwen3-4B-Instruct-2507-GGUF"
46
+ intent_provider: Optional[str] = "huggingface"
47
+ intent_model: Optional[str] = "unsloth/Qwen3-4B-Instruct-2507-GGUF"
48
+
49
+
50
+ @dataclass
51
+ class DefaultModels:
52
+ """Global default model configurations."""
53
+ global_provider: Optional[str] = None
54
+ global_model: Optional[str] = None
55
+ chat_model: Optional[str] = None
56
+ code_model: Optional[str] = None
57
+
58
+
59
+ @dataclass
60
+ class ApiKeysConfig:
61
+ """API keys configuration."""
62
+ openai: Optional[str] = None
63
+ anthropic: Optional[str] = None
64
+ google: Optional[str] = None
65
+
66
+
67
+ @dataclass
68
+ class CacheConfig:
69
+ """Cache configuration settings."""
70
+ default_cache_dir: str = "~/.cache/abstractcore"
71
+ huggingface_cache_dir: str = "~/.cache/huggingface"
72
+ local_models_cache_dir: str = "~/.abstractcore/models"
73
+
74
+
75
+ @dataclass
76
+ class LoggingConfig:
77
+ """Logging configuration settings."""
78
+ console_level: str = "WARNING"
79
+ file_level: str = "DEBUG"
80
+ file_logging_enabled: bool = False
81
+ log_base_dir: Optional[str] = None
82
+ verbatim_enabled: bool = True
83
+ console_json: bool = False
84
+ file_json: bool = True
85
+
86
+
87
+ @dataclass
88
+ class AbstractCoreConfig:
89
+ """Main configuration class."""
90
+ vision: VisionConfig
91
+ embeddings: EmbeddingsConfig
92
+ app_defaults: AppDefaults
93
+ default_models: DefaultModels
94
+ api_keys: ApiKeysConfig
95
+ cache: CacheConfig
96
+ logging: LoggingConfig
97
+
98
+ @classmethod
99
+ def default(cls):
100
+ """Create default configuration."""
101
+ return cls(
102
+ vision=VisionConfig(),
103
+ embeddings=EmbeddingsConfig(),
104
+ app_defaults=AppDefaults(),
105
+ default_models=DefaultModels(),
106
+ api_keys=ApiKeysConfig(),
107
+ cache=CacheConfig(),
108
+ logging=LoggingConfig()
109
+ )
110
+
111
+
112
+ class ConfigurationManager:
113
+ """Manages AbstractCore configuration."""
114
+
115
+ def __init__(self):
116
+ self.config_dir = Path.home() / ".abstractcore" / "config"
117
+ self.config_file = self.config_dir / "abstractcore.json"
118
+ self.config = self._load_config()
119
+
120
+ def _load_config(self) -> AbstractCoreConfig:
121
+ """Load configuration from file or create default."""
122
+ if self.config_file.exists():
123
+ try:
124
+ with open(self.config_file, 'r') as f:
125
+ data = json.load(f)
126
+ return self._dict_to_config(data)
127
+ except Exception:
128
+ # If loading fails, return default config
129
+ return AbstractCoreConfig.default()
130
+ else:
131
+ return AbstractCoreConfig.default()
132
+
133
+ def _dict_to_config(self, data: Dict[str, Any]) -> AbstractCoreConfig:
134
+ """Convert dictionary to config object."""
135
+ # Create config objects from dictionary data
136
+ vision = VisionConfig(**data.get('vision', {}))
137
+ embeddings = EmbeddingsConfig(**data.get('embeddings', {}))
138
+ app_defaults = AppDefaults(**data.get('app_defaults', {}))
139
+ default_models = DefaultModels(**data.get('default_models', {}))
140
+ api_keys = ApiKeysConfig(**data.get('api_keys', {}))
141
+ cache = CacheConfig(**data.get('cache', {}))
142
+ logging = LoggingConfig(**data.get('logging', {}))
143
+
144
+ return AbstractCoreConfig(
145
+ vision=vision,
146
+ embeddings=embeddings,
147
+ app_defaults=app_defaults,
148
+ default_models=default_models,
149
+ api_keys=api_keys,
150
+ cache=cache,
151
+ logging=logging
152
+ )
153
+
154
+ def _save_config(self):
155
+ """Save configuration to file."""
156
+ self.config_dir.mkdir(parents=True, exist_ok=True)
157
+
158
+ # Convert config to dictionary
159
+ config_dict = {
160
+ 'vision': asdict(self.config.vision),
161
+ 'embeddings': asdict(self.config.embeddings),
162
+ 'app_defaults': asdict(self.config.app_defaults),
163
+ 'default_models': asdict(self.config.default_models),
164
+ 'api_keys': asdict(self.config.api_keys),
165
+ 'cache': asdict(self.config.cache),
166
+ 'logging': asdict(self.config.logging)
167
+ }
168
+
169
+ with open(self.config_file, 'w') as f:
170
+ json.dump(config_dict, f, indent=2)
171
+
172
+ def set_vision_provider(self, provider: str, model: str) -> bool:
173
+ """Set vision provider and model."""
174
+ try:
175
+ self.config.vision.strategy = "two_stage"
176
+ self.config.vision.caption_provider = provider
177
+ self.config.vision.caption_model = model
178
+ self._save_config()
179
+ return True
180
+ except Exception:
181
+ return False
182
+
183
+ def set_vision_caption(self, model: str) -> bool:
184
+ """Set vision caption model (deprecated)."""
185
+ # Auto-detect provider from model name
186
+ provider = self._detect_provider_from_model(model)
187
+ if provider:
188
+ return self.set_vision_provider(provider, model)
189
+ return False
190
+
191
+ def _detect_provider_from_model(self, model: str) -> Optional[str]:
192
+ """Detect provider from model name."""
193
+ model_lower = model.lower()
194
+
195
+ if any(x in model_lower for x in ['qwen2.5vl', 'llama3.2-vision', 'llava']):
196
+ return "ollama"
197
+ elif any(x in model_lower for x in ['gpt-4', 'gpt-4o']):
198
+ return "openai"
199
+ elif any(x in model_lower for x in ['claude-3']):
200
+ return "anthropic"
201
+ elif '/' in model:
202
+ return "lmstudio"
203
+
204
+ return None
205
+
206
+ def get_status(self) -> Dict[str, Any]:
207
+ """Get configuration status."""
208
+ return {
209
+ "config_file": str(self.config_file),
210
+ "vision": {
211
+ "strategy": self.config.vision.strategy,
212
+ "status": "✅ Ready" if self.config.vision.caption_provider else "❌ Not configured",
213
+ "caption_provider": self.config.vision.caption_provider,
214
+ "caption_model": self.config.vision.caption_model
215
+ },
216
+ "app_defaults": {
217
+ "cli": {
218
+ "provider": self.config.app_defaults.cli_provider,
219
+ "model": self.config.app_defaults.cli_model
220
+ },
221
+ "summarizer": {
222
+ "provider": self.config.app_defaults.summarizer_provider,
223
+ "model": self.config.app_defaults.summarizer_model
224
+ },
225
+ "extractor": {
226
+ "provider": self.config.app_defaults.extractor_provider,
227
+ "model": self.config.app_defaults.extractor_model
228
+ },
229
+ "judge": {
230
+ "provider": self.config.app_defaults.judge_provider,
231
+ "model": self.config.app_defaults.judge_model
232
+ },
233
+ "intent": {
234
+ "provider": self.config.app_defaults.intent_provider,
235
+ "model": self.config.app_defaults.intent_model
236
+ }
237
+ },
238
+ "global_defaults": {
239
+ "provider": self.config.default_models.global_provider,
240
+ "model": self.config.default_models.global_model,
241
+ "chat_model": self.config.default_models.chat_model,
242
+ "code_model": self.config.default_models.code_model
243
+ },
244
+ "embeddings": {
245
+ "status": "✅ Ready",
246
+ "provider": self.config.embeddings.provider,
247
+ "model": self.config.embeddings.model
248
+ },
249
+ "streaming": {
250
+ "cli_stream_default": False # Default value
251
+ },
252
+ "logging": {
253
+ "console_level": self.config.logging.console_level,
254
+ "file_level": self.config.logging.file_level,
255
+ "file_logging_enabled": self.config.logging.file_logging_enabled
256
+ },
257
+ "cache": {
258
+ "default_cache_dir": self.config.cache.default_cache_dir
259
+ },
260
+ "api_keys": {
261
+ "openai": "✅ Set" if self.config.api_keys.openai else "❌ Not set",
262
+ "anthropic": "✅ Set" if self.config.api_keys.anthropic else "❌ Not set",
263
+ "google": "✅ Set" if self.config.api_keys.google else "❌ Not set"
264
+ }
265
+ }
266
+
267
+ def set_global_default_model(self, provider_model: str) -> bool:
268
+ """Set global default model in provider/model format."""
269
+ try:
270
+ if '/' in provider_model:
271
+ provider, model = provider_model.split('/', 1)
272
+ else:
273
+ # Assume it's just a model name, use default provider
274
+ provider = "ollama"
275
+ model = provider_model
276
+
277
+ self.config.default_models.global_provider = provider
278
+ self.config.default_models.global_model = model
279
+ self._save_config()
280
+ return True
281
+ except Exception:
282
+ return False
283
+
284
+ def set_app_default(self, app_name: str, provider: str, model: str) -> bool:
285
+ """Set app-specific default provider and model."""
286
+ try:
287
+ if app_name == "cli":
288
+ self.config.app_defaults.cli_provider = provider
289
+ self.config.app_defaults.cli_model = model
290
+ elif app_name == "summarizer":
291
+ self.config.app_defaults.summarizer_provider = provider
292
+ self.config.app_defaults.summarizer_model = model
293
+ elif app_name == "extractor":
294
+ self.config.app_defaults.extractor_provider = provider
295
+ self.config.app_defaults.extractor_model = model
296
+ elif app_name == "judge":
297
+ self.config.app_defaults.judge_provider = provider
298
+ self.config.app_defaults.judge_model = model
299
+ elif app_name == "intent":
300
+ self.config.app_defaults.intent_provider = provider
301
+ self.config.app_defaults.intent_model = model
302
+ else:
303
+ raise ValueError(f"Unknown app: {app_name}")
304
+
305
+ self._save_config()
306
+ return True
307
+ except Exception:
308
+ return False
309
+
310
+ def set_api_key(self, provider: str, key: str) -> bool:
311
+ """Set API key for a provider."""
312
+ try:
313
+ if provider == "openai":
314
+ self.config.api_keys.openai = key
315
+ elif provider == "anthropic":
316
+ self.config.api_keys.anthropic = key
317
+ elif provider == "google":
318
+ self.config.api_keys.google = key
319
+ else:
320
+ return False
321
+
322
+ self._save_config()
323
+ return True
324
+ except Exception:
325
+ return False
326
+
327
+ def get_app_default(self, app_name: str) -> Tuple[str, str]:
328
+ """Get default provider and model for an app."""
329
+ app_defaults = self.config.app_defaults
330
+
331
+ if app_name == "cli":
332
+ return app_defaults.cli_provider, app_defaults.cli_model
333
+ elif app_name == "summarizer":
334
+ return app_defaults.summarizer_provider, app_defaults.summarizer_model
335
+ elif app_name == "extractor":
336
+ return app_defaults.extractor_provider, app_defaults.extractor_model
337
+ elif app_name == "judge":
338
+ return app_defaults.judge_provider, app_defaults.judge_model
339
+ elif app_name == "intent":
340
+ return app_defaults.intent_provider, app_defaults.intent_model
341
+ else:
342
+ # Return default fallback
343
+ return "huggingface", "unsloth/Qwen3-4B-Instruct-2507-GGUF"
344
+
345
+
346
+ # Global instance
347
+ _config_manager = None
348
+
349
+
350
+ def get_config_manager() -> ConfigurationManager:
351
+ """Get the global configuration manager instance."""
352
+ global _config_manager
353
+ if _config_manager is None:
354
+ _config_manager = ConfigurationManager()
355
+ return _config_manager
@@ -893,4 +893,49 @@ class BasicSession:
893
893
  "statistics": extraction_result.get("statistics", {})
894
894
  }
895
895
 
896
- return self.facts
896
+ return self.facts
897
+
898
+ def analyze_intents(self,
899
+ focus_participant: Optional[str] = None,
900
+ depth: str = "underlying",
901
+ context_type: str = "conversational") -> Dict[str, Any]:
902
+ """
903
+ Analyze intents in the conversation using BasicIntentAnalyzer.
904
+
905
+ Args:
906
+ focus_participant: Optional role to focus analysis on (e.g., "user", "assistant")
907
+ depth: Depth of intent analysis ("surface", "underlying", "comprehensive")
908
+ context_type: Context type for analysis ("conversational" is default for sessions)
909
+
910
+ Returns:
911
+ Dict containing intent analysis results for each participant
912
+ """
913
+ if not self.messages:
914
+ return {}
915
+
916
+ if not self.provider:
917
+ raise ValueError("No provider available for intent analysis")
918
+
919
+ try:
920
+ from ..processing import BasicIntentAnalyzer, IntentDepth, IntentContext
921
+ except ImportError:
922
+ raise ImportError("BasicIntentAnalyzer not available")
923
+
924
+ # Create intent analyzer
925
+ analyzer = BasicIntentAnalyzer(self.provider)
926
+
927
+ # Convert depth and context strings to enums
928
+ depth_enum = IntentDepth(depth)
929
+ context_enum = IntentContext(context_type)
930
+
931
+ # Convert session messages to the format expected by analyze_conversation_intents
932
+ message_dicts = [{"role": msg.role, "content": msg.content} for msg in self.messages]
933
+
934
+ # Analyze conversation intents
935
+ results = analyzer.analyze_conversation_intents(
936
+ messages=message_dicts,
937
+ focus_participant=focus_participant,
938
+ depth=depth_enum
939
+ )
940
+
941
+ return results
@@ -8,9 +8,13 @@ demonstrating how to leverage the core infrastructure for real-world tasks.
8
8
  from .basic_summarizer import BasicSummarizer, SummaryStyle, SummaryLength
9
9
  from .basic_extractor import BasicExtractor
10
10
  from .basic_judge import BasicJudge, JudgmentCriteria, Assessment, create_judge
11
+ from .basic_deepsearch import BasicDeepSearch, ResearchReport, ResearchFinding, ResearchPlan, ResearchSubTask
12
+ from .basic_intent import BasicIntentAnalyzer, IntentType, IntentDepth, IntentContext, IdentifiedIntent, IntentAnalysisOutput
11
13
 
12
14
  __all__ = [
13
15
  'BasicSummarizer', 'SummaryStyle', 'SummaryLength',
14
16
  'BasicExtractor',
15
- 'BasicJudge', 'JudgmentCriteria', 'Assessment', 'create_judge'
17
+ 'BasicJudge', 'JudgmentCriteria', 'Assessment', 'create_judge',
18
+ 'BasicDeepSearch', 'ResearchReport', 'ResearchFinding', 'ResearchPlan', 'ResearchSubTask',
19
+ 'BasicIntentAnalyzer', 'IntentType', 'IntentDepth', 'IntentContext', 'IdentifiedIntent', 'IntentAnalysisOutput'
16
20
  ]