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
@@ -8,7 +8,7 @@ from __future__ import annotations
8
8
  import asyncio
9
9
  from dataclasses import dataclass, field
10
10
  from pathlib import Path
11
- from typing import Any, Callable, Literal
11
+ from typing import Any, Callable, Literal, overload
12
12
  import threading
13
13
  import concurrent.futures
14
14
  import inspect
@@ -20,9 +20,10 @@ try:
20
20
  )
21
21
  from openai.types.shared import FunctionDefinition as Function
22
22
  except ImportError:
23
- raise ImportError(
24
- "Using mcp requires the `openai` & `mcp` packages. Please install with: pip install 'hammad-python[ai]'"
25
- )
23
+ CallToolResult = Any
24
+ MCPTool = Any
25
+ OpenAITool = Any
26
+ Function = Any
26
27
 
27
28
  from .client_service import (
28
29
  MCPClientService,
@@ -521,3 +522,103 @@ class MCPClient:
521
522
  async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
522
523
  """Async context manager exit."""
523
524
  await self.async_cleanup()
525
+
526
+
527
+ # -----------------------------------------------------------------------------
528
+ # Factory Function
529
+ # -----------------------------------------------------------------------------
530
+
531
+
532
+ @overload
533
+ def create_mcp_client(
534
+ type: Literal["stdio"],
535
+ *,
536
+ command: str,
537
+ args: list[str] | None = None,
538
+ env: dict[str, str] | None = None,
539
+ cwd: Path | str | None = None,
540
+ timeout: float = 30.0,
541
+ ) -> MCPClient:
542
+ """Create an MCP client with stdio transport."""
543
+ ...
544
+
545
+
546
+ @overload
547
+ def create_mcp_client(
548
+ type: Literal["sse"],
549
+ *,
550
+ url: str,
551
+ timeout: float = 30.0,
552
+ ) -> MCPClient:
553
+ """Create an MCP client with SSE transport."""
554
+ ...
555
+
556
+
557
+ @overload
558
+ def create_mcp_client(
559
+ type: Literal["http"],
560
+ *,
561
+ url: str,
562
+ timeout: float = 30.0,
563
+ ) -> MCPClient:
564
+ """Create an MCP client with HTTP transport."""
565
+ ...
566
+
567
+
568
+ def create_mcp_client(
569
+ type: Literal["stdio", "sse", "http"],
570
+ *,
571
+ command: str | None = None,
572
+ args: list[str] | None = None,
573
+ env: dict[str, str] | None = None,
574
+ cwd: Path | str | None = None,
575
+ url: str | None = None,
576
+ timeout: float = 30.0,
577
+ ) -> MCPClient:
578
+ """Create an MCP client with the specified transport type.
579
+
580
+ Args:
581
+ service_type: The type of transport to use ("stdio", "sse", or "http").
582
+ command: Command to run for stdio transport.
583
+ args: Arguments for the command (stdio only).
584
+ env: Environment variables for the command (stdio only).
585
+ cwd: Working directory for the command (stdio only).
586
+ url: URL for SSE or HTTP transport.
587
+ timeout: Connection timeout in seconds.
588
+
589
+ Returns:
590
+ A configured MCPClient instance.
591
+
592
+ Raises:
593
+ ValueError: If required parameters for the transport type are missing.
594
+ """
595
+ service_type = type
596
+
597
+ if service_type == "stdio":
598
+ if command is None:
599
+ raise ValueError("command is required for stdio transport")
600
+
601
+ service = MCPClientServiceStdio(
602
+ command=command,
603
+ args=args or [],
604
+ env=env or {},
605
+ cwd=Path(cwd) if cwd else None,
606
+ )
607
+
608
+ elif service_type == "sse":
609
+ if url is None:
610
+ raise ValueError("url is required for SSE transport")
611
+
612
+ service = MCPClientServiceSse(url=url)
613
+
614
+ elif service_type == "http":
615
+ if url is None:
616
+ raise ValueError("url is required for HTTP transport")
617
+
618
+ service = MCPClientServiceStreamableHttp(url=url)
619
+
620
+ else:
621
+ raise ValueError(f"Unsupported service_type: {service_type}")
622
+
623
+ settings = MCPClientSettings(timeout=timeout)
624
+ return MCPClient(service=service, settings=settings)
@@ -22,9 +22,16 @@ try:
22
22
  from mcp.shared.message import SessionMessage
23
23
  from mcp.types import CallToolResult, InitializeResult
24
24
  except ImportError:
25
- raise ImportError(
26
- "Using mcp requires the `openai` & `mcp` packages. Please install with: pip install 'hammad-python[ai]'"
27
- )
25
+ MCPTool = Any
26
+ ClientSession = Any
27
+ StdioServerParameters = Any
28
+ stdio_client = Any
29
+ sse_client = Any
30
+ GetSessionIdCallback = Any
31
+ streamablehttp_client = Any
32
+ SessionMessage = Any
33
+ CallToolResult = Any
34
+ InitializeResult = Any
28
35
 
29
36
  import logging
30
37
 
@@ -1 +1,25 @@
1
1
  """hammad.mcp.servers"""
2
+
3
+ from typing import TYPE_CHECKING
4
+ from ..._internal import create_getattr_importer
5
+
6
+ if TYPE_CHECKING:
7
+ from .launcher import (
8
+ launch_mcp_servers,
9
+ MCPServerStdioSettings,
10
+ MCPServerSseSettings,
11
+ MCPServerStreamableHttpSettings,
12
+ )
13
+
14
+ __all__ = (
15
+ "launch_mcp_servers",
16
+ "MCPServerStdioSettings",
17
+ "MCPServerSseSettings",
18
+ "MCPServerStreamableHttpSettings",
19
+ )
20
+
21
+ __getattr__ = create_getattr_importer(__all__)
22
+
23
+ def __dir__() -> list[str]:
24
+ """Get the attributes of the servers module."""
25
+ return list(__all__)
@@ -1,7 +1,7 @@
1
- """hammad.performance.runtime"""
1
+ """hammad.lib.runtime"""
2
2
 
3
3
  from typing import TYPE_CHECKING
4
- from ..imports import create_getattr_importer
4
+ from ..._internal import create_getattr_importer
5
5
 
6
6
 
7
7
  if TYPE_CHECKING:
@@ -1,4 +1,4 @@
1
- """hammad.performance.runtime.decorators"""
1
+ """hammad.runtime.decorators"""
2
2
 
3
3
  import functools
4
4
  from typing import (
@@ -1,4 +1,4 @@
1
- """hammad.performance.runtime.run"""
1
+ """hammad.runtime.run"""
2
2
 
3
3
  import concurrent.futures
4
4
  import itertools
@@ -21,7 +21,7 @@ resources within this submodule. This module contains function/decorators for:
21
21
  """
22
22
 
23
23
  from typing import TYPE_CHECKING
24
- from ..performance.imports import create_getattr_importer
24
+ from .._internal import create_getattr_importer
25
25
 
26
26
  if TYPE_CHECKING:
27
27
  from .create import (
hammad/service/create.py CHANGED
@@ -24,7 +24,6 @@ try:
24
24
  from fastapi import FastAPI, HTTPException
25
25
  from pydantic import BaseModel, create_model
26
26
  from uvicorn import Config, Server
27
- import uvloop
28
27
  except ImportError as e:
29
28
  raise ImportError(
30
29
  "Service dependencies not installed. Install with: pip install hammad-python[serve]"
@@ -58,7 +57,7 @@ class ServiceConfig:
58
57
  timeout_graceful_shutdown: int = 30
59
58
  access_log: bool = True
60
59
  use_colors: bool = True
61
- loop: str = "uvloop"
60
+ loop: str = "asyncio"
62
61
 
63
62
 
64
63
  class ServiceManager:
@@ -409,10 +408,6 @@ def create_service(
409
408
  if not auto_start:
410
409
  return app
411
410
 
412
- # Set up uvloop if available
413
- if hasattr(uvloop, "install"):
414
- uvloop.install()
415
-
416
411
  # Create and configure server
417
412
  config_obj = Config(
418
413
  app=app,
@@ -424,7 +419,7 @@ def create_service(
424
419
  timeout_keep_alive=timeout_keep_alive,
425
420
  access_log=access_log,
426
421
  use_colors=use_colors,
427
- loop="uvloop" if hasattr(uvloop, "install") else "asyncio",
422
+ loop="asyncio",
428
423
  )
429
424
 
430
425
  server = Server(config_obj)
@@ -502,7 +497,7 @@ async def async_create_service(
502
497
  timeout_keep_alive=timeout_keep_alive,
503
498
  access_log=access_log,
504
499
  use_colors=use_colors,
505
- loop="uvloop" if hasattr(uvloop, "install") else "asyncio",
500
+ loop="asyncio",
506
501
  )
507
502
 
508
503
  server = Server(config_obj)
@@ -124,7 +124,7 @@ def serve(
124
124
 
125
125
 
126
126
  def serve_mcp(
127
- func_or_funcs: Optional[Union[Callable, List[Callable]]] = None,
127
+ fn: Optional[Union[Callable, List[Callable]]] = None,
128
128
  *,
129
129
  # MCP Server configuration
130
130
  name: Optional[str] = None,
@@ -162,7 +162,7 @@ def serve_mcp(
162
162
  4. As a function with multiple functions: serve_mcp([func1, func2])
163
163
 
164
164
  Args:
165
- func_or_funcs: Function or list of functions to serve
165
+ fn: Function or list of functions to serve
166
166
  name: MCP server name
167
167
  instructions: Server instructions
168
168
  transport: Transport type (stdio, sse, streamable-http)
@@ -270,16 +270,16 @@ def serve_mcp(
270
270
  return funcs
271
271
 
272
272
  # Handle different call patterns
273
- if func_or_funcs is None:
273
+ if fn is None:
274
274
  # Called as @serve_mcp(...) - return decorator
275
275
  return decorator
276
- elif callable(func_or_funcs):
276
+ elif callable(fn):
277
277
  # Called as @serve_mcp (no parentheses) or serve_mcp(single_func)
278
- return decorator(func_or_funcs)
279
- elif isinstance(func_or_funcs, list):
278
+ return decorator(fn)
279
+ elif isinstance(fn, list):
280
280
  # Called as serve_mcp([func1, func2, ...])
281
- return handle_multiple_functions(func_or_funcs)
281
+ return handle_multiple_functions(fn)
282
282
  else:
283
283
  raise TypeError(
284
- f"Expected callable or list of callables, got {type(func_or_funcs)}"
284
+ f"Expected callable or list of callables, got {type(fn)}"
285
285
  )
hammad/typing/__init__.py CHANGED
@@ -6,6 +6,7 @@ core `typing` module, `typing_extensions`, `typing_inspect` and other
6
6
  resources."""
7
7
 
8
8
  from typing import Any, TYPE_CHECKING
9
+ import inspect
9
10
  import typing_inspect as inspection
10
11
 
11
12
  try:
@@ -190,6 +191,7 @@ __all__ = (
190
191
  "get_last_origin",
191
192
  "get_generic_bases",
192
193
  "get_typed_dict_keys",
194
+ "is_function",
193
195
  )
194
196
 
195
197
 
@@ -202,6 +204,32 @@ class TypingError(Exception):
202
204
  # ------------------------------------------------------------------------
203
205
 
204
206
 
207
+ def is_function(t: "Any") -> bool:
208
+ """Check if an object is a callable function.
209
+
210
+ This function identifies whether the given object is a callable function,
211
+ including regular functions, built-in functions, and methods, but excluding
212
+ classes and other callable objects that are not strictly functions.
213
+
214
+ Args:
215
+ t: The object to check. Can be a function, method, or any other type.
216
+
217
+ Returns:
218
+ True if the object is a function or method, False otherwise.
219
+
220
+ Example:
221
+ >>> def my_func():
222
+ ... pass
223
+ >>> is_function(my_func)
224
+ True
225
+ >>> is_function(lambda x: x)
226
+ True
227
+ >>> is_function(str)
228
+ False
229
+ """
230
+ return inspect.isfunction(t) or inspect.ismethod(t)
231
+
232
+
205
233
  def is_pydantic_basemodel(t: "Any") -> bool:
206
234
  """Check if an object is a Pydantic BaseModel class or instance using duck typing.
207
235
 
hammad/web/__init__.py CHANGED
@@ -1,14 +1,14 @@
1
1
  """hammad.web"""
2
2
 
3
3
  from typing import TYPE_CHECKING
4
- from ..performance.imports import create_getattr_importer
4
+ from .._internal import create_getattr_importer
5
5
 
6
6
  if TYPE_CHECKING:
7
7
  from .utils import (
8
8
  run_web_request,
9
9
  read_web_page,
10
10
  read_web_pages,
11
- search_web,
11
+ web_search,
12
12
  search_news,
13
13
  extract_page_links,
14
14
  )
@@ -20,7 +20,7 @@ __all__ = (
20
20
  "run_web_request",
21
21
  "read_web_page",
22
22
  "read_web_pages",
23
- "search_web",
23
+ "web_search",
24
24
  "search_news",
25
25
  "extract_page_links",
26
26
  "AsyncHttpClient",
hammad/web/http/client.py CHANGED
@@ -1,4 +1,4 @@
1
- """hammad.web.http.client"""
1
+ """hammad.http.client"""
2
2
 
3
3
  from __future__ import annotations
4
4
 
hammad/web/models.py CHANGED
@@ -6,7 +6,8 @@ Output models for web search and parsing functionality.
6
6
  from __future__ import annotations
7
7
 
8
8
  from typing import List, Dict, Any, Optional, Union
9
- from typing_extensions import TypedDict, NotRequired
9
+
10
+ from pydantic import BaseModel, Field
10
11
 
11
12
 
12
13
  # -----------------------------------------------------------------------------
@@ -14,7 +15,7 @@ from typing_extensions import TypedDict, NotRequired
14
15
  # -----------------------------------------------------------------------------
15
16
 
16
17
 
17
- class SearchResult(TypedDict):
18
+ class SearchResult(BaseModel):
18
19
  """DuckDuckGo web search result."""
19
20
 
20
21
  title: str
@@ -27,7 +28,7 @@ class SearchResult(TypedDict):
27
28
  """Description/snippet of the search result."""
28
29
 
29
30
 
30
- class NewsResult(TypedDict):
31
+ class NewsResult(BaseModel):
31
32
  """DuckDuckGo news search result."""
32
33
 
33
34
  date: str
@@ -54,7 +55,7 @@ class NewsResult(TypedDict):
54
55
  # -----------------------------------------------------------------------------
55
56
 
56
57
 
57
- class LinkInfo(TypedDict):
58
+ class LinkInfo(BaseModel):
58
59
  """Information about a link extracted from a web page."""
59
60
 
60
61
  href: str
@@ -64,7 +65,7 @@ class LinkInfo(TypedDict):
64
65
  """Text content of the link."""
65
66
 
66
67
 
67
- class ImageInfo(TypedDict):
68
+ class ImageInfo(BaseModel):
68
69
  """Information about an image extracted from a web page."""
69
70
 
70
71
  src: str
@@ -77,7 +78,7 @@ class ImageInfo(TypedDict):
77
78
  """Title attribute of the image."""
78
79
 
79
80
 
80
- class SelectedElement(TypedDict):
81
+ class SelectedElement(BaseModel):
81
82
  """Information about a selected element from CSS selector."""
82
83
 
83
84
  tag: str
@@ -93,7 +94,7 @@ class SelectedElement(TypedDict):
93
94
  """Attributes of the element."""
94
95
 
95
96
 
96
- class WebPageResult(TypedDict):
97
+ class WebPageResult(BaseModel):
97
98
  """Result from parsing a single web page."""
98
99
 
99
100
  url: str
@@ -121,7 +122,7 @@ class WebPageResult(TypedDict):
121
122
  """List of elements matching the CSS selector."""
122
123
 
123
124
 
124
- class WebPageErrorResult(TypedDict):
125
+ class WebPageErrorResult(BaseModel):
125
126
  """Result from a failed web page parsing attempt."""
126
127
 
127
128
  url: str
@@ -130,7 +131,7 @@ class WebPageErrorResult(TypedDict):
130
131
  error: str
131
132
  """Error message describing what went wrong."""
132
133
 
133
- status_code: None
134
+ status_code: Optional[int]
134
135
  """Always None for error results."""
135
136
 
136
137
  content_type: str
@@ -157,7 +158,7 @@ class WebPageErrorResult(TypedDict):
157
158
  # -----------------------------------------------------------------------------
158
159
 
159
160
 
160
- class ExtractedLink(TypedDict):
161
+ class ExtractedLink(BaseModel):
161
162
  """Information about a link extracted with classification."""
162
163
 
163
164
  href: str
@@ -181,7 +182,7 @@ class ExtractedLink(TypedDict):
181
182
  # -----------------------------------------------------------------------------
182
183
 
183
184
 
184
- class HttpResponse(TypedDict):
185
+ class HttpResponse(BaseModel):
185
186
  """HTTP response from web requests."""
186
187
 
187
188
  status_code: int
@@ -199,10 +200,14 @@ class HttpResponse(TypedDict):
199
200
  elapsed: float
200
201
  """Time elapsed for the request in seconds."""
201
202
 
202
- json: NotRequired[Optional[Dict[str, Any]]]
203
+ # NOTE: This is a workaround to avoid the issue with the `json` field
204
+ # might consider moving to dataclasses
205
+ json_data: Optional[Dict[str, Any]] = Field(
206
+ alias="json"
207
+ )
203
208
  """Parsed JSON content if Content-Type is JSON."""
204
209
 
205
- text: NotRequired[str]
210
+ text: str
206
211
  """Text content if response is text-based."""
207
212
 
208
213
 
@@ -211,17 +216,44 @@ class HttpResponse(TypedDict):
211
216
  # -----------------------------------------------------------------------------
212
217
 
213
218
 
214
- WebPageResults = List[Union[WebPageResult, WebPageErrorResult]]
215
- """Results from batch web page parsing operations."""
219
+ class WebPageResults(BaseModel):
220
+ """Results from batch web page parsing operations."""
221
+
222
+ urls: List[str]
223
+ """URLs used for the web page parsing operations."""
224
+
225
+ results: List[Union[WebPageResult, WebPageErrorResult]]
226
+ """List of results from batch web page parsing operations."""
227
+
228
+
229
+ class SearchResults(BaseModel):
230
+ """Results from web search operations."""
231
+
232
+ query: str
233
+ """Query used for the web search operations."""
216
234
 
217
- SearchResults = List[SearchResult]
218
- """Results from web search operations."""
235
+ results: List[SearchResult]
236
+ """List of results from web search operations."""
219
237
 
220
- NewsResults = List[NewsResult]
221
- """Results from news search operations."""
222
238
 
223
- ExtractedLinks = List[ExtractedLink]
224
- """Results from link extraction operations."""
239
+ class NewsResults(BaseModel):
240
+ """Results from news search operations."""
241
+
242
+ query: str
243
+ """Query used for the news search operations."""
244
+
245
+ results: List[NewsResult]
246
+ """List of results from news search operations."""
247
+
248
+
249
+ class ExtractedLinks(BaseModel):
250
+ """Results from link extraction operations."""
251
+
252
+ url: str
253
+ """URL used for the link extraction operations."""
254
+
255
+ results: List[ExtractedLink]
256
+ """List of results from link extraction operations."""
225
257
 
226
258
 
227
259
  __all__ = (