hammad-python 0.0.19__py3-none-any.whl → 0.0.21__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 (83) hide show
  1. hammad/__init__.py +7 -137
  2. hammad/_internal.py +1 -0
  3. hammad/cli/_runner.py +8 -8
  4. hammad/cli/plugins.py +55 -26
  5. hammad/cli/styles/utils.py +16 -8
  6. hammad/data/__init__.py +1 -5
  7. hammad/data/collections/__init__.py +2 -3
  8. hammad/data/collections/collection.py +41 -22
  9. hammad/data/collections/indexes/__init__.py +1 -1
  10. hammad/data/collections/indexes/qdrant/__init__.py +1 -1
  11. hammad/data/collections/indexes/qdrant/index.py +106 -118
  12. hammad/data/collections/indexes/qdrant/settings.py +14 -14
  13. hammad/data/collections/indexes/qdrant/utils.py +28 -38
  14. hammad/data/collections/indexes/tantivy/__init__.py +1 -1
  15. hammad/data/collections/indexes/tantivy/index.py +57 -59
  16. hammad/data/collections/indexes/tantivy/settings.py +8 -19
  17. hammad/data/collections/indexes/tantivy/utils.py +28 -52
  18. hammad/data/models/__init__.py +2 -7
  19. hammad/data/sql/__init__.py +1 -1
  20. hammad/data/sql/database.py +71 -73
  21. hammad/data/sql/types.py +37 -51
  22. hammad/formatting/__init__.py +2 -1
  23. hammad/formatting/json/converters.py +2 -2
  24. hammad/genai/__init__.py +96 -36
  25. hammad/genai/agents/__init__.py +47 -1
  26. hammad/genai/agents/agent.py +1298 -0
  27. hammad/genai/agents/run.py +615 -0
  28. hammad/genai/agents/types/__init__.py +29 -22
  29. hammad/genai/agents/types/agent_context.py +13 -0
  30. hammad/genai/agents/types/agent_event.py +128 -0
  31. hammad/genai/agents/types/agent_hooks.py +220 -0
  32. hammad/genai/agents/types/agent_messages.py +31 -0
  33. hammad/genai/agents/types/agent_response.py +122 -0
  34. hammad/genai/agents/types/agent_stream.py +318 -0
  35. hammad/genai/models/__init__.py +1 -0
  36. hammad/genai/models/embeddings/__init__.py +39 -0
  37. hammad/genai/{embedding_models/embedding_model.py → models/embeddings/model.py} +45 -41
  38. hammad/genai/{embedding_models → models/embeddings}/run.py +10 -8
  39. hammad/genai/models/embeddings/types/__init__.py +37 -0
  40. hammad/genai/{embedding_models → models/embeddings/types}/embedding_model_name.py +2 -4
  41. hammad/genai/{embedding_models → models/embeddings/types}/embedding_model_response.py +11 -4
  42. hammad/genai/{embedding_models/embedding_model_request.py → models/embeddings/types/embedding_model_run_params.py} +4 -3
  43. hammad/genai/models/embeddings/types/embedding_model_settings.py +47 -0
  44. hammad/genai/models/language/__init__.py +48 -0
  45. hammad/genai/{language_models/language_model.py → models/language/model.py} +496 -204
  46. hammad/genai/{language_models → models/language}/run.py +80 -57
  47. hammad/genai/models/language/types/__init__.py +40 -0
  48. hammad/genai/models/language/types/language_model_instructor_mode.py +47 -0
  49. hammad/genai/models/language/types/language_model_messages.py +28 -0
  50. hammad/genai/{language_models/_types.py → models/language/types/language_model_name.py} +3 -40
  51. hammad/genai/{language_models → models/language/types}/language_model_request.py +17 -25
  52. hammad/genai/{language_models → models/language/types}/language_model_response.py +60 -67
  53. hammad/genai/{language_models → models/language/types}/language_model_response_chunk.py +8 -5
  54. hammad/genai/models/language/types/language_model_settings.py +89 -0
  55. hammad/genai/{language_models/_streaming.py → models/language/types/language_model_stream.py} +221 -243
  56. hammad/genai/{language_models/_utils → models/language/utils}/__init__.py +8 -11
  57. hammad/genai/models/language/utils/requests.py +421 -0
  58. hammad/genai/{language_models/_utils/_structured_outputs.py → models/language/utils/structured_outputs.py} +31 -20
  59. hammad/genai/models/model_provider.py +4 -0
  60. hammad/genai/{multimodal_models.py → models/multimodal.py} +4 -5
  61. hammad/genai/models/reranking.py +26 -0
  62. hammad/genai/types/__init__.py +1 -0
  63. hammad/genai/types/base.py +215 -0
  64. hammad/genai/{agents/types → types}/history.py +101 -88
  65. hammad/genai/{agents/types/tool.py → types/tools.py} +157 -140
  66. hammad/logging/logger.py +9 -1
  67. hammad/mcp/client/__init__.py +2 -3
  68. hammad/mcp/client/client.py +10 -10
  69. hammad/mcp/servers/__init__.py +2 -1
  70. hammad/service/decorators.py +1 -3
  71. hammad/web/models.py +1 -3
  72. hammad/web/search/client.py +10 -22
  73. {hammad_python-0.0.19.dist-info → hammad_python-0.0.21.dist-info}/METADATA +10 -2
  74. hammad_python-0.0.21.dist-info/RECORD +127 -0
  75. hammad/genai/embedding_models/__init__.py +0 -41
  76. hammad/genai/language_models/__init__.py +0 -35
  77. hammad/genai/language_models/_utils/_completions.py +0 -131
  78. hammad/genai/language_models/_utils/_messages.py +0 -89
  79. hammad/genai/language_models/_utils/_requests.py +0 -202
  80. hammad/genai/rerank_models.py +0 -26
  81. hammad_python-0.0.19.dist-info/RECORD +0 -111
  82. {hammad_python-0.0.19.dist-info → hammad_python-0.0.21.dist-info}/WHEEL +0 -0
  83. {hammad_python-0.0.19.dist-info → hammad_python-0.0.21.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,318 @@
1
+ """hammad.genai.agents.types.agent_stream"""
2
+
3
+ from typing import (
4
+ Generic,
5
+ TypeVar,
6
+ Iterator,
7
+ AsyncIterator,
8
+ List,
9
+ Any,
10
+ Dict,
11
+ Optional,
12
+ TYPE_CHECKING,
13
+ Type,
14
+ Union,
15
+ Literal,
16
+ )
17
+ from contextlib import contextmanager, asynccontextmanager
18
+
19
+ from ...types.base import BaseGenAIModelStream
20
+ from ...types.tools import (
21
+ Tool,
22
+ execute_tools_from_language_model_response,
23
+ )
24
+ from ...models.language.model import LanguageModel
25
+ from ...models.language.types import (
26
+ LanguageModelMessages,
27
+ LanguageModelResponse,
28
+ LanguageModelResponseChunk,
29
+ LanguageModelStream,
30
+ LanguageModelSettings,
31
+ )
32
+ from ...models.language.utils.requests import (
33
+ parse_messages_input as parse_messages,
34
+ consolidate_system_messages,
35
+ )
36
+
37
+ from .agent_response import (
38
+ AgentResponse,
39
+ _create_agent_response_from_language_model_response,
40
+ )
41
+ from .agent_context import AgentContext
42
+
43
+ if TYPE_CHECKING:
44
+ from ..agent import Agent
45
+
46
+ T = TypeVar("T")
47
+
48
+
49
+ class AgentResponseChunk(LanguageModelResponseChunk[T], Generic[T]):
50
+ """A chunk from an agent response stream representing a single step."""
51
+
52
+ def __init__(
53
+ self,
54
+ step_number: int,
55
+ response: LanguageModelResponse[str],
56
+ output: T | None = None,
57
+ content: str | None = None,
58
+ model: str | None = None,
59
+ is_final: bool = False,
60
+ **kwargs: Any,
61
+ ):
62
+ """Initialize a AgentResponseChunk.
63
+
64
+ Args:
65
+ step_number: The step number of this chunk
66
+ response: The language model response for this step
67
+ output: The output value
68
+ content: The content string
69
+ model: The model name
70
+ is_final: Whether this is the final chunk
71
+ **kwargs: Additional keyword arguments
72
+ """
73
+ super().__init__(
74
+ output=output if output is not None else response.output,
75
+ content=content if content is not None else response.content,
76
+ model=model if model is not None else response.model,
77
+ is_final=is_final,
78
+ **kwargs,
79
+ )
80
+ self.step_number = step_number
81
+ self.response = response
82
+
83
+ def __bool__(self) -> bool:
84
+ """Check if this chunk has meaningful content."""
85
+ return bool(self.response)
86
+
87
+ def __str__(self) -> str:
88
+ """String representation of the chunk."""
89
+ output = f"AgentResponseChunk(step={self.step_number}, final={self.is_final})"
90
+
91
+ # Show content if available
92
+ if self.output or self.content:
93
+ content_preview = str(self.output if self.output else self.content)
94
+ if len(content_preview) > 100:
95
+ content_preview = content_preview[:100] + "..."
96
+ output += f"\nContent: {content_preview}"
97
+
98
+ return output
99
+
100
+
101
+ class AgentStream(BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentContext]):
102
+ """Stream of agent responses that can be used in sync and async contexts."""
103
+
104
+ def __init__(
105
+ self,
106
+ agent: "Agent[T]",
107
+ messages: LanguageModelMessages,
108
+ model: Optional[Union[LanguageModel, str]] = None,
109
+ max_steps: Optional[int] = None,
110
+ context: Optional[AgentContext] = None,
111
+ output_type: Optional[Type[T]] = None,
112
+ stream: bool = False,
113
+ **kwargs: Any,
114
+ ):
115
+ self.agent = agent
116
+ self.messages = messages
117
+ self.context = context
118
+ self.output_type = output_type
119
+ self.stream = stream
120
+ self.kwargs = kwargs
121
+ self.current_step = 0
122
+ self.steps: List[LanguageModelResponse[str]] = []
123
+ self.current_messages = parse_messages(messages)
124
+ self.is_done = False
125
+ self._final_response: Optional[LanguageModelResponse[str]] = None
126
+
127
+ # Model setup
128
+ if model is None:
129
+ self.model = agent.model
130
+ elif isinstance(model, str):
131
+ self.model = LanguageModel(model=model)
132
+ else:
133
+ self.model = model
134
+
135
+ # Max steps setup
136
+ self.max_steps = max_steps or agent.settings.max_steps
137
+
138
+ # Context handling
139
+ self.current_context = context
140
+ self.initial_context = context
141
+
142
+ # Model kwargs setup
143
+ self.model_kwargs = kwargs.copy()
144
+ if output_type:
145
+ self.model_kwargs["type"] = output_type
146
+ if agent.instructor_mode:
147
+ self.model_kwargs["instructor_mode"] = agent.instructor_mode
148
+ if stream:
149
+ self.model_kwargs["stream"] = stream
150
+
151
+ def _format_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
152
+ if self.agent.instructions:
153
+ system_content = self.agent.instructions
154
+
155
+ # Add context if available
156
+ if self.current_context is not None:
157
+ from ..agent import _format_context_for_instructions
158
+ context_str = _format_context_for_instructions(
159
+ self.current_context, self.agent.context_format
160
+ )
161
+ if context_str:
162
+ system_content += f"\n\nContext:\n{context_str}"
163
+
164
+ system_message = {"role": "system", "content": system_content}
165
+ messages = [system_message] + messages
166
+ return consolidate_system_messages(messages)
167
+
168
+ def _process_response(
169
+ self, response: LanguageModelResponse
170
+ ) -> AgentResponseChunk[T]:
171
+ self.current_messages.append(response.to_message())
172
+
173
+ if response.has_tool_calls:
174
+ tool_responses = execute_tools_from_language_model_response(
175
+ tools=self.agent.tools, response=response
176
+ )
177
+ for tool_resp in tool_responses:
178
+ self.current_messages.append(tool_resp.to_dict())
179
+
180
+ self.steps.append(response)
181
+ return AgentResponseChunk(
182
+ step_number=self.current_step, response=response, is_final=False
183
+ )
184
+ else:
185
+ self.is_done = True
186
+ self._final_response = response
187
+
188
+ # Update context after processing if configured
189
+ if self.current_context and self.agent._should_update_context(self.current_context, "after"):
190
+ self.current_context = self.agent._perform_context_update(
191
+ context=self.current_context,
192
+ model=self.model,
193
+ current_messages=self.current_messages,
194
+ timing="after",
195
+ )
196
+
197
+ return AgentResponseChunk(
198
+ step_number=self.current_step, response=response, is_final=True
199
+ )
200
+
201
+ def __iter__(self) -> Iterator[AgentResponseChunk[T]]:
202
+ # The context manager handling should be managed by the agent's run method
203
+ while not self.is_done and self.current_step < self.max_steps:
204
+ self.current_step += 1
205
+
206
+ # Update context before processing if configured
207
+ if self.current_context and self.agent._should_update_context(self.current_context, "before"):
208
+ self.current_context = self.agent._perform_context_update(
209
+ context=self.current_context,
210
+ model=self.model,
211
+ current_messages=self.current_messages,
212
+ timing="before",
213
+ )
214
+
215
+ formatted_messages = self.current_messages
216
+ if self.current_step == 1:
217
+ formatted_messages = self._format_messages(self.current_messages)
218
+
219
+ response = self.model.run(
220
+ messages=formatted_messages,
221
+ tools=[tool.model_dump() for tool in self.agent.tools]
222
+ if self.agent.tools
223
+ else None,
224
+ **self.model_kwargs,
225
+ )
226
+
227
+ chunk = self._process_response(response)
228
+ yield chunk
229
+ if chunk.is_final:
230
+ break
231
+
232
+ def __aiter__(self) -> AsyncIterator[AgentResponseChunk[T]]:
233
+ return self
234
+
235
+ async def __anext__(self) -> AgentResponseChunk[T]:
236
+ if self.is_done or self.current_step >= self.max_steps:
237
+ raise StopAsyncIteration
238
+
239
+ # The context manager handling should be managed by the agent's run method
240
+ self.current_step += 1
241
+
242
+ # Update context before processing if configured
243
+ if self.current_context and self.agent._should_update_context(self.current_context, "before"):
244
+ self.current_context = self.agent._perform_context_update(
245
+ context=self.current_context,
246
+ model=self.model,
247
+ current_messages=self.current_messages,
248
+ timing="before",
249
+ )
250
+
251
+ formatted_messages = self.current_messages
252
+ if self.current_step == 1:
253
+ formatted_messages = self._format_messages(self.current_messages)
254
+
255
+ response = await self.model.async_run(
256
+ messages=formatted_messages,
257
+ tools=[tool.model_dump() for tool in self.agent.tools]
258
+ if self.agent.tools
259
+ else None,
260
+ **self.model_kwargs,
261
+ )
262
+
263
+ chunk = self._process_response(response)
264
+ if chunk.is_final:
265
+ self.is_done = True
266
+ return chunk
267
+
268
+ def _build_response(self) -> AgentResponse[T, AgentContext]:
269
+ if self._final_response:
270
+ final_response = self._final_response
271
+ elif self.steps:
272
+ final_response = self.steps[-1]
273
+ else:
274
+ raise RuntimeError("No response generated by the agent.")
275
+
276
+ return _create_agent_response_from_language_model_response(
277
+ response=final_response,
278
+ steps=self.steps,
279
+ context=self.current_context,
280
+ )
281
+
282
+ def _format_context_display(self, context: AgentContext) -> str:
283
+ """Format context for display in string representation."""
284
+ if context is None:
285
+ return "None"
286
+
287
+ try:
288
+ # For Pydantic models, show as dict
289
+ if hasattr(context, 'model_dump'):
290
+ context_dict = context.model_dump()
291
+ elif isinstance(context, dict):
292
+ context_dict = context
293
+ else:
294
+ return str(context)
295
+
296
+ # Format as compact JSON-like string
297
+ items = []
298
+ for key, value in context_dict.items():
299
+ if isinstance(value, str):
300
+ items.append(f"{key}='{value}'")
301
+ else:
302
+ items.append(f"{key}={value}")
303
+
304
+ return "{" + ", ".join(items) + "}"
305
+ except Exception:
306
+ return str(context)
307
+
308
+ def collect(self) -> AgentResponse[T, AgentContext]:
309
+ """Collect all steps and return final response."""
310
+ for _ in self:
311
+ pass
312
+ return self._build_response()
313
+
314
+ async def async_collect(self) -> AgentResponse[T, AgentContext]:
315
+ """Collect all steps and return final response."""
316
+ async for _ in self:
317
+ pass
318
+ return self._build_response()
@@ -0,0 +1 @@
1
+ """hammad.genai.models"""
@@ -0,0 +1,39 @@
1
+ """hammad.genai.models.embeddings"""
2
+
3
+ from typing import TYPE_CHECKING
4
+ from ...._internal import create_getattr_importer
5
+
6
+
7
+ if TYPE_CHECKING:
8
+ from .model import EmbeddingModel
9
+ from .run import (
10
+ run_embedding_model,
11
+ async_run_embedding_model,
12
+ )
13
+ from .types import (
14
+ Embedding,
15
+ EmbeddingModelResponse,
16
+ EmbeddingModelSettings,
17
+ )
18
+
19
+
20
+ __all__ = [
21
+ "EmbeddingModel",
22
+ # hammad.genai.models.embeddings.run
23
+ "run_embedding_model",
24
+ "async_run_embedding_model",
25
+ # hammad.genai.models.embeddings.types.embedding
26
+ "Embedding",
27
+ # hammad.genai.models.embeddings.types.embedding_model_response
28
+ "EmbeddingModelResponse",
29
+ # hammad.genai.models.embeddings.types.embedding_model_settings
30
+ "EmbeddingModelSettings",
31
+ ]
32
+
33
+
34
+ __getattr__ = create_getattr_importer(__all__)
35
+
36
+
37
+ def __dir__() -> list[str]:
38
+ """Return the list of attributes to be shown in the REPL."""
39
+ return __all__
@@ -2,7 +2,7 @@
2
2
 
