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.
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/PKG-INFO +2 -2
- aidial_adapter_anthropic-0.2.0rc0/aidial_adapter_anthropic/__init__.py +5 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/json.py +1 -1
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_base.py +1 -4
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/adapter.py +6 -7
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/blocks.py +20 -4
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/citations.py +4 -4
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/config.py +4 -2
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/state.py +2 -2
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_decorator/base.py +2 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_decorator/preprocess.py +2 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_decorator/replicator.py +1 -1
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_truncate_prompt.py +5 -2
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/_attachments.py +5 -6
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/consumer.py +3 -63
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/request.py +2 -5
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/resource.py +12 -12
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/storage.py +2 -1
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/pyproject.toml +11 -3
- aidial_adapter_anthropic-0.1.0rc0/aidial_adapter_anthropic/_utils/pydantic.py +0 -6
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/LICENSE +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/README.md +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/list.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/resource.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/_utils/text.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/__init__.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/converters.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/params.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/__init__.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/anthropic.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/approximate.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tokenizer/base.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_claude/tools.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_errors.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/_tokenize.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/adapter/claude.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/_lazy_stage.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/_message.py +0 -0
- {aidial_adapter_anthropic-0.1.0rc0 → aidial_adapter_anthropic-0.2.0rc0}/aidial_adapter_anthropic/dial/token_usage.py +0 -0
- {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.
|
|
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 (>=
|
|
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/
|
|
@@ -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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
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=
|
|
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
|
-
|
|
110
|
-
supported_types={
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
|
@@ -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
|
|
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
|
-
|
|
54
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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,
|
|
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 =
|
|
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
|
-
@
|
|
81
|
-
def
|
|
82
|
-
|
|
83
|
-
return
|
|
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
|
-
@
|
|
117
|
+
@field_validator("attachment", mode="before")
|
|
118
118
|
def parse_attachment(cls, value):
|
|
119
119
|
if isinstance(value, dict):
|
|
120
|
-
attachment = Attachment.
|
|
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
|
-
@
|
|
129
|
-
def
|
|
130
|
-
|
|
131
|
-
return
|
|
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
|
|
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.
|
|
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 (>=
|
|
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 = [
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|