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.
Files changed (122) hide show
  1. hammad/__init__.py +177 -0
  2. hammad/{performance/imports.py → _internal.py} +7 -1
  3. hammad/cache/__init__.py +1 -1
  4. hammad/cli/__init__.py +3 -1
  5. hammad/cli/_runner.py +265 -0
  6. hammad/cli/animations.py +1 -1
  7. hammad/cli/plugins.py +133 -78
  8. hammad/cli/styles/__init__.py +1 -1
  9. hammad/cli/styles/utils.py +149 -3
  10. hammad/data/__init__.py +56 -29
  11. hammad/data/collections/__init__.py +27 -17
  12. hammad/data/collections/collection.py +205 -383
  13. hammad/data/collections/indexes/__init__.py +37 -0
  14. hammad/data/collections/indexes/qdrant/__init__.py +1 -0
  15. hammad/data/collections/indexes/qdrant/index.py +735 -0
  16. hammad/data/collections/indexes/qdrant/settings.py +94 -0
  17. hammad/data/collections/indexes/qdrant/utils.py +220 -0
  18. hammad/data/collections/indexes/tantivy/__init__.py +1 -0
  19. hammad/data/collections/indexes/tantivy/index.py +428 -0
  20. hammad/data/collections/indexes/tantivy/settings.py +51 -0
  21. hammad/data/collections/indexes/tantivy/utils.py +200 -0
  22. hammad/data/configurations/__init__.py +2 -2
  23. hammad/data/configurations/configuration.py +2 -2
  24. hammad/data/models/__init__.py +20 -9
  25. hammad/data/models/extensions/__init__.py +4 -0
  26. hammad/data/models/{pydantic → extensions/pydantic}/__init__.py +6 -19
  27. hammad/data/models/{pydantic → extensions/pydantic}/converters.py +143 -16
  28. hammad/data/models/{base/fields.py → fields.py} +1 -1
  29. hammad/data/models/{base/model.py → model.py} +1 -1
  30. hammad/data/models/{base/utils.py → utils.py} +1 -1
  31. hammad/data/sql/__init__.py +23 -0
  32. hammad/data/sql/database.py +578 -0
  33. hammad/data/sql/types.py +141 -0
  34. hammad/data/types/__init__.py +1 -3
  35. hammad/data/types/file.py +3 -3
  36. hammad/data/types/multimodal/__init__.py +2 -2
  37. hammad/data/types/multimodal/audio.py +2 -2
  38. hammad/data/types/multimodal/image.py +2 -2
  39. hammad/formatting/__init__.py +9 -27
  40. hammad/formatting/json/__init__.py +8 -2
  41. hammad/formatting/json/converters.py +7 -1
  42. hammad/formatting/text/__init__.py +1 -1
  43. hammad/formatting/yaml/__init__.py +1 -1
  44. hammad/genai/__init__.py +78 -0
  45. hammad/genai/agents/__init__.py +1 -0
  46. hammad/genai/agents/types/__init__.py +35 -0
  47. hammad/genai/agents/types/history.py +277 -0
  48. hammad/genai/agents/types/tool.py +490 -0
  49. hammad/genai/embedding_models/__init__.py +41 -0
  50. hammad/{ai/embeddings/client/litellm_embeddings_client.py → genai/embedding_models/embedding_model.py} +47 -142
  51. hammad/genai/embedding_models/embedding_model_name.py +77 -0
  52. hammad/genai/embedding_models/embedding_model_request.py +65 -0
  53. hammad/{ai/embeddings/types.py → genai/embedding_models/embedding_model_response.py} +3 -3
  54. hammad/genai/embedding_models/run.py +161 -0
  55. hammad/genai/language_models/__init__.py +35 -0
  56. hammad/genai/language_models/_streaming.py +622 -0
  57. hammad/genai/language_models/_types.py +276 -0
  58. hammad/genai/language_models/_utils/__init__.py +31 -0
  59. hammad/genai/language_models/_utils/_completions.py +131 -0
  60. hammad/genai/language_models/_utils/_messages.py +89 -0
  61. hammad/genai/language_models/_utils/_requests.py +202 -0
  62. hammad/genai/language_models/_utils/_structured_outputs.py +124 -0
  63. hammad/genai/language_models/language_model.py +734 -0
  64. hammad/genai/language_models/language_model_request.py +135 -0
  65. hammad/genai/language_models/language_model_response.py +219 -0
  66. hammad/genai/language_models/language_model_response_chunk.py +53 -0
  67. hammad/genai/language_models/run.py +530 -0
  68. hammad/genai/multimodal_models.py +48 -0
  69. hammad/genai/rerank_models.py +26 -0
  70. hammad/logging/__init__.py +1 -1
  71. hammad/logging/decorators.py +1 -1
  72. hammad/logging/logger.py +2 -2
  73. hammad/mcp/__init__.py +1 -1
  74. hammad/mcp/client/__init__.py +35 -0
  75. hammad/mcp/client/client.py +105 -4
  76. hammad/mcp/client/client_service.py +10 -3
  77. hammad/mcp/servers/__init__.py +24 -0
  78. hammad/{performance/runtime → runtime}/__init__.py +2 -2
  79. hammad/{performance/runtime → runtime}/decorators.py +1 -1
  80. hammad/{performance/runtime → runtime}/run.py +1 -1
  81. hammad/service/__init__.py +1 -1
  82. hammad/service/create.py +3 -8
  83. hammad/service/decorators.py +8 -8
  84. hammad/typing/__init__.py +28 -0
  85. hammad/web/__init__.py +3 -3
  86. hammad/web/http/client.py +1 -1
  87. hammad/web/models.py +53 -21
  88. hammad/web/search/client.py +99 -52
  89. hammad/web/utils.py +13 -13
  90. hammad_python-0.0.16.dist-info/METADATA +191 -0
  91. hammad_python-0.0.16.dist-info/RECORD +110 -0
  92. hammad/ai/__init__.py +0 -1
  93. hammad/ai/_utils.py +0 -142
  94. hammad/ai/completions/__init__.py +0 -45
  95. hammad/ai/completions/client.py +0 -684
  96. hammad/ai/completions/create.py +0 -710
  97. hammad/ai/completions/settings.py +0 -100
  98. hammad/ai/completions/types.py +0 -792
  99. hammad/ai/completions/utils.py +0 -486
  100. hammad/ai/embeddings/__init__.py +0 -35
  101. hammad/ai/embeddings/client/__init__.py +0 -1
  102. hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
  103. hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
  104. hammad/ai/embeddings/create.py +0 -159
  105. hammad/data/collections/base_collection.py +0 -58
  106. hammad/data/collections/searchable_collection.py +0 -556
  107. hammad/data/collections/vector_collection.py +0 -596
  108. hammad/data/databases/__init__.py +0 -21
  109. hammad/data/databases/database.py +0 -902
  110. hammad/data/models/base/__init__.py +0 -35
  111. hammad/data/models/pydantic/models/__init__.py +0 -28
  112. hammad/data/models/pydantic/models/arbitrary_model.py +0 -46
  113. hammad/data/models/pydantic/models/cacheable_model.py +0 -79
  114. hammad/data/models/pydantic/models/fast_model.py +0 -318
  115. hammad/data/models/pydantic/models/function_model.py +0 -176
  116. hammad/data/models/pydantic/models/subscriptable_model.py +0 -63
  117. hammad/performance/__init__.py +0 -36
  118. hammad/py.typed +0 -0
  119. hammad_python-0.0.14.dist-info/METADATA +0 -70
  120. hammad_python-0.0.14.dist-info/RECORD +0 -99
  121. {hammad_python-0.0.14.dist-info → hammad_python-0.0.16.dist-info}/WHEEL +0 -0
  122. {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
+ )