Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ repos:
rev: v2.1.0
hooks:
- id: codespell
args: ["--skip=*.ipynb,*.json,*.jsonlines"]
args: ["--skip=*.ipynb,*.json,*.jsonlines,*.yaml"]

- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0
Expand Down
9 changes: 9 additions & 0 deletions src/yandex_cloud_ml_sdk/_chat/completions/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ChatFunctionResultMessageDict(TypedDict):
ChatMessageInputType = Union[ChatCompletionsMessageType, Iterable[ChatCompletionsMessageType]]


# pylint: disable-next=too-many-return-statements
def message_to_json(message: ChatCompletionsMessageType, tool_name_ids: dict[str, str]) -> JsonObject | list[JsonObject]:
if isinstance(message, str):
return {'role': 'user', 'content': message}
Expand Down Expand Up @@ -56,6 +57,14 @@ def message_to_json(message: ChatCompletionsMessageType, tool_name_ids: dict[str
'tool_call_id': tool_call_id,
}

if tool_calls := message.get('tool_calls'):
tool_calls = cast(JsonObject, tool_calls)
role = message.get('role', 'assistant')
return {
'tool_calls': tool_calls,
'role': role,
}

if text:
message = cast(TextMessageDict, message)
role = message.get('role', 'user')
Expand Down
1 change: 0 additions & 1 deletion src/yandex_cloud_ml_sdk/_chat/completions/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ def _build_request_json(self, messages: ChatMessageInputType, stream: bool) -> d

if c.tool_choice is not None:
result['tool_choice'] = coerce_tool_choice_to_json(c.tool_choice)

return result

@override
Expand Down
2 changes: 1 addition & 1 deletion test_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ certifi
data-science-types
googleapis-common-protos-stubs
grpc-stubs
mypy!=1.17.0,!=1.17.1
mypy!=1.17.0,!=1.17.1,!=1.18.0,!=1.18.1
psutil
pyarrow-stubs
pydantic<2.10
Expand Down
Empty file added tests/chat/__init__.py
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
interactions:
- request:
body: '{"model":"gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest","messages":[{"role":"user","content":"doesn''t
matter"}],"stream":false,"tools":[{"function":{"name":"something","description":"Tool
which have to collect all the numbers from user message and do a SOMETHING with
it","parameters":{"properties":{"numbers":{"items":{"type":"integer"},"title":"Numbers","type":"array"}},"required":["numbers"],"title":"Numbers","type":"object"},"strict":null},"type":"function"}],"tool_choice":"foo"}'
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
authorization:
- Bearer t1.9euelZqOl8_MysaajJLNx5uQipTHmO3rnpWalM3InMbJl5qUmJnHmcfPzsnl8_cpaXQ5-e94QTBB_d3z92kXcjn573hBMEH9zef1656VmpyJzpyOzMbLncfGnJDNnJWe7_zF656VmpyJzpyOzMbLncfGnJDNnJWeveuelZqZio7GyJCbiY-KzJCVyZuMzrXrhpzRlp6S0ZCPmpGWm9KMmo2Jmo0.5Xf19Ehbay0iZuIm7eBBIf1wntPWuIc_CpGJBkkREyU2J0hL3Uavgu1L5_K3WUTKWDfgYUpGCkZxZA-NV1ZCDQ
connection:
- keep-alive
content-length:
- '485'
content-type:
- application/json
host:
- llm.api.cloud.yandex.net
user-agent:
- yandex-cloud-ml-sdk/0.15.0 python/3.12
x-client-request-id:
- e0ed5418-d8a0-400f-8826-4de630914f3d
method: POST
uri: https://llm.api.cloud.yandex.net/v1/chat/completions
response:
body:
string: '{"error":{"message":"invalid tool choice: foo","type":"invalid_request_error"}}

'
headers:
content-length:
- '80'
content-type:
- application/json
date:
- Thu, 11 Sep 2025 13:35:47 GMT
server:
- ycalb
x-client-request-id:
- e0ed5418-d8a0-400f-8826-4de630914f3d
x-request-id:
- 959ab37f-b3d9-4689-aba2-8b24fe5fe219
x-server-trace-id:
- 8715238fd9c10677:c2f06193888bfc9e:8715238fd9c10677:1
status:
code: 400
message: Bad Request
version: 1
137 changes: 137 additions & 0 deletions tests/chat/cassettes/test_completions/test_chat.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
interactions:
- request:
body: '{"model":"gpt://b1ghsjum2v37c2un8h64/qwen3-235b-a22b-fp8/latest","messages":[{"content":"Your
name is Arkadiy","role":"system"},{"role":"user","content":"Hello! how is your
name?"}],"stream":false}'
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
authorization:
- Bearer t1.9euelZqWlp2bxpiUmZuLl57Lz8yMjO3rnpWalM3InMbJl5qUmJnHmcfPzsnl8_cXWF85-e9wPgBV_t3z91cGXTn573A-AFX-zef1656VmpHMi8vNmY2YjI_OjpWYncaM7_zF656VmpHMi8vNmY2YjI_OjpWYncaMveuelZrHy5fHis2MjY-dzIyJnJXIkrXrhpzRlp6S0ZCPmpGWm9KMmo2Jmo0.G0eyVx1OQ_yLFHLGkNV9gUPu64rm0aIT2-Hdbo-LGa5pwM7KetKWhD9ZTXg-Sg6L6CH_kW8Ay1LzAaQON5OfAw
connection:
- keep-alive
content-length:
- '197'
content-type:
- application/json
host:
- llm.api.cloud.yandex.net
user-agent:
- yandex-cloud-ml-sdk/0.15.0 python/3.12
x-client-request-id:
- 5a3fcf89-bb93-4e61-9379-61227d23bd28
method: POST
uri: https://llm.api.cloud.yandex.net/v1/chat/completions
response:
body:
string: "{\"id\":\"chatcmpl-2ee9e39e-6ceb-4c70-93e1-a29034b09534\",\"object\":\"chat.completion\",\"created\":1757951686,\"model\":\"gpt://qwen3-235b-a22b-fp8/latest\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"Hello!
My name is Arkadiy. How can I assist you today? \U0001F60A\"},\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":26,\"total_tokens\":45,\"completion_tokens\":19}}\n"
headers:
content-length:
- '366'
content-type:
- application/json
date:
- Mon, 15 Sep 2025 15:54:46 GMT
server:
- ycalb
x-server-trace-id:
- a2fbc7955280d426:7d558323c079506f:a2fbc7955280d426:1
status:
code: 200
message: OK
- request:
body: "{\"model\":\"gpt://b1ghsjum2v37c2un8h64/qwen3-235b-a22b-fp8/latest\",\"messages\":[{\"content\":\"Your
name is Arkadiy\",\"role\":\"system\"},{\"role\":\"user\",\"content\":\"Hello!
how is your name?\"},{\"content\":\"Hello! My name is Arkadiy. How can I assist
you today? \U0001F60A\",\"role\":\"assistant\"},{\"role\":\"user\",\"content\":\"My
name is Andrew\"}],\"stream\":false}"
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
authorization:
- Bearer t1.9euelZqWlp2bxpiUmZuLl57Lz8yMjO3rnpWalM3InMbJl5qUmJnHmcfPzsnl8_cXWF85-e9wPgBV_t3z91cGXTn573A-AFX-zef1656VmpHMi8vNmY2YjI_OjpWYncaM7_zF656VmpHMi8vNmY2YjI_OjpWYncaMveuelZrHy5fHis2MjY-dzIyJnJXIkrXrhpzRlp6S0ZCPmpGWm9KMmo2Jmo0.G0eyVx1OQ_yLFHLGkNV9gUPu64rm0aIT2-Hdbo-LGa5pwM7KetKWhD9ZTXg-Sg6L6CH_kW8Ay1LzAaQON5OfAw
connection:
- keep-alive
content-length:
- '336'
content-type:
- application/json
host:
- llm.api.cloud.yandex.net
user-agent:
- yandex-cloud-ml-sdk/0.15.0 python/3.12
x-client-request-id:
- 24ae7c12-ca25-4764-9b37-d3848f67cd81
method: POST
uri: https://llm.api.cloud.yandex.net/v1/chat/completions
response:
body:
string: "{\"id\":\"chatcmpl-26c17979-ed03-414d-b613-6a2a5bc7ba03\",\"object\":\"chat.completion\",\"created\":1757951686,\"model\":\"gpt://qwen3-235b-a22b-fp8/latest\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"Nice
to meet you, Andrew! \U0001F60A How can I help you today?\"},\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":58,\"total_tokens\":75,\"completion_tokens\":17}}\n"
headers:
content-length:
- '363'
content-type:
- application/json
date:
- Mon, 15 Sep 2025 15:54:46 GMT
server:
- ycalb
x-server-trace-id:
- 73cf81250d9fc777:1cd7ffa5c15e8f0:73cf81250d9fc777:1
status:
code: 200
message: OK
- request:
body: "{\"model\":\"gpt://b1ghsjum2v37c2un8h64/qwen3-235b-a22b-fp8/latest\",\"messages\":[{\"content\":\"Your
name is Arkadiy\",\"role\":\"system\"},{\"role\":\"user\",\"content\":\"Hello!
how is your name?\"},{\"content\":\"Hello! My name is Arkadiy. How can I assist
you today? \U0001F60A\",\"role\":\"assistant\"},{\"role\":\"user\",\"content\":\"My
name is Andrew\"},{\"content\":\"Nice to meet you, Andrew! \U0001F60A How can
I help you today?\",\"role\":\"assistant\"},{\"role\":\"user\",\"content\":\"What
is my name?\"}],\"stream\":false}"
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
authorization:
- Bearer t1.9euelZqWlp2bxpiUmZuLl57Lz8yMjO3rnpWalM3InMbJl5qUmJnHmcfPzsnl8_cXWF85-e9wPgBV_t3z91cGXTn573A-AFX-zef1656VmpHMi8vNmY2YjI_OjpWYncaM7_zF656VmpHMi8vNmY2YjI_OjpWYncaMveuelZrHy5fHis2MjY-dzIyJnJXIkrXrhpzRlp6S0ZCPmpGWm9KMmo2Jmo0.G0eyVx1OQ_yLFHLGkNV9gUPu64rm0aIT2-Hdbo-LGa5pwM7KetKWhD9ZTXg-Sg6L6CH_kW8Ay1LzAaQON5OfAw
connection:
- keep-alive
content-length:
- '471'
content-type:
- application/json
host:
- llm.api.cloud.yandex.net
user-agent:
- yandex-cloud-ml-sdk/0.15.0 python/3.12
x-client-request-id:
- d26dea55-8f0c-4f20-a771-ac77db321a2b
method: POST
uri: https://llm.api.cloud.yandex.net/v1/chat/completions
response:
body:
string: "{\"id\":\"chatcmpl-985ce6ba-8160-4c52-b6c7-466c9e470bf5\",\"object\":\"chat.completion\",\"created\":1757951687,\"model\":\"gpt://qwen3-235b-a22b-fp8/latest\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"Your
name is Andrew! \U0001F60A\"},\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":89,\"total_tokens\":97,\"completion_tokens\":8}}\n"
headers:
content-length:
- '331'
content-type:
- application/json
date:
- Mon, 15 Sep 2025 15:54:47 GMT
server:
- ycalb
x-server-trace-id:
- 3f621a2346607f53:8798599acd908a22:3f621a2346607f53:1
status:
code: 200
message: OK
version: 1
102 changes: 102 additions & 0 deletions tests/chat/cassettes/test_completions/test_function_call.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
interactions:
- request:
body: '{"model":"gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest","messages":[{"role":"user","content":"do
a SOMETHING with all the numbers from: 5, 4, a, 1"}],"stream":false,"tools":[{"function":{"name":"something","description":"Tool
which have to collect all the numbers from user message and do a SOMETHING with
it","parameters":{"properties":{"numbers":{"items":{"type":"integer"},"title":"Numbers","type":"array"}},"required":["numbers"],"title":"Numbers","type":"object"},"strict":null},"type":"function"}]}'
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
authorization:
- Bearer t1.9euelZqWlp2bxpiUmZuLl57Lz8yMjO3rnpWalM3InMbJl5qUmJnHmcfPzsnl8_cXWF85-e9wPgBV_t3z91cGXTn573A-AFX-zef1656VmpHMi8vNmY2YjI_OjpWYncaM7_zF656VmpHMi8vNmY2YjI_OjpWYncaMveuelZrHy5fHis2MjY-dzIyJnJXIkrXrhpzRlp6S0ZCPmpGWm9KMmo2Jmo0.G0eyVx1OQ_yLFHLGkNV9gUPu64rm0aIT2-Hdbo-LGa5pwM7KetKWhD9ZTXg-Sg6L6CH_kW8Ay1LzAaQON5OfAw
connection:
- keep-alive
content-length:
- '503'
content-type:
- application/json
host:
- llm.api.cloud.yandex.net
user-agent:
- yandex-cloud-ml-sdk/0.15.0 python/3.12
x-client-request-id:
- 0567acea-6d36-43fd-a9fe-8413785acbb9
method: POST
uri: https://llm.api.cloud.yandex.net/v1/chat/completions
response:
body:
string: '{"id":"d5ef1f8c-652e-4c53-ada8-6d748b5808b6","object":"chat.completion","created":1757951688,"model":"gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest","choices":[{"index":0,"message":{"role":"assistant","content":"","tool_calls":[{"index":0,"id":"something","type":"function","function":{"name":"something","arguments":"{\"numbers\":[5,4,1]}"}}]},"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":100,"total_tokens":114,"completion_tokens":14}}

'
headers:
content-length:
- '447'
content-type:
- application/json
date:
- Mon, 15 Sep 2025 15:54:48 GMT
server:
- ycalb
x-client-request-id:
- 0567acea-6d36-43fd-a9fe-8413785acbb9
x-request-id:
- 5255a16b-e5e7-4acd-943a-30c79cb11050
x-server-trace-id:
- 124a38f19dd92e4f:503d1158efd4e39:124a38f19dd92e4f:1
status:
code: 200
message: OK
- request:
body: '{"model":"gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest","messages":[{"role":"user","content":"do
a SOMETHING with all the numbers from: 5, 4, a, 1"},{"role":"assistant","tool_calls":[{"index":0,"id":"something","type":"function","function":{"name":"something","arguments":"{\"numbers\":[5,4,1]}"}}]},{"role":"tool","content":"+20.0","tool_call_id":"something"}],"stream":false,"tools":[{"function":{"name":"something","description":"Tool
which have to collect all the numbers from user message and do a SOMETHING with
it","parameters":{"properties":{"numbers":{"items":{"type":"integer"},"title":"Numbers","type":"array"}},"required":["numbers"],"title":"Numbers","type":"object"},"strict":null},"type":"function"}]}'
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
authorization:
- Bearer t1.9euelZqWlp2bxpiUmZuLl57Lz8yMjO3rnpWalM3InMbJl5qUmJnHmcfPzsnl8_cXWF85-e9wPgBV_t3z91cGXTn573A-AFX-zef1656VmpHMi8vNmY2YjI_OjpWYncaM7_zF656VmpHMi8vNmY2YjI_OjpWYncaMveuelZrHy5fHis2MjY-dzIyJnJXIkrXrhpzRlp6S0ZCPmpGWm9KMmo2Jmo0.G0eyVx1OQ_yLFHLGkNV9gUPu64rm0aIT2-Hdbo-LGa5pwM7KetKWhD9ZTXg-Sg6L6CH_kW8Ay1LzAaQON5OfAw
connection:
- keep-alive
content-length:
- '715'
content-type:
- application/json
host:
- llm.api.cloud.yandex.net
user-agent:
- yandex-cloud-ml-sdk/0.15.0 python/3.12
x-client-request-id:
- 1a13e16d-a129-4579-a92d-91dad64a9c7b
method: POST
uri: https://llm.api.cloud.yandex.net/v1/chat/completions
response:
body:
string: '{"id":"a24b0c4c-26b5-49ac-8763-6d32ce420680","object":"chat.completion","created":1757951688,"model":"gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest","choices":[{"index":0,"message":{"role":"assistant","content":"The
result of the operation performed by the tool on the numbers [5, 4, 1] is
+20.0."},"finish_reason":"stop"}],"usage":{"prompt_tokens":130,"total_tokens":158,"completion_tokens":28}}

'
headers:
content-length:
- '395'
content-type:
- application/json
date:
- Mon, 15 Sep 2025 15:54:48 GMT
server:
- ycalb
x-client-request-id:
- 1a13e16d-a129-4579-a92d-91dad64a9c7b
x-request-id:
- 8710b8a5-f823-4f4b-91e4-f43cb8497891
x-server-trace-id:
- b729c273dfa0d799:b06551a059e0ae74:b729c273dfa0d799:1
status:
code: 200
message: OK
version: 1
Loading