aidial-adapter-anthropic 0.1.0rc0__tar.gz → 0.2.0rc0__tar.gz

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 (40) hide show
  1. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/PKG-INFO +2 -2
  2. aidial_adapter_anthropic-0.2.0rc0/aidial_adapter_anthropic/__init__.py +5 -0
  3. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/json.py +1 -1
  4. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_base.py +1 -4
  5. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/adapter.py +6 -7
  6. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/blocks.py +20 -4
  7. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/citations.py +4 -4
  8. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/config.py +4 -2
  9. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/state.py +2 -2
  10. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_decorator/base.py +2 -0
  11. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_decorator/preprocess.py +2 -0
  12. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_decorator/replicator.py +1 -1
  13. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_truncate_prompt.py +5 -2
  14. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/_attachments.py +5 -6
  15. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/consumer.py +3 -63
  16. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/request.py +2 -5
  17. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/resource.py +12 -12
  18. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/storage.py +2 -1
  19. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/pyproject.toml +11 -3
  20. aidial_adapter_anthropic-0.1.0rc0/aidial_adapter_anthropic/_utils/pydantic.py +0 -6
  21. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/LICENSE +0 -0
  22. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/README.md +0 -0
  23. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/list.py +0 -0
  24. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/resource.py +0 -0
  25. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/text.py +0 -0
  26. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/__init__.py +0 -0
  27. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/converters.py +0 -0
  28. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/params.py +0 -0
  29. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/__init__.py +0 -0
  30. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/anthropic.py +0 -0
  31. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/approximate.py +0 -0
  32. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/base.py +0 -0
  33. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tools.py +0 -0
  34. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_errors.py +0 -0
  35. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_tokenize.py +0 -0
  36. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/claude.py +0 -0
  37. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/_lazy_stage.py +0 -0
  38. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/_message.py +0 -0
  39. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/token_usage.py +0 -0
  40. {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: aidial-adapter-anthropic
3
- Version: 0.1.0rc0
3
+ Version: 0.2.0rc0
4
4
  Summary: Package implementing adapter from DIAL Chat Completions API to Anthropic API
5
5
  License: Apache-2.0
6
6
  Keywords: ai
@@ -12,7 +12,7 @@ Requires-Dist: aidial-sdk (>=0.28.0,<1)
12
12
  Requires-Dist: aiohttp (>=3.13.3,<4)
13
13
  Requires-Dist: anthropic (>=0.75.0,<1)
14
14
  Requires-Dist: pillow (>=10.4.0,<11)
15
- Requires-Dist: pydantic (>=1.10.17,<3)
15
+ Requires-Dist: pydantic (>=2.8.2,<3)
16
16
  Project-URL: Documentation, https://epam-rail.com/dial_api
17
17
  Project-URL: Homepage, https://epam-rail.com
18
18
  Project-URL: Repository, https://github.com/epam/ai-dial-adapter-anthropic/
@@ -0,0 +1,5 @@
1
+ import os
2
+ import warnings
3
+
4
+ if os.getenv("PYDANTIC_V2", "0").lower() not in ("1", "true"):
5
+ warnings.warn("PYDANTIC_V2 env variable is expected to be set to True")
@@ -57,7 +57,7 @@ def _to_dict(obj: Any, **kwargs) -> Any:
57
57
  return tuple(rec(element) for element in obj)
58
58
 
59
59
  if isinstance(obj, BaseModel):
60
- return rec(obj.dict())
60
+ return rec(obj.model_dump())
61
61
 
62
62
  if hasattr(obj, "to_dict"):
63
63
  return rec(obj.to_dict())
@@ -15,10 +15,7 @@ from aidial_adapter_anthropic.dial.request import (
15
15
  )
16
16
 
17
17
 
18
- class ChatCompletionAdapter(ABC, BaseModel):
19
- class Config:
20
- arbitrary_types_allowed = True
21
-
18
+ class ChatCompletionAdapter(ABC):
22
19
  @abstractmethod
23
20
  async def chat(
24
21
  self,
@@ -88,7 +88,7 @@ from aidial_adapter_anthropic.adapter._base import (
88
88
  from aidial_adapter_anthropic.adapter._claude.blocks import (
89
89
  IMAGE_ATTACHMENT_PROCESSOR,
90
90
  PDF_ATTACHMENT_PROCESSOR,
91
- TEXT_ATTACHMENT_PROCESSOR,
91
+ PLAIN_TEXT_ATTACHMENT_PROCESSOR,
92
92
  create_text_block,
93
93
  )
94
94
  from aidial_adapter_anthropic.adapter._claude.citations import create_citations
@@ -210,6 +210,7 @@ async def create_adapter(
210
210
  )(model)
211
211
 
212
212
 
213
+ @dataclass
213
214
  class Adapter(ChatCompletionAdapter):
214
215
  deployment: str
215
216
  storage: Optional[FileStorage]
@@ -227,7 +228,7 @@ class Adapter(ChatCompletionAdapter):
227
228
  def attachment_processors(self) -> AttachmentProcessors:
228
229
  # Document support: https://docs.anthropic.com/en/docs/build-with-claude/pdf-support#supported-platforms-and-models
229
230
  document_processors = (
230
- [PDF_ATTACHMENT_PROCESSOR, TEXT_ATTACHMENT_PROCESSOR]
231
+ [PDF_ATTACHMENT_PROCESSOR, PLAIN_TEXT_ATTACHMENT_PROCESSOR]
231
232
  if self.supports_documents
232
233
  else []
233
234
  )
@@ -426,10 +427,8 @@ class Adapter(ChatCompletionAdapter):
426
427
  case TextBlock(citations=citations):
427
428
  # The text content is already handled in TextEvent handler.
428
429
  for citation in citations or []:
429
- await create_citations(
430
- consumer,
431
- request.get_resource,
432
- citation,
430
+ create_citations(
431
+ consumer, request.get_resource, citation
433
432
  )
434
433
  case ToolUseBlock():
435
434
  # Tool Use is processed in ContentBlockStartEvent and InputJsonEvent handlers
@@ -508,7 +507,7 @@ class Adapter(ChatCompletionAdapter):
508
507
  case TextBlock(text=text, citations=citations):
509
508
  consumer.append_content(text)
510
509
  for citation in citations or []:
511
- await create_citations(
510
+ create_citations(
512
511
  consumer, request.get_resource, citation
513
512
  )
514
513
  case ToolUseBlock():
@@ -50,7 +50,7 @@ def create_text_document_block(
50
50
  return RequestDocumentBlockParam(
51
51
  source=PlainTextSourceParam(
52
52
  data=resource.data.decode("utf-8"),
53
- media_type=resource.type, # type: ignore
53
+ media_type="text/plain",
54
54
  type="text",
55
55
  ),
56
56
  type="document",
@@ -64,7 +64,7 @@ def create_pdf_document_block(
64
64
  return RequestDocumentBlockParam(
65
65
  source=Base64PDFSourceParam(
66
66
  data=resource.data_base64,
67
- media_type=resource.type, # type: ignore
67
+ media_type="application/pdf",
68
68
  type="base64",
69
69
  ),
70
70
  type="document",
@@ -106,7 +106,23 @@ PDF_ATTACHMENT_PROCESSOR = AttachmentProcessor(
106
106
  handler=create_pdf_document_block,
107
107
  )
108
108
 
109
- TEXT_ATTACHMENT_PROCESSOR = AttachmentProcessor(
110
- supported_types={"text/plain": {"txt"}},
109
+ PLAIN_TEXT_ATTACHMENT_PROCESSOR = AttachmentProcessor(
110
+ supported_types={
111
+ "text/plain": {"txt"},
112
+ "text/html": {"html", "htm"},
113
+ "text/css": {"css"},
114
+ "text/javascript": {"js"},
115
+ "application/x-javascript": {"js"},
116
+ "text/x-typescript": {"ts"},
117
+ "application/x-typescript": {"ts"},
118
+ "text/csv": {"csv"},
119
+ "text/markdown": {"md"},
120
+ "text/x-python": {"py"},
121
+ "application/x-python-code": {"py"},
122
+ "application/json": {"json"},
123
+ "text/xml": {"xml"},
124
+ "application/rtf": {"rtf"},
125
+ "text/rtf": {"rtf"},
126
+ },
111
127
  handler=create_text_document_block,
112
128
  )
@@ -21,7 +21,7 @@ from aidial_adapter_anthropic.dial.consumer import Consumer
21
21
  from aidial_adapter_anthropic.dial.resource import DialResource
22
22
 
23
23
 
24
- async def _add_document_citation(
24
+ def _add_document_citation(
25
25
  consumer: Consumer,
26
26
  get_document: Callable[[int], DialResource | None],
27
27
  document_index: int,
@@ -31,7 +31,7 @@ async def _add_document_citation(
31
31
 
32
32
  # NOTE: multiple citations to the same document are merged into one citation
33
33
  # until we find a better API to handle citations embedded in text.
34
- display_index = await consumer.add_citation_attachment(
34
+ display_index = consumer.add_citation_attachment(
35
35
  document_id=document_index, document=document
36
36
  )
37
37
 
@@ -40,7 +40,7 @@ async def _add_document_citation(
40
40
  consumer.append_content(f"[{display_index}]")
41
41
 
42
42
 
43
- async def create_citations(
43
+ def create_citations(
44
44
  consumer: Consumer,
45
45
  get_document: Callable[[int], DialResource | None],
46
46
  citation: TextCitation,
@@ -49,7 +49,7 @@ async def create_citations(
49
49
  case CitationCharLocation(
50
50
  document_index=document_index
51
51
  ) | CitationPageLocation(document_index=document_index):
52
- await _add_document_citation(consumer, get_document, document_index)
52
+ _add_document_citation(consumer, get_document, document_index)
53
53
 
54
54
  # Custom document aren't supported yet
55
55
  case CitationContentBlockLocation():
@@ -2,9 +2,11 @@ from typing import List, Literal
2
2
 
3
3
  from anthropic.types.anthropic_beta_param import AnthropicBetaParam
4
4
  from anthropic.types.beta import BetaThinkingConfigParam as ThinkingConfigParam
5
- from pydantic import Field
5
+ from pydantic import BaseModel, ConfigDict, Field
6
6
 
7
- from aidial_adapter_anthropic._utils.pydantic import ExtraForbidModel
7
+
8
+ class ExtraForbidModel(BaseModel):
9
+ model_config = ConfigDict(extra="forbid")
8
10
 
9
11
 
10
12
  class ThinkingConfigEnabled(ExtraForbidModel):
@@ -21,7 +21,7 @@ class MessageState(BaseModel):
21
21
  claude_message_content: List[ParsedContentBlock] | List[ContentBlock]
22
22
 
23
23
  def to_dict(self) -> dict:
24
- return self.dict(
24
+ return self.model_dump(
25
25
  # FIXME: a hack to exclude the private __json_buf field
26
26
  exclude={"claude_message_content": {"__all__": {"__json_buf"}}},
27
27
  # Excluding `citations: null`, since they could not be even parsed
@@ -35,7 +35,7 @@ def get_message_content_from_state(
35
35
  ) -> List[ContentBlockParam] | None:
36
36
  if (cc := message.custom_content) and (state_dict := cc.state):
37
37
  try:
38
- state = MessageState.parse_obj(state_dict)
38
+ state = MessageState.model_validate(state_dict)
39
39
  return [block.to_dict() for block in state.claude_message_content] # type: ignore
40
40
  except pydantic.ValidationError as e:
41
41
  _log.error(
@@ -1,3 +1,4 @@
1
+ from dataclasses import dataclass
1
2
  from typing import Callable, List
2
3
 
3
4
  from aidial_sdk.chat_completion import Message
@@ -9,6 +10,7 @@ from aidial_adapter_anthropic.dial.consumer import Consumer
9
10
  from aidial_adapter_anthropic.dial.request import ModelParameters
10
11
 
11
12
 
13
+ @dataclass
12
14
  class ChatCompletionDecorator(ChatCompletionAdapter):
13
15
  adapter: ChatCompletionAdapter
14
16
 
@@ -1,3 +1,4 @@
1
+ from dataclasses import dataclass
1
2
  from typing import Callable, List
2
3
 
3
4
  from aidial_sdk.chat_completion import Message
@@ -20,6 +21,7 @@ def preprocess_messages_decorator(
20
21
  )
21
22
 
22
23
 
24
+ @dataclass
23
25
  class PreprocessMessagesDecorator(ChatCompletionDecorator):
24
26
  on_messages: Callable[[List[Message]], ListProjection[Message]]
25
27
 
@@ -22,7 +22,7 @@ class ReplicatorDecorator(ChatCompletionDecorator):
22
22
  params: ModelParameters,
23
23
  messages: List[Message],
24
24
  ) -> None:
25
- params1 = params.copy()
25
+ params1 = params.model_copy()
26
26
  params1.n = 1
27
27
 
28
28
  async def _chat(root_consumer: Consumer):
@@ -1,4 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass
2
3
  from typing import Awaitable, Callable, List, Optional, Set, Tuple, TypeVar
3
4
 
4
5
  from aidial_sdk.exceptions import ContextLengthExceededError
@@ -7,7 +8,6 @@ from aidial_sdk.exceptions import (
7
8
  InvalidRequestError,
8
9
  TruncatePromptSystemAndLastUserError,
9
10
  )
10
- from pydantic import BaseModel
11
11
 
12
12
  from aidial_adapter_anthropic._utils.list import (
13
13
  omit_by_indices,
@@ -15,7 +15,7 @@ from aidial_adapter_anthropic._utils.list import (
15
15
  )
16
16
 
17
17
 
18
- class TruncatePromptError(ABC, BaseModel):
18
+ class TruncatePromptError(ABC):
19
19
  @abstractmethod
20
20
  def to_dial_exception(self) -> DialException:
21
21
  pass
@@ -24,6 +24,7 @@ class TruncatePromptError(ABC, BaseModel):
24
24
  return self.to_dial_exception().message
25
25
 
26
26
 
27
+ @dataclass
27
28
  class InconsistentLimitsError(TruncatePromptError):
28
29
  user_limit: int
29
30
  model_limit: int
@@ -35,6 +36,7 @@ class InconsistentLimitsError(TruncatePromptError):
35
36
  )
36
37
 
37
38
 
39
+ @dataclass
38
40
  class ModelLimitOverflow(TruncatePromptError):
39
41
  model_limit: int
40
42
  token_count: int
@@ -43,6 +45,7 @@ class ModelLimitOverflow(TruncatePromptError):
43
45
  return ContextLengthExceededError(self.model_limit, self.token_count)
44
46
 
45
47
 
48
+ @dataclass
46
49
  class UserLimitOverflow(TruncatePromptError):
47
50
  user_limit: int
48
51
  token_count: int
@@ -50,10 +50,8 @@ class HandlerWithConfig(Protocol, Generic[_T, _Config]):
50
50
  def __call__(self, resource: Resource, config: _Config | None) -> _T: ...
51
51
 
52
52
 
53
- class AttachmentProcessor(BaseModel, Generic[_T, _Config]):
54
- class Config:
55
- arbitrary_types_allowed = True
56
-
53
+ @dataclass
54
+ class AttachmentProcessor(Generic[_T, _Config]):
57
55
  supported_types: Dict[str, Set[str]]
58
56
  """MIME type to file extensions mapping"""
59
57
 
@@ -89,11 +87,12 @@ class WithResources(Generic[_T]):
89
87
  return WithResources(payload=payload, resources=resources)
90
88
 
91
89
 
92
- class AttachmentProcessors(BaseModel, Generic[_Txt, _T, _Config]):
93
- config: _Config | None = None
90
+ @dataclass
91
+ class AttachmentProcessors(Generic[_Txt, _T, _Config]):
94
92
  attachment_processors: Sequence[AttachmentProcessor[_T, _Config]]
95
93
  text_handler: Callable[[str], _Txt]
96
94
  file_storage: FileStorage | None
95
+ config: _Config | None = field(default=None)
97
96
 
98
97
  @property
99
98
  def supported_types(self) -> Dict[str, Set[str]]:
@@ -57,7 +57,7 @@ class Consumer(ContextManager, ABC):
57
57
  def add_attachment(self, attachment: Attachment): ...
58
58
 
59
59
  @abstractmethod
60
- async def add_citation_attachment(
60
+ def add_citation_attachment(
61
61
  self, document_id: int, document: Attachment | None
62
62
  ) -> int: ...
63
63
 
@@ -169,7 +169,7 @@ class ChoiceConsumer(Consumer):
169
169
  def add_attachment(self, attachment: Attachment):
170
170
  self.choice.add_attachment(attachment)
171
171
 
172
- async def add_citation_attachment(
172
+ def add_citation_attachment(
173
173
  self, document_id: int, document: Attachment | None
174
174
  ) -> int:
175
175
  if document_id in self._citations:
@@ -179,7 +179,7 @@ class ChoiceConsumer(Consumer):
179
179
  self._citations[document_id] = (display_index, document)
180
180
 
181
181
  if document:
182
- document = document.copy()
182
+ document = document.model_copy()
183
183
  document.title = f"[{display_index}] {document.title or ''}".strip()
184
184
  document.reference_type = document.reference_type or document.type
185
185
  document.reference_url = document.reference_url or document.url
@@ -233,63 +233,3 @@ class ChoiceConsumer(Consumer):
233
233
  @property
234
234
  def has_function_call(self) -> bool:
235
235
  return self._choice is not None and self._choice.has_function_call
236
-
237
-
238
- class ConsumerDecorator(Consumer):
239
- consumer: Consumer
240
-
241
- def __init__(self, consumer: Consumer):
242
- self.consumer = consumer
243
-
244
- def __enter__(self) -> Consumer:
245
- return self.consumer.__enter__()
246
-
247
- def __exit__(
248
- self,
249
- exc_type: type[BaseException] | None,
250
- exc: BaseException | None,
251
- traceback: TracebackType | None,
252
- ) -> bool | None:
253
- return self.consumer.__exit__(exc_type, exc, traceback)
254
-
255
- def fork(self) -> Consumer:
256
- return self.consumer.fork()
257
-
258
- @property
259
- def choice(self) -> Choice:
260
- return self.consumer.choice
261
-
262
- def close_content(self, finish_reason: FinishReason | None = None):
263
- self.consumer.close_content(finish_reason)
264
-
265
- def append_content(self, content: str):
266
- self.consumer.append_content(content)
267
-
268
- def add_attachment(self, attachment: Attachment):
269
- self.consumer.add_attachment(attachment)
270
-
271
- async def add_citation_attachment(self, document_id, document):
272
- return await self.consumer.add_citation_attachment(
273
- document_id, document
274
- )
275
-
276
- def add_usage(self, usage: TokenUsage):
277
- self.consumer.add_usage(usage)
278
-
279
- def set_discarded_messages(
280
- self, discarded_messages: Optional[DiscardedMessages]
281
- ):
282
- self.consumer.set_discarded_messages(discarded_messages)
283
-
284
- def get_discarded_messages(self) -> Optional[DiscardedMessages]:
285
- return self.consumer.get_discarded_messages()
286
-
287
- def create_function_tool_call(self, call: ToolCall) -> ToolUseMessage:
288
- return self.consumer.create_function_tool_call(call)
289
-
290
- def create_function_call(self, call: FunctionCall) -> ToolUseMessage:
291
- return self.consumer.create_function_call(call)
292
-
293
- @property
294
- def has_function_call(self) -> bool:
295
- return self.consumer.has_function_call
@@ -20,7 +20,7 @@ from aidial_sdk.chat_completion.request import (
20
20
  )
21
21
  from aidial_sdk.exceptions import RequestValidationError
22
22
  from pydantic import BaseModel
23
- from pydantic.v1 import ValidationError as PydanticValidationError
23
+ from pydantic import ValidationError as PydanticValidationError
24
24
 
25
25
  from aidial_adapter_anthropic.adapter._errors import ValidationError
26
26
  from aidial_adapter_anthropic.dial.tools import (
@@ -82,9 +82,6 @@ class ModelParameters(BaseModel):
82
82
  configuration=configuration,
83
83
  )
84
84
 
85
- def add_stop_sequences(self, stop: List[str]) -> "ModelParameters":
86
- return self.copy(update={"stop": [*self.stop, *stop]})
87
-
88
85
  @property
89
86
  def tools_mode(self) -> ToolsMode | None:
90
87
  if self.tool_config is not None:
@@ -93,7 +90,7 @@ class ModelParameters(BaseModel):
93
90
 
94
91
  def parse_configuration(self, cls: Type[_Model]) -> _Model:
95
92
  try:
96
- return cls.parse_obj(self.configuration or {})
93
+ return cls.model_validate(self.configuration or {})
97
94
  except PydanticValidationError as e:
98
95
  if self.configuration is None:
99
96
  msg = "The configuration at path 'custom_fields.configuration' is missing."
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
4
4
  from typing import List
5
5
 
6
6
  from aidial_sdk.chat_completion import Attachment
7
- from pydantic import BaseModel, Field, root_validator, validator
7
+ from pydantic import BaseModel, Field, field_validator, model_validator
8
8
 
9
9
  from aidial_adapter_anthropic._utils.resource import Resource
10
10
  from aidial_adapter_anthropic._utils.text import truncate_string
@@ -34,7 +34,7 @@ class UnsupportedContentType(ValidationError):
34
34
 
35
35
 
36
36
  class DialResource(ABC, BaseModel):
37
- entity_name: str = Field(default=None)
37
+ entity_name: str | None = None
38
38
  supported_types: List[str] | None = Field(default=None)
39
39
 
40
40
  @abstractmethod
@@ -77,10 +77,10 @@ class URLResource(DialResource):
77
77
  def to_attachment(self) -> Attachment:
78
78
  return Attachment(type=self.content_type, url=self.url)
79
79
 
80
- @root_validator
81
- def validator(cls, values):
82
- values["entity_name"] = values.get("entity_name") or "URL"
83
- return values
80
+ @model_validator(mode="after")
81
+ def default_entity_name(self):
82
+ self.entity_name = self.entity_name or "URL"
83
+ return self
84
84
 
85
85
  async def download(self, storage: FileStorage | None) -> Resource:
86
86
  type = await self.get_content_type()
@@ -114,10 +114,10 @@ class AttachmentResource(DialResource):
114
114
  def to_attachment(self) -> Attachment:
115
115
  return self.attachment
116
116
 
117
- @validator("attachment", pre=True)
117
+ @field_validator("attachment", mode="before")
118
118
  def parse_attachment(cls, value):
119
119
  if isinstance(value, dict):
120
- attachment = Attachment.parse_obj(value)
120
+ attachment = Attachment.model_validate(value)
121
121
  # Working around the issue of defaulting missing type to a markdown:
122
122
  # https://github.com/epam/ai-dial-sdk/blob/2835107e950c89645a2b619fecba2518fa2d7bb1/aidial_sdk/chat_completion/request.py#L22
123
123
  if "type" not in value:
@@ -125,10 +125,10 @@ class AttachmentResource(DialResource):
125
125
  return attachment
126
126
  return value
127
127
 
128
- @root_validator(pre=True)
129
- def validator(cls, values):
130
- values["entity_name"] = values.get("entity_name") or "attachment"
131
- return values
128
+ @model_validator(mode="after")
129
+ def default_entity_name(self):
130
+ self.entity_name = self.entity_name or "attachment"
131
+ return self
132
132
 
133
133
  async def download(self, storage: FileStorage | None) -> Resource:
134
134
  type = await self.get_content_type()
@@ -3,11 +3,12 @@ import hashlib
3
3
  import io
4
4
  import logging
5
5
  import mimetypes
6
- from typing import Mapping, Optional, TypedDict
6
+ from typing import Mapping, Optional
7
7
  from urllib.parse import unquote, urljoin
8
8
 
9
9
  import aiohttp
10
10
  from pydantic import BaseModel
11
+ from typing_extensions import TypedDict
11
12
 
12
13
  _log = logging.getLogger(__name__)
13
14
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aidial-adapter-anthropic"
3
- version = "0.1.0rc"
3
+ version = "0.2.0rc"
4
4
  description = "Package implementing adapter from DIAL Chat Completions API to Anthropic API"
5
5
  authors = [{ name = "EPAM RAIL", email = "SpecialEPM-DIALDevTeam@epam.com" }]
6
6
  license = "Apache-2.0"
@@ -11,7 +11,7 @@ requires-python = ">=3.11,<4.0"
11
11
  dependencies = [
12
12
  "aidial-sdk (>=0.28.0,<1)",
13
13
  "anthropic (>=0.75.0,<1)",
14
- "pydantic (>=1.10.17,<3)",
14
+ "pydantic (>=2.8.2,<3)",
15
15
  "pillow (>=10.4.0,<11)",
16
16
  "aiohttp (>=3.13.3,<4)",
17
17
  ]
@@ -47,7 +47,15 @@ addopts = "-n=auto --asyncio-mode=auto --self-contained-html --html=pytest.html
47
47
  generate_report_on_test = true
48
48
  env_override_existing_values = 1
49
49
  testpaths = ["tests"]
50
- filterwarnings = ["error"]
50
+ filterwarnings = [
51
+ "error",
52
+ # "ignore::pydantic.warnings.PydanticDeprecatedSince20",
53
+ # "ignore::pytest.PytestUnraisableExceptionWarning",
54
+ # muting warnings coming from opentelemetry and pkg_resources packages
55
+ # "ignore::DeprecationWarning:opentelemetry.instrumentation.dependencies",
56
+ # "ignore::DeprecationWarning:pkg_resources",
57
+
58
+ ]
51
59
 
52
60
  [tool.pyright]
53
61
  typeCheckingMode = "basic"
@@ -1,6 +0,0 @@
1
- from pydantic import BaseModel
2
-
3
-
4
- class ExtraForbidModel(BaseModel):
5
- class Config:
6
- extra = "forbid"