abstractcore 2.6.9__py3-none-any.whl → 2.9.1__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.
- abstractcore/apps/summarizer.py +69 -27
- abstractcore/architectures/detection.py +190 -25
- abstractcore/assets/architecture_formats.json +129 -6
- abstractcore/assets/model_capabilities.json +803 -141
- abstractcore/config/main.py +2 -2
- abstractcore/config/manager.py +3 -1
- abstractcore/events/__init__.py +7 -1
- abstractcore/mcp/__init__.py +30 -0
- abstractcore/mcp/client.py +213 -0
- abstractcore/mcp/factory.py +64 -0
- abstractcore/mcp/naming.py +28 -0
- abstractcore/mcp/stdio_client.py +336 -0
- abstractcore/mcp/tool_source.py +164 -0
- abstractcore/processing/__init__.py +2 -2
- abstractcore/processing/basic_deepsearch.py +1 -1
- abstractcore/processing/basic_summarizer.py +379 -93
- abstractcore/providers/anthropic_provider.py +91 -10
- abstractcore/providers/base.py +540 -16
- abstractcore/providers/huggingface_provider.py +17 -8
- abstractcore/providers/lmstudio_provider.py +170 -25
- abstractcore/providers/mlx_provider.py +13 -10
- abstractcore/providers/ollama_provider.py +42 -26
- abstractcore/providers/openai_compatible_provider.py +87 -22
- abstractcore/providers/openai_provider.py +12 -9
- abstractcore/providers/streaming.py +201 -39
- abstractcore/providers/vllm_provider.py +78 -21
- abstractcore/server/app.py +116 -30
- abstractcore/structured/retry.py +20 -7
- abstractcore/tools/__init__.py +46 -24
- abstractcore/tools/abstractignore.py +166 -0
- abstractcore/tools/arg_canonicalizer.py +61 -0
- abstractcore/tools/common_tools.py +2443 -742
- abstractcore/tools/core.py +109 -13
- abstractcore/tools/handler.py +17 -3
- abstractcore/tools/parser.py +894 -159
- abstractcore/tools/registry.py +122 -18
- abstractcore/tools/syntax_rewriter.py +68 -6
- abstractcore/tools/tag_rewriter.py +186 -1
- abstractcore/utils/jsonish.py +111 -0
- abstractcore/utils/version.py +1 -1
- {abstractcore-2.6.9.dist-info → abstractcore-2.9.1.dist-info}/METADATA +56 -2
- {abstractcore-2.6.9.dist-info → abstractcore-2.9.1.dist-info}/RECORD +46 -37
- {abstractcore-2.6.9.dist-info → abstractcore-2.9.1.dist-info}/WHEEL +0 -0
- {abstractcore-2.6.9.dist-info → abstractcore-2.9.1.dist-info}/entry_points.txt +0 -0
- {abstractcore-2.6.9.dist-info → abstractcore-2.9.1.dist-info}/licenses/LICENSE +0 -0
- {abstractcore-2.6.9.dist-info → abstractcore-2.9.1.dist-info}/top_level.txt +0 -0
|
@@ -100,6 +100,30 @@ class AnthropicProvider(BaseProvider):
|
|
|
100
100
|
"role": "assistant",
|
|
101
101
|
"content": msg["content"]
|
|
102
102
|
})
|
|
103
|
+
elif role == "tool":
|
|
104
|
+
# Anthropic Messages API represents tool outputs as `tool_result`
|
|
105
|
+
# content blocks inside a USER message (there is no `role="tool"`).
|
|
106
|
+
meta = msg.get("metadata") if isinstance(msg.get("metadata"), dict) else {}
|
|
107
|
+
tool_use_id = meta.get("call_id") or meta.get("tool_use_id") or meta.get("id")
|
|
108
|
+
tool_text = msg.get("content", "")
|
|
109
|
+
tool_text = "" if tool_text is None else str(tool_text)
|
|
110
|
+
|
|
111
|
+
if isinstance(tool_use_id, str) and tool_use_id.strip():
|
|
112
|
+
api_messages.append(
|
|
113
|
+
{
|
|
114
|
+
"role": "user",
|
|
115
|
+
"content": [
|
|
116
|
+
{
|
|
117
|
+
"type": "tool_result",
|
|
118
|
+
"tool_use_id": tool_use_id.strip(),
|
|
119
|
+
"content": tool_text,
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
# Fallback: preserve as plain user text when no tool_use_id is available.
|
|
126
|
+
api_messages.append({"role": "user", "content": tool_text})
|
|
103
127
|
else:
|
|
104
128
|
api_messages.append({
|
|
105
129
|
"role": "user",
|
|
@@ -194,7 +218,9 @@ class AnthropicProvider(BaseProvider):
|
|
|
194
218
|
call_params["tool_choice"] = {"type": kwargs.get("tool_choice", "auto")}
|
|
195
219
|
else:
|
|
196
220
|
# Add tools as system prompt for prompted models
|
|
197
|
-
|
|
221
|
+
system_text = call_params.get("system") if isinstance(call_params.get("system"), str) else ""
|
|
222
|
+
include_tool_list = "## Tools (session)" not in system_text
|
|
223
|
+
tool_prompt = self.tool_handler.format_tools_prompt(tools, include_tool_list=include_tool_list)
|
|
198
224
|
if call_params.get("system"):
|
|
199
225
|
call_params["system"] += f"\n\n{tool_prompt}"
|
|
200
226
|
else:
|
|
@@ -213,6 +239,8 @@ class AnthropicProvider(BaseProvider):
|
|
|
213
239
|
formatted = self._format_response(response)
|
|
214
240
|
# Add generation time to response
|
|
215
241
|
formatted.gen_time = gen_time
|
|
242
|
+
formatted.metadata = dict(formatted.metadata or {})
|
|
243
|
+
formatted.metadata["_provider_request"] = {"call_params": call_params}
|
|
216
244
|
|
|
217
245
|
# Handle tool execution for Anthropic responses
|
|
218
246
|
if tools and (formatted.has_tool_calls() or
|
|
@@ -232,7 +260,7 @@ class AnthropicProvider(BaseProvider):
|
|
|
232
260
|
error_message = format_model_error("Anthropic", self.model, available_models)
|
|
233
261
|
raise ModelNotFoundError(error_message)
|
|
234
262
|
else:
|
|
235
|
-
raise
|
|
263
|
+
raise
|
|
236
264
|
|
|
237
265
|
async def _agenerate_internal(self,
|
|
238
266
|
prompt: str,
|
|
@@ -260,6 +288,30 @@ class AnthropicProvider(BaseProvider):
|
|
|
260
288
|
"role": "assistant",
|
|
261
289
|
"content": msg["content"]
|
|
262
290
|
})
|
|
291
|
+
elif role == "tool":
|
|
292
|
+
# Anthropic Messages API represents tool outputs as `tool_result`
|
|
293
|
+
# content blocks inside a USER message (there is no `role="tool"`).
|
|
294
|
+
meta = msg.get("metadata") if isinstance(msg.get("metadata"), dict) else {}
|
|
295
|
+
tool_use_id = meta.get("call_id") or meta.get("tool_use_id") or meta.get("id")
|
|
296
|
+
tool_text = msg.get("content", "")
|
|
297
|
+
tool_text = "" if tool_text is None else str(tool_text)
|
|
298
|
+
|
|
299
|
+
if isinstance(tool_use_id, str) and tool_use_id.strip():
|
|
300
|
+
api_messages.append(
|
|
301
|
+
{
|
|
302
|
+
"role": "user",
|
|
303
|
+
"content": [
|
|
304
|
+
{
|
|
305
|
+
"type": "tool_result",
|
|
306
|
+
"tool_use_id": tool_use_id.strip(),
|
|
307
|
+
"content": tool_text,
|
|
308
|
+
}
|
|
309
|
+
],
|
|
310
|
+
}
|
|
311
|
+
)
|
|
312
|
+
else:
|
|
313
|
+
# Fallback: preserve as plain user text when no tool_use_id is available.
|
|
314
|
+
api_messages.append({"role": "user", "content": tool_text})
|
|
263
315
|
else:
|
|
264
316
|
api_messages.append({
|
|
265
317
|
"role": "user",
|
|
@@ -348,7 +400,9 @@ class AnthropicProvider(BaseProvider):
|
|
|
348
400
|
elif kwargs.get("tool_choice"):
|
|
349
401
|
call_params["tool_choice"] = {"type": kwargs.get("tool_choice", "auto")}
|
|
350
402
|
else:
|
|
351
|
-
|
|
403
|
+
system_text = call_params.get("system") if isinstance(call_params.get("system"), str) else ""
|
|
404
|
+
include_tool_list = "## Tools (session)" not in system_text
|
|
405
|
+
tool_prompt = self.tool_handler.format_tools_prompt(tools, include_tool_list=include_tool_list)
|
|
352
406
|
if call_params.get("system"):
|
|
353
407
|
call_params["system"] += f"\n\n{tool_prompt}"
|
|
354
408
|
else:
|
|
@@ -365,6 +419,8 @@ class AnthropicProvider(BaseProvider):
|
|
|
365
419
|
|
|
366
420
|
formatted = self._format_response(response)
|
|
367
421
|
formatted.gen_time = gen_time
|
|
422
|
+
formatted.metadata = dict(formatted.metadata or {})
|
|
423
|
+
formatted.metadata["_provider_request"] = {"call_params": call_params}
|
|
368
424
|
|
|
369
425
|
if tools and (formatted.has_tool_calls() or
|
|
370
426
|
(self.tool_handler.supports_prompted and formatted.content)):
|
|
@@ -381,7 +437,7 @@ class AnthropicProvider(BaseProvider):
|
|
|
381
437
|
error_message = format_model_error("Anthropic", self.model, available_models)
|
|
382
438
|
raise ModelNotFoundError(error_message)
|
|
383
439
|
else:
|
|
384
|
-
raise
|
|
440
|
+
raise
|
|
385
441
|
|
|
386
442
|
async def _async_stream_response(self, call_params: Dict[str, Any], tools: Optional[List[Dict[str, Any]]] = None) -> AsyncIterator[GenerateResponse]:
|
|
387
443
|
"""Native async streaming with Anthropic's context manager pattern."""
|
|
@@ -397,7 +453,7 @@ class AnthropicProvider(BaseProvider):
|
|
|
397
453
|
raw_response=chunk
|
|
398
454
|
)
|
|
399
455
|
except Exception as e:
|
|
400
|
-
raise
|
|
456
|
+
raise
|
|
401
457
|
|
|
402
458
|
def unload(self) -> None:
|
|
403
459
|
"""Close async client if it was created."""
|
|
@@ -414,13 +470,38 @@ class AnthropicProvider(BaseProvider):
|
|
|
414
470
|
"""Format tools for Anthropic API format"""
|
|
415
471
|
formatted_tools = []
|
|
416
472
|
for tool in tools:
|
|
417
|
-
#
|
|
473
|
+
# Anthropic expects `input_schema` to be a JSON Schema object:
|
|
474
|
+
# https://platform.claude.com/docs/en/agents-and-tools/tool-use/implement-tool-use
|
|
475
|
+
#
|
|
476
|
+
# Our internal tool representation typically uses:
|
|
477
|
+
# tool["parameters"] = { "arg": {"type": "...", "default": ...?}, ... }
|
|
478
|
+
# or, less commonly:
|
|
479
|
+
# tool["parameters"] = {"type":"object","properties":{...},"required":[...]}
|
|
418
480
|
params = tool.get("parameters", {})
|
|
419
|
-
|
|
481
|
+
|
|
482
|
+
properties: Dict[str, Any] = {}
|
|
483
|
+
required: List[str] = []
|
|
484
|
+
|
|
485
|
+
if isinstance(params, dict) and "properties" in params:
|
|
486
|
+
# Treat as already-schema-like.
|
|
487
|
+
raw_props = params.get("properties") if isinstance(params.get("properties"), dict) else {}
|
|
488
|
+
properties = dict(raw_props)
|
|
489
|
+
raw_required = params.get("required")
|
|
490
|
+
if isinstance(raw_required, list):
|
|
491
|
+
required = [str(x) for x in raw_required if isinstance(x, (str, int))]
|
|
492
|
+
elif isinstance(params, dict):
|
|
493
|
+
# Treat as compact parameter dict; infer required args by absence of `default`.
|
|
494
|
+
properties = dict(params)
|
|
495
|
+
for k, v in params.items():
|
|
496
|
+
if isinstance(v, dict) and "default" not in v:
|
|
497
|
+
required.append(str(k))
|
|
498
|
+
|
|
499
|
+
input_schema: Dict[str, Any] = {
|
|
420
500
|
"type": "object",
|
|
421
|
-
"properties":
|
|
422
|
-
"required": params.get("required", list(params.keys()) if "properties" not in params else [])
|
|
501
|
+
"properties": properties,
|
|
423
502
|
}
|
|
503
|
+
if required:
|
|
504
|
+
input_schema["required"] = required
|
|
424
505
|
|
|
425
506
|
formatted_tool = {
|
|
426
507
|
"name": tool.get("name"),
|
|
@@ -440,7 +521,7 @@ class AnthropicProvider(BaseProvider):
|
|
|
440
521
|
# Handle different content types
|
|
441
522
|
for content_block in response.content:
|
|
442
523
|
if content_block.type == "text":
|
|
443
|
-
content
|
|
524
|
+
content += content_block.text
|
|
444
525
|
elif content_block.type == "tool_use":
|
|
445
526
|
if tool_calls is None:
|
|
446
527
|
tool_calls = []
|