3
3
  import asyncio
4
4
  from dataclasses import dataclass
5
- from typing import Any, List, Literal, Optional, TYPE_CHECKING
5
+ from typing import Any, List, Optional
6
6
  import sys
7
7
 
8
8
  if sys.version_info >= (3, 12):
@@ -10,21 +10,17 @@ if sys.version_info >= (3, 12):
10
10
  else:
11
11
  from typing_extensions import TypedDict
12
12
 
13
- if TYPE_CHECKING:
14
- try:
15
- from litellm import EmbeddingResponse as _LitellmEmbeddingResponse
16
- except ImportError:
17
- _LitellmEmbeddingResponse = Any
18
-
19
- from ..language_models.language_model import _AIProvider
20
- from .embedding_model_request import EmbeddingModelRequest
21
- from .embedding_model_name import EmbeddingModelName
22
- from .embedding_model_response import (
13
+ from ..model_provider import litellm
14
+
15
+ from .types import (
16
+ EmbeddingModelName,
17
+ EmbeddingModelRunParams,
18
+ EmbeddingModelSettings,
23
19
  Embedding,
24
20
  EmbeddingUsage,
25
21
  EmbeddingModelResponse,
26
22
  )
27
- from ...formatting.text import convert_to_text
23
+ from ....formatting.text import convert_to_text
28
24
 
29
25
 
30
26
  __all__ = (
@@ -43,7 +39,9 @@ class EmbeddingModelError(Exception):
43
39
  super().__init__(self.message)
44
40
 
45
41
 
46
- def _parse_litellm_response_to_embedding_model_response(response: "_LitellmEmbeddingResponse") -> EmbeddingModelResponse:
42
+ def _parse_litellm_response_to_embedding_model_response(
43
+ response: "litellm.EmbeddingResponse",
44
+ ) -> EmbeddingModelResponse:
47
45
  """Parse the response from `litellm` to an `EmbeddingModelResponse` object."""
48
46
  try:
49
47
  embedding_data: List[Embedding] = []
@@ -57,10 +55,11 @@ def _parse_litellm_response_to_embedding_model_response(response: "_LitellmEmbed
57
55
  total_tokens=response.usage.total_tokens,
58
56
  )
59
57
  return EmbeddingModelResponse(
60
- data=embedding_data,
58
+ output=embedding_data,
61
59
  model=response.model,
62
60
  object="list",
63
61
  usage=usage,
62
+ type="embedding_model",
64
63
  )
65
64
  except Exception as e:
66
65
  raise EmbeddingModelError(
@@ -73,19 +72,30 @@ def _parse_litellm_response_to_embedding_model_response(response: "_LitellmEmbed
73
72
  class EmbeddingModel:
74
73
  """Embeddings provider client that utilizes the `litellm` module
75
74
  when generating embeddings."""
76
-
77
- model: EmbeddingModelName = "openai/text-embedding-3-small"
78
-
75
+
76
+ model: EmbeddingModelName | str = "openai/text-embedding-3-small"
77
+
78
+ base_url: Optional[str] = None
79
+ """Optional base URL for a custom embedding provider."""
80
+
81
+ api_key: Optional[str] = None
82
+ """Optional API key for a custom embedding provider."""
83
+
84
+ api_type: Optional[str] = None
85
+ """Optional API type for a custom embedding provider."""
86
+
87
+ api_version: Optional[str] = None
88
+ """Optional API version for a custom embedding provider."""
89
+
90
+ settings: EmbeddingModelSettings = EmbeddingModelSettings()
91
+ """Optional settings for the embedding model."""
92
+
79
93
  async def async_run(
80
94
  self,
81
95
  input: List[Any] | Any,
82
96
  dimensions: Optional[int] = None,
83
97
  encoding_format: Optional[str] = None,
84
98
  timeout=600,
85
- api_base: Optional[str] = None,
86
- api_version: Optional[str] = None,
87
- api_key: Optional[str] = None,
88
- api_type: Optional[str] = None,
89
99
  caching: bool = False,
90
100
  user: Optional[str] = None,
91
101
  format: bool = False,
@@ -122,24 +132,26 @@ class EmbeddingModel:
122
132
  i,
123
133
  )
124
134
 
125
- async_embedding_fn = _AIProvider.get_litellm().aembedding
135
+ async_embedding_fn = litellm.aembedding
126
136
 
127
137
  try:
128
138
  response = await async_embedding_fn(
129
139
  model=self.model,
130
140
  input=input,
131
- dimensions=dimensions,
132
- encoding_format=encoding_format,
133
- timeout=timeout,
134
- api_base=api_base,
135
- api_version=api_version,
136
- api_key=api_key,
137
- api_type=api_type,
138
- caching=caching,
139
- user=user,
141
+ dimensions=dimensions or self.settings.dimensions,
142
+ encoding_format=encoding_format or self.settings.encoding_format,
143
+ timeout=timeout or self.settings.timeout,
144
+ api_base=self.base_url or self.settings.api_base,
145
+ api_version=self.api_version or self.settings.api_version,
146
+ api_key=self.api_key or self.settings.api_key,
147
+ api_type=self.api_type or self.settings.api_type,
148
+ caching=caching or self.settings.caching,
149
+ user=user or self.settings.user,
140
150
  )
141
151
  except Exception as e:
142
- raise EmbeddingModelError(f"Error in embedding model request: {e}", response=None) from e
152
+ raise EmbeddingModelError(
153
+ f"Error in embedding model request: {e}", response=None
154
+ ) from e
143
155
 
144
156
  return _parse_litellm_response_to_embedding_model_response(response)
145
157
 
@@ -149,10 +161,6 @@ class EmbeddingModel:
149
161
  dimensions: Optional[int] = None,
150
162
  encoding_format: Optional[str] = None,
151
163
  timeout=600,
152
- api_base: Optional[str] = None,
153
- api_version: Optional[str] = None,
154
- api_key: Optional[str] = None,
155
- api_type: Optional[str] = None,
156
164
  caching: bool = False,
157
165
  user: Optional[str] = None,
158
166
  format: bool = False,
@@ -182,12 +190,8 @@ class EmbeddingModel:
182
190
  dimensions=dimensions,
183
191
  encoding_format=encoding_format,
184
192
  timeout=timeout,
185
- api_base=api_base,
186
- api_version=api_version,
187
- api_key=api_key,
188
- api_type=api_type,
189
193
  caching=caching,
190
194
  user=user,
191
195
  format=format,
192
196
  )
193
- )
197
+ )
@@ -5,9 +5,11 @@ Standalone functions for running embedding models with full parameter typing.
5
5
 
6
6
  from typing import Any, List, Optional, overload, Union
7
7
 
8
- from .embedding_model_name import EmbeddingModelName
9
- from .embedding_model import EmbeddingModel
10
- from .embedding_model_response import EmbeddingModelResponse
8
+ from .types import (
9
+ EmbeddingModelName,
10
+ EmbeddingModelResponse,
11
+ )
12
+ from .model import EmbeddingModel
11
13
 
12
14
  __all__ = [
13
15
  "run_embedding_model",
@@ -54,7 +56,7 @@ def run_embedding_model(
54
56
  format: bool = False,
55
57
  ) -> EmbeddingModelResponse:
56
58
  """Run an embedding model with the given input.
57
-
59
+
58
60
  Args:
59
61
  input: The input text/content to generate embeddings for
60
62
  model: The embedding model to use
@@ -68,7 +70,7 @@ def run_embedding_model(
68
70
  caching: Whether to cache the request
69
71
  user: The user to use for the request
70
72
  format: Whether to format each non-string input as a markdown string
71
-
73
+
72
74
  Returns:
73
75
  EmbeddingModelResponse: The embedding response
74
76
  """
@@ -127,7 +129,7 @@ async def async_run_embedding_model(
127
129
  format: bool = False,
128
130
  ) -> EmbeddingModelResponse:
129
131
  """Asynchronously run an embedding model with the given input.
130
-
132
+
131
133
  Args:
132
134
  input: The input text/content to generate embeddings for
133
135
  model: The embedding model to use
@@ -141,7 +143,7 @@ async def async_run_embedding_model(
141
143
  caching: Whether to cache the request
142
144
  user: The user to use for the request
143
145
  format: Whether to format each non-string input as a markdown string
144
-
146
+
145
147
  Returns:
146
148
  EmbeddingModelResponse: The embedding response
147
149
  """
@@ -158,4 +160,4 @@ async def async_run_embedding_model(
158
160
  caching=caching,
159
161
  user=user,
160
162
  format=format,
161
- )
163
+ )
@@ -0,0 +1,37 @@
1
+ """hammad.genai.models.embeddings.types"""
2
+
3
+ from typing import TYPE_CHECKING
4
+ from ....._internal import create_getattr_importer
5
+
6
+
7
+ if TYPE_CHECKING:
8
+ from .embedding_model_name import EmbeddingModelName
9
+ from .embedding_model_run_params import EmbeddingModelRunParams
10
+ from .embedding_model_response import (
11
+ Embedding,
12
+ EmbeddingUsage,
13
+ EmbeddingModelResponse,
14
+ )
15
+ from .embedding_model_settings import EmbeddingModelSettings
16
+
17
+
18
+ __all__ = [
19
+ # hammad.genai.models.embeddings.types.embedding_model_name
20
+ "EmbeddingModelName",
21
+ # hammad.genai.models.embeddings.types.embedding_model_run_params
22
+ "EmbeddingModelRunParams",
23
+ # hammad.genai.models.embeddings.types.embedding_model_response
24
+ "Embedding",
25
+ "EmbeddingUsage",
26
+ "EmbeddingModelResponse",
27
+ # hammad.genai.models.embeddings.types.embedding_model_settings
28
+ "EmbeddingModelSettings",
29
+ ]
30
+
31
+
32
+ __getattr__ = create_getattr_importer(__all__)
33
+
34
+
35
+ def __dir__() -> list[str]:
36
+ """Return the list of attributes to be shown in the REPL."""
37
+ return __all__
@@ -3,9 +3,7 @@
3
3
  from typing import Literal
4
4
 
5
5
 
6
- __all__ = (
7
- "EmbeddingModelName",
8
- )
6
+ __all__ = ("EmbeddingModelName",)
9
7
 
10
8
 
11
9
  EmbeddingModelName = Literal[
@@ -74,4 +72,4 @@ EmbeddingModelName = Literal[
74
72
  "ollama/all-minilm",
75
73
  "ollama/nomic-embed-text",
76
74
  ]
77
- """Common embedding models supported by `litellm`."""
75
+ """Common embedding models supported by `litellm`."""
@@ -4,6 +4,8 @@ from typing import List, Literal
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
+ from ....types.base import BaseGenAIModelResponse
8
+
7
9
  __all__ = (
8
10
  "Embedding",
9
11
  "EmbeddingUsage",
@@ -41,8 +43,8 @@ class EmbeddingUsage(BaseModel):
41
43
  """The total number of tokens used by the request."""
42
44
 
43
45
 
44
- class EmbeddingModelResponse(BaseModel):
45
- data: List[Embedding]
46
+ class EmbeddingModelResponse(BaseGenAIModelResponse[List[Embedding]]):
47
+ output: List[Embedding]
46
48
  """The list of embeddings generated by the model."""
47
49
 
48
50
  model: str
@@ -54,10 +56,15 @@ class EmbeddingModelResponse(BaseModel):
54
56
  usage: EmbeddingUsage
55
57
  """The usage information for the request."""
56
58
 
59
+ @property
60
+ def data(self) -> List[Embedding]:
61
+ """The list of embeddings generated by the model."""
62
+ return self.output
63
+
57
64
  @property
58
65
  def dimensions(self) -> int:
59
66
  """The dimensions of the embedding."""
60
- return len(self.data[0].embedding)
67
+ return len(self.output[0].embedding)
61
68
 
62
69
  def __str__(self) -> str:
63
70
  return (
@@ -65,5 +72,5 @@ class EmbeddingModelResponse(BaseModel):
65
72
  f">>> Model: {self.model}\n"
66
73
  f">>> Dimensions: {self.dimensions}\n"
67
74
  f">>> Usage: {self.usage}\n"
68
- f">>> Number of Generated Embeddings: {len(self.data)}\n"
75
+ f">>> Number of Generated Embeddings: {len(self.output)}\n"
69
76
  )