abstractcore 2.6.6__tar.gz → 2.6.8__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.
- {abstractcore-2.6.6 → abstractcore-2.6.8}/PKG-INFO +46 -1
- {abstractcore-2.6.6 → abstractcore-2.6.8}/README.md +44 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/assets/model_capabilities.json +14 -5
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/utils/image_scaler.py +1 -8
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/processing/__init__.py +2 -2
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/processing/basic_summarizer.py +79 -10
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/base.py +22 -1
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/server/app.py +51 -2
- abstractcore-2.6.8/abstractcore/tools/__init__.py +122 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/tools/common_tools.py +177 -15
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/tools/parser.py +96 -4
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/tools/registry.py +15 -16
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/version.py +1 -1
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/vlm_token_calculator.py +1 -6
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore.egg-info/PKG-INFO +46 -1
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore.egg-info/requires.txt +1 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/pyproject.toml +1 -0
- abstractcore-2.6.6/abstractcore/tools/__init__.py +0 -101
- {abstractcore-2.6.6 → abstractcore-2.6.8}/LICENSE +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/__main__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/app_config_utils.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/deepsearch.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/extractor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/intent.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/judge.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/apps/summarizer.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/architectures/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/architectures/detection.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/architectures/enums.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/assets/architecture_formats.json +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/assets/session_schema.json +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/analytics.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/cache.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/config.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/exceptions.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/glyph_processor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/optimizer.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/orchestrator.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/pil_text_renderer.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/quality.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/text_formatter.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/compression/vision_compressor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/config/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/config/main.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/config/manager.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/config/vision_config.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/core/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/core/enums.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/core/factory.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/core/interface.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/core/retry.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/core/session.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/core/types.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/download.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/embeddings/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/embeddings/manager.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/embeddings/models.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/events/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/exceptions/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/auto_handler.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/base.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/capabilities.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/handlers/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/handlers/anthropic_handler.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/handlers/local_handler.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/handlers/openai_handler.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/processors/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/processors/direct_pdf_processor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/processors/glyph_pdf_processor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/processors/image_processor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/processors/office_processor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/processors/pdf_processor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/processors/text_processor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/types.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/utils/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/media/vision_fallback.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/processing/basic_deepsearch.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/processing/basic_extractor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/processing/basic_intent.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/processing/basic_judge.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/anthropic_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/huggingface_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/lmstudio_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/mlx_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/model_capabilities.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/ollama_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/openai_compatible_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/openai_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/registry.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/streaming.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/providers/vllm_provider.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/server/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/structured/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/structured/handler.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/structured/retry.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/tools/core.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/tools/handler.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/tools/syntax_rewriter.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/tools/tag_rewriter.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/__init__.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/cli.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/message_preprocessor.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/self_fixes.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/structured_logging.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/token_utils.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore/utils/trace_export.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore.egg-info/SOURCES.txt +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore.egg-info/dependency_links.txt +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore.egg-info/entry_points.txt +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/abstractcore.egg-info/top_level.txt +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/setup.cfg +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_agentic_cli_compatibility.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_basic_session.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_complete_integration.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_comprehensive_events.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_core_components.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_enhanced_prompt.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_environment_variable_tool_call_tags.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_factory.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_final_accuracy.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_final_comprehensive.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_final_graceful_errors.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_graceful_fallback.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_import_debug.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_integrated_functionality.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_retry_observability.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_retry_strategy.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_seed_determinism.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_seed_temperature_basic.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_sensory_prompting.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_text_only_model_experience.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_unload_memory.py +0 -0
- {abstractcore-2.6.6 → abstractcore-2.6.8}/tests/test_user_scenario_validation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: abstractcore
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.8
|
|
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>
|
|
@@ -30,6 +30,7 @@ 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
32
|
Requires-Dist: requests<3.0.0,>=2.25.0
|
|
33
|
+
Requires-Dist: Pillow<12.0.0,>=10.0.0
|
|
33
34
|
Provides-Extra: openai
|
|
34
35
|
Requires-Dist: openai<2.0.0,>=1.0.0; extra == "openai"
|
|
35
36
|
Provides-Extra: anthropic
|
|
@@ -194,6 +195,50 @@ response = llm.generate(
|
|
|
194
195
|
print(response.content)
|
|
195
196
|
```
|
|
196
197
|
|
|
198
|
+
### Tool Execution Modes
|
|
199
|
+
|
|
200
|
+
AbstractCore supports two tool execution modes:
|
|
201
|
+
|
|
202
|
+
**Mode 1: Passthrough (Default)** - Returns raw tool call tags for downstream processing
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
from abstractcore import create_llm
|
|
206
|
+
from abstractcore.tools import tool
|
|
207
|
+
|
|
208
|
+
@tool(name="get_weather", description="Get weather for a city")
|
|
209
|
+
def get_weather(city: str) -> str:
|
|
210
|
+
return f"Weather in {city}: Sunny, 22°C"
|
|
211
|
+
|
|
212
|
+
llm = create_llm("ollama", model="qwen3:4b") # execute_tools=False by default
|
|
213
|
+
response = llm.generate("What's the weather in Paris?", tools=[get_weather])
|
|
214
|
+
# response.content contains raw tool call tags: <|tool_call|>...
|
|
215
|
+
# Downstream runtime (AbstractRuntime, Codex, Claude Code) parses and executes
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Use case**: Agent loops, AbstractRuntime, Codex, Claude Code, custom orchestration
|
|
219
|
+
|
|
220
|
+
**Mode 2: Direct Execution** - AbstractCore executes tools and returns results
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
from abstractcore import create_llm
|
|
224
|
+
from abstractcore.tools import tool
|
|
225
|
+
from abstractcore.tools.registry import register_tool
|
|
226
|
+
|
|
227
|
+
@tool(name="get_weather", description="Get weather for a city")
|
|
228
|
+
def get_weather(city: str) -> str:
|
|
229
|
+
return f"Weather in {city}: Sunny, 22°C"
|
|
230
|
+
|
|
231
|
+
register_tool(get_weather) # Required for direct execution
|
|
232
|
+
|
|
233
|
+
llm = create_llm("ollama", model="qwen3:4b", execute_tools=True)
|
|
234
|
+
response = llm.generate("What's the weather in Paris?", tools=[get_weather])
|
|
235
|
+
# response.content contains executed tool results
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Use case**: Simple scripts, single-turn tool use
|
|
239
|
+
|
|
240
|
+
> **Note**: The `@tool` decorator creates metadata but does NOT register globally. Tools are passed explicitly to `generate()`. Use `register_tool()` only when using direct execution mode.
|
|
241
|
+
|
|
197
242
|
### Response Object (GenerateResponse)
|
|
198
243
|
|
|
199
244
|
Every LLM generation returns a **GenerateResponse** object with consistent structure across all providers:
|
|
@@ -65,6 +65,50 @@ response = llm.generate(
|
|
|
65
65
|
print(response.content)
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
### Tool Execution Modes
|
|
69
|
+
|
|
70
|
+
AbstractCore supports two tool execution modes:
|
|
71
|
+
|
|
72
|
+
**Mode 1: Passthrough (Default)** - Returns raw tool call tags for downstream processing
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from abstractcore import create_llm
|
|
76
|
+
from abstractcore.tools import tool
|
|
77
|
+
|
|
78
|
+
@tool(name="get_weather", description="Get weather for a city")
|
|
79
|
+
def get_weather(city: str) -> str:
|
|
80
|
+
return f"Weather in {city}: Sunny, 22°C"
|
|
81
|
+
|
|
82
|
+
llm = create_llm("ollama", model="qwen3:4b") # execute_tools=False by default
|
|
83
|
+
response = llm.generate("What's the weather in Paris?", tools=[get_weather])
|
|
84
|
+
# response.content contains raw tool call tags: <|tool_call|>...
|
|
85
|
+
# Downstream runtime (AbstractRuntime, Codex, Claude Code) parses and executes
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Use case**: Agent loops, AbstractRuntime, Codex, Claude Code, custom orchestration
|
|
89
|
+
|
|
90
|
+
**Mode 2: Direct Execution** - AbstractCore executes tools and returns results
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from abstractcore import create_llm
|
|
94
|
+
from abstractcore.tools import tool
|
|
95
|
+
from abstractcore.tools.registry import register_tool
|
|
96
|
+
|
|
97
|
+
@tool(name="get_weather", description="Get weather for a city")
|
|
98
|
+
def get_weather(city: str) -> str:
|
|
99
|
+
return f"Weather in {city}: Sunny, 22°C"
|
|
100
|
+
|
|
101
|
+
register_tool(get_weather) # Required for direct execution
|
|
102
|
+
|
|
103
|
+
llm = create_llm("ollama", model="qwen3:4b", execute_tools=True)
|
|
104
|
+
response = llm.generate("What's the weather in Paris?", tools=[get_weather])
|
|
105
|
+
# response.content contains executed tool results
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Use case**: Simple scripts, single-turn tool use
|
|
109
|
+
|
|
110
|
+
> **Note**: The `@tool` decorator creates metadata but does NOT register globally. Tools are passed explicitly to `generate()`. Use `register_tool()` only when using direct execution mode.
|
|
111
|
+
|
|
68
112
|
### Response Object (GenerateResponse)
|
|
69
113
|
|
|
70
114
|
Every LLM generation returns a **GenerateResponse** object with consistent structure across all providers:
|
|
@@ -638,17 +638,26 @@
|
|
|
638
638
|
"max_tokens": 262144
|
|
639
639
|
},
|
|
640
640
|
"qwen3-coder-30b": {
|
|
641
|
-
"max_output_tokens":
|
|
641
|
+
"max_output_tokens": 65536,
|
|
642
642
|
"tool_support": "native",
|
|
643
643
|
"structured_output": "native",
|
|
644
644
|
"parallel_tools": true,
|
|
645
645
|
"vision_support": false,
|
|
646
646
|
"audio_support": false,
|
|
647
|
-
"
|
|
648
|
-
"
|
|
647
|
+
"architecture": "mixture_of_experts",
|
|
648
|
+
"total_parameters": "30.5B",
|
|
649
|
+
"active_parameters": "3.3B",
|
|
650
|
+
"experts": 128,
|
|
651
|
+
"experts_activated": 8,
|
|
652
|
+
"notes": "Code-focused MoE model (30.5B total/3.3B active, 128 experts/8 activated). Native tool support via chatml-function-calling format. Supports up to 1M tokens with YaRN extension.",
|
|
653
|
+
"source": "Qwen HuggingFace model card 2025",
|
|
649
654
|
"canonical_name": "qwen3-coder-30b",
|
|
650
|
-
"aliases": [
|
|
651
|
-
|
|
655
|
+
"aliases": [
|
|
656
|
+
"Qwen/Qwen3-Coder-30B-A3B-Instruct",
|
|
657
|
+
"qwen3-coder-30b-a3b",
|
|
658
|
+
"qwen3-coder-30b-a3b-instruct"
|
|
659
|
+
],
|
|
660
|
+
"max_tokens": 262144
|
|
652
661
|
},
|
|
653
662
|
"qwen2-vl": {
|
|
654
663
|
"max_output_tokens": 8192,
|
|
@@ -3,20 +3,13 @@ Image scaling utility for AbstractCore media handling.
|
|
|
3
3
|
|
|
4
4
|
Provides intelligent image scaling based on model-specific requirements
|
|
5
5
|
and capabilities for vision models.
|
|
6
|
-
|
|
7
|
-
Requires: PIL (Pillow) - install with `pip install Pillow`
|
|
8
6
|
"""
|
|
9
7
|
|
|
10
8
|
from typing import Tuple, Optional, Union, Dict, Any
|
|
11
9
|
from enum import Enum
|
|
12
10
|
from pathlib import Path
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
from PIL import Image, ImageOps
|
|
16
|
-
except ImportError as e:
|
|
17
|
-
raise ImportError(
|
|
18
|
-
"PIL (Pillow) is required for image scaling. Install with: pip install Pillow"
|
|
19
|
-
) from e
|
|
12
|
+
from PIL import Image, ImageOps
|
|
20
13
|
|
|
21
14
|
from ..base import MediaProcessingError
|
|
22
15
|
from ...utils.structured_logging import get_logger
|
|
@@ -5,14 +5,14 @@ Basic text processing capabilities built on top of AbstractCore,
|
|
|
5
5
|
demonstrating how to leverage the core infrastructure for real-world tasks.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from .basic_summarizer import BasicSummarizer, SummaryStyle, SummaryLength
|
|
8
|
+
from .basic_summarizer import BasicSummarizer, SummaryStyle, SummaryLength, CompressionMode
|
|
9
9
|
from .basic_extractor import BasicExtractor
|
|
10
10
|
from .basic_judge import BasicJudge, JudgmentCriteria, Assessment, create_judge
|
|
11
11
|
from .basic_deepsearch import BasicDeepSearch, ResearchReport, ResearchFinding, ResearchPlan, ResearchSubTask
|
|
12
12
|
from .basic_intent import BasicIntentAnalyzer, IntentType, IntentDepth, IntentContext, IdentifiedIntent, IntentAnalysisOutput
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
15
|
-
'BasicSummarizer', 'SummaryStyle', 'SummaryLength',
|
|
15
|
+
'BasicSummarizer', 'SummaryStyle', 'SummaryLength', 'CompressionMode',
|
|
16
16
|
'BasicExtractor',
|
|
17
17
|
'BasicJudge', 'JudgmentCriteria', 'Assessment', 'create_judge',
|
|
18
18
|
'BasicDeepSearch', 'ResearchReport', 'ResearchFinding', 'ResearchPlan', 'ResearchSubTask',
|
|
@@ -35,6 +35,42 @@ class SummaryLength(Enum):
|
|
|
35
35
|
COMPREHENSIVE = "comprehensive" # Full analysis with context
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
class CompressionMode(Enum):
|
|
39
|
+
"""Compression aggressiveness for chat history summarization.
|
|
40
|
+
|
|
41
|
+
Controls how aggressively the summarizer compresses conversation history:
|
|
42
|
+
- LIGHT: Keep most information, only remove redundancy
|
|
43
|
+
- STANDARD: Balanced compression, main points and context
|
|
44
|
+
- HEAVY: Aggressive compression, only critical information
|
|
45
|
+
"""
|
|
46
|
+
LIGHT = "light"
|
|
47
|
+
STANDARD = "standard"
|
|
48
|
+
HEAVY = "heavy"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Compression mode-specific instructions for summarization prompts
|
|
52
|
+
COMPRESSION_INSTRUCTIONS = {
|
|
53
|
+
CompressionMode.LIGHT: (
|
|
54
|
+
"Preserve most details from this conversation while removing only redundancy. "
|
|
55
|
+
"Keep: all key decisions and outcomes, important context and background, "
|
|
56
|
+
"specific details/names/numbers/technical terms, all tool calls and results, "
|
|
57
|
+
"error messages and resolutions. Remove only: repetitive greetings, duplicate information."
|
|
58
|
+
),
|
|
59
|
+
CompressionMode.STANDARD: (
|
|
60
|
+
"Summarize with balanced compression, keeping main points and essential context. "
|
|
61
|
+
"Keep: key decisions and rationale, important outcomes, critical context for ongoing work, "
|
|
62
|
+
"unresolved items and pending tasks. Remove: intermediate reasoning steps, "
|
|
63
|
+
"exploratory tangents, detailed tool outputs (keep only key findings)."
|
|
64
|
+
),
|
|
65
|
+
CompressionMode.HEAVY: (
|
|
66
|
+
"Extract only the most critical information. Keep ONLY: final decisions made, "
|
|
67
|
+
"critical outcomes (success/failure), essential context to continue work, "
|
|
68
|
+
"blocking issues and hard dependencies. Remove: all exploratory discussion, "
|
|
69
|
+
"all intermediate steps, all detailed outputs, all background explanations."
|
|
70
|
+
),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
38
74
|
class LLMSummaryOutput(BaseModel):
|
|
39
75
|
"""LLM-generated summary output (without word counts)"""
|
|
40
76
|
summary: str = Field(description="The main summary text")
|
|
@@ -493,7 +529,8 @@ Create a unified summary that represents the entire document effectively."""
|
|
|
493
529
|
self,
|
|
494
530
|
messages: List[dict],
|
|
495
531
|
preserve_recent: int = 6,
|
|
496
|
-
focus: Optional[str] = None
|
|
532
|
+
focus: Optional[str] = None,
|
|
533
|
+
compression_mode: CompressionMode = CompressionMode.STANDARD
|
|
497
534
|
) -> SummaryOutput:
|
|
498
535
|
"""
|
|
499
536
|
Specialized method for chat history summarization following SOTA 2025 practices
|
|
@@ -502,6 +539,7 @@ Create a unified summary that represents the entire document effectively."""
|
|
|
502
539
|
messages: List of message dicts with 'role' and 'content' keys
|
|
503
540
|
preserve_recent: Number of recent messages to keep intact (default 6)
|
|
504
541
|
focus: Optional focus for summarization (e.g., "key decisions", "technical solutions")
|
|
542
|
+
compression_mode: How aggressively to compress (LIGHT, STANDARD, HEAVY)
|
|
505
543
|
|
|
506
544
|
Returns:
|
|
507
545
|
SummaryOutput: Structured summary optimized for chat history context
|
|
@@ -511,36 +549,67 @@ Create a unified summary that represents the entire document effectively."""
|
|
|
511
549
|
- Focuses on decisions, solutions, and ongoing topics
|
|
512
550
|
- Maintains user intent and assistant responses
|
|
513
551
|
- Optimized for chat continuation rather than standalone summary
|
|
552
|
+
|
|
553
|
+
Compression Modes:
|
|
554
|
+
- LIGHT: Keep most information, only remove redundancy
|
|
555
|
+
- STANDARD: Balanced compression, main points and context
|
|
556
|
+
- HEAVY: Aggressive compression, only critical information
|
|
514
557
|
"""
|
|
558
|
+
# Build focus with compression instructions
|
|
559
|
+
compression_instruction = COMPRESSION_INSTRUCTIONS.get(
|
|
560
|
+
compression_mode,
|
|
561
|
+
COMPRESSION_INSTRUCTIONS[CompressionMode.STANDARD]
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
# Combine user focus with compression instruction
|
|
565
|
+
if focus:
|
|
566
|
+
effective_focus = f"{compression_instruction} Focus especially on: {focus}"
|
|
567
|
+
else:
|
|
568
|
+
effective_focus = compression_instruction
|
|
569
|
+
|
|
570
|
+
# Map compression mode to summary length for appropriate output size
|
|
571
|
+
length_map = {
|
|
572
|
+
CompressionMode.LIGHT: SummaryLength.DETAILED,
|
|
573
|
+
CompressionMode.STANDARD: SummaryLength.STANDARD,
|
|
574
|
+
CompressionMode.HEAVY: SummaryLength.BRIEF,
|
|
575
|
+
}
|
|
576
|
+
target_length = length_map.get(compression_mode, SummaryLength.STANDARD)
|
|
577
|
+
|
|
578
|
+
logger.debug("Chat history summarization with compression mode",
|
|
579
|
+
message_count=len(messages),
|
|
580
|
+
preserve_recent=preserve_recent,
|
|
581
|
+
compression_mode=compression_mode.value,
|
|
582
|
+
target_length=target_length.value)
|
|
583
|
+
|
|
515
584
|
if len(messages) <= preserve_recent:
|
|
516
585
|
# If short enough, just summarize normally
|
|
517
|
-
logger.debug("Chat history is short, using standard summarization",
|
|
518
|
-
message_count=len(messages),
|
|
586
|
+
logger.debug("Chat history is short, using standard summarization",
|
|
587
|
+
message_count=len(messages),
|
|
519
588
|
preserve_recent=preserve_recent)
|
|
520
589
|
chat_text = self._format_chat_messages_to_text(messages)
|
|
521
590
|
return self.summarize(
|
|
522
591
|
chat_text,
|
|
523
|
-
focus=
|
|
592
|
+
focus=effective_focus,
|
|
524
593
|
style=SummaryStyle.CONVERSATIONAL,
|
|
525
|
-
length=
|
|
594
|
+
length=target_length
|
|
526
595
|
)
|
|
527
596
|
|
|
528
597
|
# Split into older messages (to summarize) and recent messages (to preserve)
|
|
529
598
|
older_messages = messages[:-preserve_recent]
|
|
530
599
|
recent_messages = messages[-preserve_recent:]
|
|
531
|
-
|
|
532
|
-
logger.debug("Splitting chat history for summarization",
|
|
600
|
+
|
|
601
|
+
logger.debug("Splitting chat history for summarization",
|
|
533
602
|
total_messages=len(messages),
|
|
534
603
|
older_messages=len(older_messages),
|
|
535
604
|
recent_messages=len(recent_messages))
|
|
536
605
|
|
|
537
|
-
# Summarize older messages with conversational focus
|
|
606
|
+
# Summarize older messages with conversational focus and compression mode
|
|
538
607
|
older_text = self._format_chat_messages_to_text(older_messages)
|
|
539
608
|
older_summary = self.summarize(
|
|
540
609
|
older_text,
|
|
541
|
-
focus=
|
|
610
|
+
focus=effective_focus,
|
|
542
611
|
style=SummaryStyle.CONVERSATIONAL,
|
|
543
|
-
length=
|
|
612
|
+
length=target_length
|
|
544
613
|
)
|
|
545
614
|
|
|
546
615
|
# The summary should ONLY contain the older messages summary
|
|
@@ -5,6 +5,7 @@ Base provider with integrated telemetry, events, and exception handling.
|
|
|
5
5
|
import time
|
|
6
6
|
import uuid
|
|
7
7
|
import asyncio
|
|
8
|
+
import warnings
|
|
8
9
|
from collections import deque
|
|
9
10
|
from typing import List, Dict, Any, Optional, Union, Iterator, AsyncIterator, Type
|
|
10
11
|
from abc import ABC, abstractmethod
|
|
@@ -60,6 +61,13 @@ class BaseProvider(AbstractCoreInterface, ABC):
|
|
|
60
61
|
# execute_tools: True = AbstractCore executes tools (legacy mode)
|
|
61
62
|
# False = Pass-through mode (default - for API server / agentic CLI)
|
|
62
63
|
self.execute_tools = kwargs.get('execute_tools', False)
|
|
64
|
+
if self.execute_tools:
|
|
65
|
+
warnings.warn(
|
|
66
|
+
"execute_tools=True is deprecated. Prefer passing tools explicitly to generate() "
|
|
67
|
+
"and executing tool calls in the host/runtime via a ToolExecutor.",
|
|
68
|
+
DeprecationWarning,
|
|
69
|
+
stacklevel=2,
|
|
70
|
+
)
|
|
63
71
|
|
|
64
72
|
# Setup retry manager with optional configuration
|
|
65
73
|
retry_config = kwargs.get('retry_config', None)
|
|
@@ -202,6 +210,12 @@ class BaseProvider(AbstractCoreInterface, ABC):
|
|
|
202
210
|
"""
|
|
203
211
|
trace_id = str(uuid.uuid4())
|
|
204
212
|
|
|
213
|
+
# If trace retention is disabled, still return a trace_id for correlation
|
|
214
|
+
# without constructing/storing a full trace payload.
|
|
215
|
+
maxlen = getattr(getattr(self, "_traces", None), "maxlen", None)
|
|
216
|
+
if maxlen == 0:
|
|
217
|
+
return trace_id
|
|
218
|
+
|
|
205
219
|
# Extract generation parameters
|
|
206
220
|
temperature = kwargs.get('temperature', self.temperature)
|
|
207
221
|
max_tokens = kwargs.get('max_tokens', self.max_tokens)
|
|
@@ -408,6 +422,13 @@ class BaseProvider(AbstractCoreInterface, ABC):
|
|
|
408
422
|
|
|
409
423
|
# Handle tool execution control
|
|
410
424
|
should_execute_tools = execute_tools if execute_tools is not None else self.execute_tools
|
|
425
|
+
if should_execute_tools and converted_tools:
|
|
426
|
+
warnings.warn(
|
|
427
|
+
"execute_tools=True is deprecated. Prefer passing tools explicitly to generate() "
|
|
428
|
+
"and executing tool calls in the host/runtime via a ToolExecutor.",
|
|
429
|
+
DeprecationWarning,
|
|
430
|
+
stacklevel=2,
|
|
431
|
+
)
|
|
411
432
|
if not should_execute_tools and converted_tools:
|
|
412
433
|
# If tools are provided but execution is disabled,
|
|
413
434
|
# we still pass them to the provider for generation but won't execute them
|
|
@@ -1556,4 +1577,4 @@ Please provide a structured response."""
|
|
|
1556
1577
|
# Yield chunks asynchronously
|
|
1557
1578
|
for chunk in sync_gen:
|
|
1558
1579
|
yield chunk
|
|
1559
|
-
await asyncio.sleep(0) # Yield control to event loop
|
|
1580
|
+
await asyncio.sleep(0) # Yield control to event loop
|
|
@@ -1956,6 +1956,39 @@ async def provider_chat_completions(
|
|
|
1956
1956
|
_, model = parse_model_string(request.model)
|
|
1957
1957
|
return await process_chat_completion(provider, model, request, http_request)
|
|
1958
1958
|
|
|
1959
|
+
|
|
1960
|
+
def _extract_trace_metadata(http_request: Request) -> Dict[str, Any]:
|
|
1961
|
+
"""Extract trace metadata from request headers (schema-safe)."""
|
|
1962
|
+
meta: Dict[str, Any] = {}
|
|
1963
|
+
|
|
1964
|
+
raw = (
|
|
1965
|
+
http_request.headers.get("x-abstractcore-trace-metadata")
|
|
1966
|
+
or http_request.headers.get("x-abstract-trace-metadata")
|
|
1967
|
+
)
|
|
1968
|
+
if raw:
|
|
1969
|
+
try:
|
|
1970
|
+
parsed = json.loads(raw)
|
|
1971
|
+
if isinstance(parsed, dict):
|
|
1972
|
+
meta.update(parsed)
|
|
1973
|
+
except Exception:
|
|
1974
|
+
# Ignore invalid metadata payloads; tracing is best-effort.
|
|
1975
|
+
pass
|
|
1976
|
+
|
|
1977
|
+
header_map = {
|
|
1978
|
+
"actor_id": "x-abstractcore-actor-id",
|
|
1979
|
+
"session_id": "x-abstractcore-session-id",
|
|
1980
|
+
"run_id": "x-abstractcore-run-id",
|
|
1981
|
+
"parent_run_id": "x-abstractcore-parent-run-id",
|
|
1982
|
+
}
|
|
1983
|
+
for key, header in header_map.items():
|
|
1984
|
+
val = http_request.headers.get(header)
|
|
1985
|
+
if val is not None and key not in meta:
|
|
1986
|
+
meta[key] = val
|
|
1987
|
+
|
|
1988
|
+
# Never log or return these directly; they are for internal correlation only.
|
|
1989
|
+
return meta
|
|
1990
|
+
|
|
1991
|
+
|
|
1959
1992
|
async def process_chat_completion(
|
|
1960
1993
|
provider: str,
|
|
1961
1994
|
model: str,
|
|
@@ -2019,6 +2052,11 @@ async def process_chat_completion(
|
|
|
2019
2052
|
# Create LLM instance
|
|
2020
2053
|
# Prepare provider-specific kwargs
|
|
2021
2054
|
provider_kwargs = {}
|
|
2055
|
+
trace_metadata = _extract_trace_metadata(http_request)
|
|
2056
|
+
if trace_metadata:
|
|
2057
|
+
# Enable trace capture (trace_id) without retaining full trace buffers by default.
|
|
2058
|
+
provider_kwargs["enable_tracing"] = True
|
|
2059
|
+
provider_kwargs.setdefault("max_traces", 0)
|
|
2022
2060
|
if request.base_url:
|
|
2023
2061
|
provider_kwargs["base_url"] = request.base_url
|
|
2024
2062
|
logger.info(
|
|
@@ -2047,6 +2085,8 @@ async def process_chat_completion(
|
|
|
2047
2085
|
"tool_choice": request.tool_choice if request.tools else None,
|
|
2048
2086
|
"execute_tools": False, # Server mode - don't execute tools
|
|
2049
2087
|
}
|
|
2088
|
+
if trace_metadata:
|
|
2089
|
+
gen_kwargs["trace_metadata"] = trace_metadata
|
|
2050
2090
|
|
|
2051
2091
|
# Add optional parameters
|
|
2052
2092
|
if request.stop:
|
|
@@ -2081,9 +2121,18 @@ async def process_chat_completion(
|
|
|
2081
2121
|
)
|
|
2082
2122
|
else:
|
|
2083
2123
|
response = llm.generate(**gen_kwargs)
|
|
2084
|
-
|
|
2124
|
+
openai_response = convert_to_openai_response(
|
|
2085
2125
|
response, provider, model, syntax_rewriter, request_id
|
|
2086
2126
|
)
|
|
2127
|
+
trace_id = None
|
|
2128
|
+
if hasattr(response, "metadata") and isinstance(getattr(response, "metadata"), dict):
|
|
2129
|
+
trace_id = response.metadata.get("trace_id")
|
|
2130
|
+
if trace_id:
|
|
2131
|
+
return JSONResponse(
|
|
2132
|
+
content=openai_response,
|
|
2133
|
+
headers={"X-AbstractCore-Trace-Id": str(trace_id)},
|
|
2134
|
+
)
|
|
2135
|
+
return openai_response
|
|
2087
2136
|
finally:
|
|
2088
2137
|
# Cleanup temporary files (base64 and downloaded images) with delay to avoid race conditions
|
|
2089
2138
|
import threading
|
|
@@ -2408,4 +2457,4 @@ Debug Mode:
|
|
|
2408
2457
|
# ============================================================================
|
|
2409
2458
|
|
|
2410
2459
|
if __name__ == "__main__":
|
|
2411
|
-
run_server_with_args()
|
|
2460
|
+
run_server_with_args()
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Universal tool support for AbstractCore.
|
|
3
|
+
|
|
4
|
+
This package provides a unified tool system that works across all models
|
|
5
|
+
and providers, whether they have native tool APIs or require prompting.
|
|
6
|
+
|
|
7
|
+
Tool Execution Modes
|
|
8
|
+
--------------------
|
|
9
|
+
|
|
10
|
+
AbstractCore supports two tool execution modes:
|
|
11
|
+
|
|
12
|
+
**Passthrough Mode (Default)** - execute_tools=False
|
|
13
|
+
The LLM returns raw tool call tags that downstream runtimes
|
|
14
|
+
(AbstractRuntime, Codex, Claude Code) parse and execute.
|
|
15
|
+
Use case: Agent loops, custom orchestration, multi-step workflows.
|
|
16
|
+
|
|
17
|
+
**Direct Execution Mode** - execute_tools=True
|
|
18
|
+
AbstractCore parses and executes tools internally using the
|
|
19
|
+
global registry. Requires register_tool() for each tool.
|
|
20
|
+
Use case: Simple scripts, single-turn tool use.
|
|
21
|
+
|
|
22
|
+
Key Components
|
|
23
|
+
--------------
|
|
24
|
+
- Core types (ToolDefinition, ToolCall, ToolResult)
|
|
25
|
+
- Universal handler for all models
|
|
26
|
+
- Architecture-based parsing and formatting
|
|
27
|
+
- Tool registry for managing available tools
|
|
28
|
+
|
|
29
|
+
Example: Passthrough Mode (Default)
|
|
30
|
+
-----------------------------------
|
|
31
|
+
```python
|
|
32
|
+
from abstractcore import create_llm
|
|
33
|
+
from abstractcore.tools import tool
|
|
34
|
+
|
|
35
|
+
@tool(name="get_weather", description="Get weather for a city")
|
|
36
|
+
def get_weather(city: str) -> str:
|
|
37
|
+
return f"Weather in {city}: Sunny"
|
|
38
|
+
|
|
39
|
+
llm = create_llm("ollama", model="qwen3:4b")
|
|
40
|
+
response = llm.generate("Weather in Paris?", tools=[get_weather])
|
|
41
|
+
# response.content has tool call tags - parse with your runtime
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Example: Direct Execution Mode
|
|
45
|
+
------------------------------
|
|
46
|
+
```python
|
|
47
|
+
from abstractcore import create_llm
|
|
48
|
+
from abstractcore.tools import tool, register_tool
|
|
49
|
+
|
|
50
|
+
@tool(name="get_weather", description="Get weather for a city")
|
|
51
|
+
def get_weather(city: str) -> str:
|
|
52
|
+
return f"Weather in {city}: Sunny"
|
|
53
|
+
|
|
54
|
+
register_tool(get_weather) # Required for direct execution
|
|
55
|
+
|
|
56
|
+
llm = create_llm("ollama", model="qwen3:4b", execute_tools=True)
|
|
57
|
+
response = llm.generate("Weather in Paris?", tools=[get_weather])
|
|
58
|
+
# response.content has executed tool results
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Note: The @tool decorator creates metadata but does NOT auto-register.
|
|
62
|
+
Tools are passed explicitly to generate(). Use register_tool() only
|
|
63
|
+
when using direct execution mode.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
# Core types
|
|
67
|
+
from .core import (
|
|
68
|
+
ToolDefinition,
|
|
69
|
+
ToolCall,
|
|
70
|
+
ToolResult,
|
|
71
|
+
ToolCallResponse,
|
|
72
|
+
tool
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Handler
|
|
76
|
+
from .handler import (
|
|
77
|
+
UniversalToolHandler,
|
|
78
|
+
create_handler
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Parser functions
|
|
82
|
+
from .parser import (
|
|
83
|
+
detect_tool_calls,
|
|
84
|
+
parse_tool_calls,
|
|
85
|
+
format_tool_prompt
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Registry
|
|
89
|
+
from .registry import (
|
|
90
|
+
ToolRegistry,
|
|
91
|
+
register_tool,
|
|
92
|
+
get_registry,
|
|
93
|
+
execute_tool,
|
|
94
|
+
execute_tools,
|
|
95
|
+
clear_registry
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
__all__ = [
|
|
99
|
+
# Core types
|
|
100
|
+
"ToolDefinition",
|
|
101
|
+
"ToolCall",
|
|
102
|
+
"ToolResult",
|
|
103
|
+
"ToolCallResponse",
|
|
104
|
+
"tool",
|
|
105
|
+
|
|
106
|
+
# Handler
|
|
107
|
+
"UniversalToolHandler",
|
|
108
|
+
"create_handler",
|
|
109
|
+
|
|
110
|
+
# Parser
|
|
111
|
+
"detect_tool_calls",
|
|
112
|
+
"parse_tool_calls",
|
|
113
|
+
"format_tool_prompt",
|
|
114
|
+
|
|
115
|
+
# Registry
|
|
116
|
+
"ToolRegistry",
|
|
117
|
+
"register_tool",
|
|
118
|
+
"get_registry",
|
|
119
|
+
"execute_tool",
|
|
120
|
+
"execute_tools",
|
|
121
|
+
"clear_registry",
|
|
122
|
+
]
|