hammad-python 0.0.14__py3-none-any.whl → 0.0.16__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.
- hammad/__init__.py +177 -0
- hammad/{performance/imports.py → _internal.py} +7 -1
- hammad/cache/__init__.py +1 -1
- hammad/cli/__init__.py +3 -1
- hammad/cli/_runner.py +265 -0
- hammad/cli/animations.py +1 -1
- hammad/cli/plugins.py +133 -78
- hammad/cli/styles/__init__.py +1 -1
- hammad/cli/styles/utils.py +149 -3
- hammad/data/__init__.py +56 -29
- hammad/data/collections/__init__.py +27 -17
- hammad/data/collections/collection.py +205 -383
- hammad/data/collections/indexes/__init__.py +37 -0
- hammad/data/collections/indexes/qdrant/__init__.py +1 -0
- hammad/data/collections/indexes/qdrant/index.py +735 -0
- hammad/data/collections/indexes/qdrant/settings.py +94 -0
- hammad/data/collections/indexes/qdrant/utils.py +220 -0
- hammad/data/collections/indexes/tantivy/__init__.py +1 -0
- hammad/data/collections/indexes/tantivy/index.py +428 -0
- hammad/data/collections/indexes/tantivy/settings.py +51 -0
- hammad/data/collections/indexes/tantivy/utils.py +200 -0
- hammad/data/configurations/__init__.py +2 -2
- hammad/data/configurations/configuration.py +2 -2
- hammad/data/models/__init__.py +20 -9
- hammad/data/models/extensions/__init__.py +4 -0
- hammad/data/models/{pydantic → extensions/pydantic}/__init__.py +6 -19
- hammad/data/models/{pydantic → extensions/pydantic}/converters.py +143 -16
- hammad/data/models/{base/fields.py → fields.py} +1 -1
- hammad/data/models/{base/model.py → model.py} +1 -1
- hammad/data/models/{base/utils.py → utils.py} +1 -1
- hammad/data/sql/__init__.py +23 -0
- hammad/data/sql/database.py +578 -0
- hammad/data/sql/types.py +141 -0
- hammad/data/types/__init__.py +1 -3
- hammad/data/types/file.py +3 -3
- hammad/data/types/multimodal/__init__.py +2 -2
- hammad/data/types/multimodal/audio.py +2 -2
- hammad/data/types/multimodal/image.py +2 -2
- hammad/formatting/__init__.py +9 -27
- hammad/formatting/json/__init__.py +8 -2
- hammad/formatting/json/converters.py +7 -1
- hammad/formatting/text/__init__.py +1 -1
- hammad/formatting/yaml/__init__.py +1 -1
- hammad/genai/__init__.py +78 -0
- hammad/genai/agents/__init__.py +1 -0
- hammad/genai/agents/types/__init__.py +35 -0
- hammad/genai/agents/types/history.py +277 -0
- hammad/genai/agents/types/tool.py +490 -0
- hammad/genai/embedding_models/__init__.py +41 -0
- hammad/{ai/embeddings/client/litellm_embeddings_client.py → genai/embedding_models/embedding_model.py} +47 -142
- hammad/genai/embedding_models/embedding_model_name.py +77 -0
- hammad/genai/embedding_models/embedding_model_request.py +65 -0
- hammad/{ai/embeddings/types.py → genai/embedding_models/embedding_model_response.py} +3 -3
- hammad/genai/embedding_models/run.py +161 -0
- hammad/genai/language_models/__init__.py +35 -0
- hammad/genai/language_models/_streaming.py +622 -0
- hammad/genai/language_models/_types.py +276 -0
- hammad/genai/language_models/_utils/__init__.py +31 -0
- hammad/genai/language_models/_utils/_completions.py +131 -0
- hammad/genai/language_models/_utils/_messages.py +89 -0
- hammad/genai/language_models/_utils/_requests.py +202 -0
- hammad/genai/language_models/_utils/_structured_outputs.py +124 -0
- hammad/genai/language_models/language_model.py +734 -0
- hammad/genai/language_models/language_model_request.py +135 -0
- hammad/genai/language_models/language_model_response.py +219 -0
- hammad/genai/language_models/language_model_response_chunk.py +53 -0
- hammad/genai/language_models/run.py +530 -0
- hammad/genai/multimodal_models.py +48 -0
- hammad/genai/rerank_models.py +26 -0
- hammad/logging/__init__.py +1 -1
- hammad/logging/decorators.py +1 -1
- hammad/logging/logger.py +2 -2
- hammad/mcp/__init__.py +1 -1
- hammad/mcp/client/__init__.py +35 -0
- hammad/mcp/client/client.py +105 -4
- hammad/mcp/client/client_service.py +10 -3
- hammad/mcp/servers/__init__.py +24 -0
- hammad/{performance/runtime → runtime}/__init__.py +2 -2
- hammad/{performance/runtime → runtime}/decorators.py +1 -1
- hammad/{performance/runtime → runtime}/run.py +1 -1
- hammad/service/__init__.py +1 -1
- hammad/service/create.py +3 -8
- hammad/service/decorators.py +8 -8
- hammad/typing/__init__.py +28 -0
- hammad/web/__init__.py +3 -3
- hammad/web/http/client.py +1 -1
- hammad/web/models.py +53 -21
- hammad/web/search/client.py +99 -52
- hammad/web/utils.py +13 -13
- hammad_python-0.0.16.dist-info/METADATA +191 -0
- hammad_python-0.0.16.dist-info/RECORD +110 -0
- hammad/ai/__init__.py +0 -1
- hammad/ai/_utils.py +0 -142
- hammad/ai/completions/__init__.py +0 -45
- hammad/ai/completions/client.py +0 -684
- hammad/ai/completions/create.py +0 -710
- hammad/ai/completions/settings.py +0 -100
- hammad/ai/completions/types.py +0 -792
- hammad/ai/completions/utils.py +0 -486
- hammad/ai/embeddings/__init__.py +0 -35
- hammad/ai/embeddings/client/__init__.py +0 -1
- hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
- hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
- hammad/ai/embeddings/create.py +0 -159
- hammad/data/collections/base_collection.py +0 -58
- hammad/data/collections/searchable_collection.py +0 -556
- hammad/data/collections/vector_collection.py +0 -596
- hammad/data/databases/__init__.py +0 -21
- hammad/data/databases/database.py +0 -902
- hammad/data/models/base/__init__.py +0 -35
- hammad/data/models/pydantic/models/__init__.py +0 -28
- hammad/data/models/pydantic/models/arbitrary_model.py +0 -46
- hammad/data/models/pydantic/models/cacheable_model.py +0 -79
- hammad/data/models/pydantic/models/fast_model.py +0 -318
- hammad/data/models/pydantic/models/function_model.py +0 -176
- hammad/data/models/pydantic/models/subscriptable_model.py +0 -63
- hammad/performance/__init__.py +0 -36
- hammad/py.typed +0 -0
- hammad_python-0.0.14.dist-info/METADATA +0 -70
- hammad_python-0.0.14.dist-info/RECORD +0 -99
- {hammad_python-0.0.14.dist-info → hammad_python-0.0.16.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.14.dist-info → hammad_python-0.0.16.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,202 @@
|
|
1
|
+
"""hammad.genai.language_models._utils._requests"""
|
2
|
+
|
3
|
+
from typing import (
|
4
|
+
Any,
|
5
|
+
Dict,
|
6
|
+
List,
|
7
|
+
Generic,
|
8
|
+
Optional,
|
9
|
+
Type,
|
10
|
+
TypeVar,
|
11
|
+
Union,
|
12
|
+
TYPE_CHECKING,
|
13
|
+
)
|
14
|
+
|
15
|
+
from ....data.models import (
|
16
|
+
convert_to_pydantic_model,
|
17
|
+
is_pydantic_model_class,
|
18
|
+
)
|
19
|
+
|
20
|
+
from .._types import LanguageModelName, LanguageModelInstructorMode
|
21
|
+
from ..language_model_request import (
|
22
|
+
LanguageModelMessagesParam,
|
23
|
+
LanguageModelRequest,
|
24
|
+
)
|
25
|
+
|
26
|
+
__all__ = [
|
27
|
+
"LanguageModelRequestBuilder"
|
28
|
+
]
|
29
|
+
|
30
|
+
|
31
|
+
T = TypeVar("T")
|
32
|
+
|
33
|
+
|
34
|
+
class LanguageModelRequestBuilder(Generic[T]):
|
35
|
+
"""A request to a language model with comprehensive parameter handling."""
|
36
|
+
|
37
|
+
def __init__(
|
38
|
+
self,
|
39
|
+
messages: LanguageModelMessagesParam,
|
40
|
+
instructions: Optional[str] = None,
|
41
|
+
model: LanguageModelName = "openai/gpt-4o-mini",
|
42
|
+
**kwargs: Any,
|
43
|
+
):
|
44
|
+
"""Initialize a language model request.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
messages: The input messages/content for the request
|
48
|
+
instructions: Optional system instructions to prepend
|
49
|
+
model: The model to use for the request
|
50
|
+
**kwargs: Additional request settings
|
51
|
+
"""
|
52
|
+
self.messages = messages
|
53
|
+
self.instructions = instructions
|
54
|
+
self.model = model
|
55
|
+
self.settings = self._build_settings(**kwargs)
|
56
|
+
|
57
|
+
# Validate settings
|
58
|
+
self._validate_settings()
|
59
|
+
|
60
|
+
def _build_settings(self, **kwargs: Any) -> LanguageModelRequest:
|
61
|
+
"""Build the complete settings dictionary from kwargs."""
|
62
|
+
settings: LanguageModelRequest = {"model": self.model}
|
63
|
+
|
64
|
+
# Add all provided kwargs to settings
|
65
|
+
for key, value in kwargs.items():
|
66
|
+
if value is not None:
|
67
|
+
settings[key] = value
|
68
|
+
|
69
|
+
return settings
|
70
|
+
|
71
|
+
def _validate_settings(self) -> None:
|
72
|
+
"""Validate that the settings are compatible."""
|
73
|
+
# Check if both tools and structured outputs are specified
|
74
|
+
has_tools = any(
|
75
|
+
key in self.settings
|
76
|
+
for key in ["tools", "tool_choice", "parallel_tool_calls", "functions", "function_call"]
|
77
|
+
)
|
78
|
+
|
79
|
+
has_structured_output = "type" in self.settings and self.settings["type"] is not str
|
80
|
+
|
81
|
+
if has_tools and has_structured_output:
|
82
|
+
raise ValueError(
|
83
|
+
"Tools and structured outputs cannot be used together. "
|
84
|
+
"Please specify either tools OR a structured output type, not both."
|
85
|
+
)
|
86
|
+
|
87
|
+
def is_structured_output(self) -> bool:
|
88
|
+
"""Check if this request is for structured output."""
|
89
|
+
return "type" in self.settings and self.settings["type"] is not str
|
90
|
+
|
91
|
+
def is_streaming(self) -> bool:
|
92
|
+
"""Check if this request is for streaming."""
|
93
|
+
return self.settings.get("stream", False)
|
94
|
+
|
95
|
+
def has_tools(self) -> bool:
|
96
|
+
"""Check if this request has tools."""
|
97
|
+
return any(
|
98
|
+
key in self.settings
|
99
|
+
for key in ["tools", "tool_choice", "parallel_tool_calls", "functions", "function_call"]
|
100
|
+
)
|
101
|
+
|
102
|
+
def get_completion_settings(self) -> Dict[str, Any]:
|
103
|
+
"""Get settings filtered for standard completion requests."""
|
104
|
+
excluded_keys = {
|
105
|
+
"type", "instructor_mode", "response_field_name",
|
106
|
+
"response_field_instruction", "response_model_name", "max_retries", "strict",
|
107
|
+
"validation_context", "context",
|
108
|
+
"completion_kwargs_hooks", "completion_response_hooks",
|
109
|
+
"completion_error_hooks", "completion_last_attempt_hooks",
|
110
|
+
"parse_error_hooks"
|
111
|
+
}
|
112
|
+
|
113
|
+
return {
|
114
|
+
key: value for key, value in self.settings.items()
|
115
|
+
if key not in excluded_keys
|
116
|
+
}
|
117
|
+
|
118
|
+
def get_structured_output_settings(self) -> Dict[str, Any]:
|
119
|
+
"""Get settings filtered for structured output requests."""
|
120
|
+
excluded_keys = {
|
121
|
+
"tools", "tool_choice", "parallel_tool_calls",
|
122
|
+
"functions", "function_call",
|
123
|
+
"type", "instructor_mode", "response_field_name",
|
124
|
+
"response_field_instruction", "response_model_name", "max_retries", "strict",
|
125
|
+
"validation_context", "context",
|
126
|
+
"completion_kwargs_hooks", "completion_response_hooks",
|
127
|
+
"completion_error_hooks", "completion_last_attempt_hooks",
|
128
|
+
"parse_error_hooks"
|
129
|
+
}
|
130
|
+
|
131
|
+
return {
|
132
|
+
key: value for key, value in self.settings.items()
|
133
|
+
if key not in excluded_keys
|
134
|
+
}
|
135
|
+
|
136
|
+
def get_output_type(self) -> Type[T]:
|
137
|
+
"""Get the requested output type."""
|
138
|
+
return self.settings.get("type", str)
|
139
|
+
|
140
|
+
def get_instructor_mode(self) -> LanguageModelInstructorMode:
|
141
|
+
"""Get the instructor mode for structured outputs."""
|
142
|
+
return self.settings.get("instructor_mode", "tool_call")
|
143
|
+
|
144
|
+
def get_response_field_name(self) -> str:
|
145
|
+
"""Get the response field name for structured outputs."""
|
146
|
+
return self.settings.get("response_field_name", "content")
|
147
|
+
|
148
|
+
def get_response_field_instruction(self) -> str:
|
149
|
+
"""Get the response field instruction for structured outputs."""
|
150
|
+
return self.settings.get(
|
151
|
+
"response_field_instruction",
|
152
|
+
"A response in the correct type as requested by the user, or relevant content."
|
153
|
+
)
|
154
|
+
|
155
|
+
def get_response_model_name(self) -> str:
|
156
|
+
"""Get the response model name for structured outputs."""
|
157
|
+
return self.settings.get("response_model_name", "Response")
|
158
|
+
|
159
|
+
def get_max_retries(self) -> int:
|
160
|
+
"""Get the maximum retries for structured outputs."""
|
161
|
+
return self.settings.get("max_retries", 3)
|
162
|
+
|
163
|
+
def get_strict_mode(self) -> bool:
|
164
|
+
"""Get the strict mode for structured outputs."""
|
165
|
+
return self.settings.get("strict", True)
|
166
|
+
|
167
|
+
def get_validation_context(self) -> Optional[Dict[str, Any]]:
|
168
|
+
"""Get the validation context for structured outputs."""
|
169
|
+
return self.settings.get("validation_context")
|
170
|
+
|
171
|
+
def get_context(self) -> Optional[Dict[str, Any]]:
|
172
|
+
"""Get the context for structured outputs."""
|
173
|
+
return self.settings.get("context")
|
174
|
+
|
175
|
+
def prepare_pydantic_model(self) -> Optional[Type[Any]]:
|
176
|
+
"""Prepare a Pydantic model for structured outputs if needed."""
|
177
|
+
if not self.is_structured_output():
|
178
|
+
return None
|
179
|
+
|
180
|
+
output_type = self.get_output_type()
|
181
|
+
|
182
|
+
if is_pydantic_model_class(output_type):
|
183
|
+
return output_type
|
184
|
+
|
185
|
+
# Convert to Pydantic model
|
186
|
+
return convert_to_pydantic_model(
|
187
|
+
target=output_type,
|
188
|
+
name="Response",
|
189
|
+
field_name=self.get_response_field_name(),
|
190
|
+
description=self.get_response_field_instruction(),
|
191
|
+
)
|
192
|
+
|
193
|
+
def __repr__(self) -> str:
|
194
|
+
"""String representation of the request."""
|
195
|
+
return (
|
196
|
+
f"LanguageModelRequest("
|
197
|
+
f"model={self.model}, "
|
198
|
+
f"structured_output={self.is_structured_output()}, "
|
199
|
+
f"streaming={self.is_streaming()}, "
|
200
|
+
f"has_tools={self.has_tools()}"
|
201
|
+
f")"
|
202
|
+
)
|
@@ -0,0 +1,124 @@
|
|
1
|
+
"""hammad.genai.language_models._utils._structured_outputs"""
|
2
|
+
|
3
|
+
from typing import Any, Dict, Type, TypeVar
|
4
|
+
|
5
|
+
from ....cache import cached
|
6
|
+
from ....data.models import (
|
7
|
+
convert_to_pydantic_model,
|
8
|
+
is_pydantic_model_class,
|
9
|
+
)
|
10
|
+
from ..language_model_response import LanguageModelResponse
|
11
|
+
|
12
|
+
__all__ = [
|
13
|
+
"handle_structured_output_request_params",
|
14
|
+
"prepare_response_model",
|
15
|
+
"handle_structured_output_response",
|
16
|
+
]
|
17
|
+
|
18
|
+
T = TypeVar("T")
|
19
|
+
|
20
|
+
|
21
|
+
@cached
|
22
|
+
def handle_structured_output_request_params(params: Dict[str, Any]) -> Dict[str, Any]:
|
23
|
+
"""Filter and process parameters for structured output requests.
|
24
|
+
|
25
|
+
Args:
|
26
|
+
params: Raw request parameters
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
Filtered parameters suitable for Instructor
|
30
|
+
"""
|
31
|
+
# Remove tool-related parameters (not supported with structured outputs)
|
32
|
+
# and structured output specific parameters
|
33
|
+
excluded_keys = {
|
34
|
+
"tools", "tool_choice", "parallel_tool_calls",
|
35
|
+
"functions", "function_call",
|
36
|
+
"type", "instructor_mode", "response_field_name", "response_field_instruction",
|
37
|
+
"response_model_name", "max_retries", "strict"
|
38
|
+
}
|
39
|
+
|
40
|
+
filtered_params = {
|
41
|
+
key: value for key, value in params.items()
|
42
|
+
if key not in excluded_keys and value is not None
|
43
|
+
}
|
44
|
+
|
45
|
+
return filtered_params
|
46
|
+
|
47
|
+
|
48
|
+
@cached
|
49
|
+
def prepare_response_model(
|
50
|
+
output_type: Type[T],
|
51
|
+
response_field_name: str = "content",
|
52
|
+
response_field_instruction: str = "A response in the correct type as requested by the user, or relevant content.",
|
53
|
+
response_model_name: str = "Response",
|
54
|
+
) -> Type[Any]:
|
55
|
+
"""Prepare a Pydantic model for structured outputs.
|
56
|
+
|
57
|
+
Args:
|
58
|
+
output_type: The desired output type
|
59
|
+
response_field_name: Name of the response field
|
60
|
+
response_field_instruction: Description of the response field
|
61
|
+
response_model_name: Name of the response model
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
Pydantic model class suitable for Instructor
|
65
|
+
"""
|
66
|
+
# Check if it's already a Pydantic model
|
67
|
+
if is_pydantic_model_class(output_type):
|
68
|
+
return output_type
|
69
|
+
|
70
|
+
# Convert to Pydantic model
|
71
|
+
return convert_to_pydantic_model(
|
72
|
+
target=output_type,
|
73
|
+
name=response_model_name,
|
74
|
+
field_name=response_field_name,
|
75
|
+
description=response_field_instruction,
|
76
|
+
)
|
77
|
+
|
78
|
+
|
79
|
+
def handle_structured_output_response(
|
80
|
+
response: Any,
|
81
|
+
completion: Any,
|
82
|
+
model: str,
|
83
|
+
output_type: Type[T],
|
84
|
+
response_field_name: str = "content",
|
85
|
+
) -> LanguageModelResponse[T]:
|
86
|
+
"""Convert an Instructor response to LanguageModelResponse.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
response: The structured response from Instructor
|
90
|
+
completion: The raw completion object
|
91
|
+
model: Model name used for the request
|
92
|
+
output_type: The expected output type
|
93
|
+
response_field_name: Name of the response field
|
94
|
+
|
95
|
+
Returns:
|
96
|
+
LanguageModelResponse object with structured output
|
97
|
+
"""
|
98
|
+
# Extract the actual value if using converted pydantic model
|
99
|
+
if not is_pydantic_model_class(output_type) and hasattr(response, response_field_name):
|
100
|
+
actual_output = getattr(response, response_field_name)
|
101
|
+
else:
|
102
|
+
actual_output = response
|
103
|
+
|
104
|
+
# Extract content and tool calls from the completion
|
105
|
+
content = None
|
106
|
+
tool_calls = None
|
107
|
+
refusal = None
|
108
|
+
|
109
|
+
if hasattr(completion, "choices") and completion.choices:
|
110
|
+
choice = completion.choices[0]
|
111
|
+
if hasattr(choice, "message"):
|
112
|
+
message = choice.message
|
113
|
+
content = getattr(message, "content", None)
|
114
|
+
tool_calls = getattr(message, "tool_calls", None)
|
115
|
+
refusal = getattr(message, "refusal", None)
|
116
|
+
|
117
|
+
return LanguageModelResponse(
|
118
|
+
model=model,
|
119
|
+
output=actual_output,
|
120
|
+
completion=completion,
|
121
|
+
content=content,
|
122
|
+
tool_calls=tool_calls,
|
123
|
+
refusal=refusal,
|
124
|
+
)
|