v2.17.0 (#822)
Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai> Co-authored-by: Guillaume LE GOFF <guillaume.lgf@gmail.com> Co-authored-by: Hdandria <henri.dandria@mistral.ai> Co-authored-by: Ivana Dunisijevic <ivana.dunisijevic@mistral.ai> Co-authored-by: Jean Burellier <sheplu@users.noreply.github.com> Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai> Co-authored-by: Mert Unsal <mert.unsal@mistral.ai> Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com> Co-authored-by: Paul VEZIA <166131032+le-codeur-rapide@users.noreply.github.com> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Val <102326092+vdeva@users.noreply.github.com> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: renovate-mistral[bot] <253709520+renovate-mistral[bot]@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
parent
564a14365e
commit
6bedf271ce
223 changed files with 10533 additions and 6947 deletions
132
tests/backend/data/anthropic.py
Normal file
132
tests/backend/data/anthropic.py
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from tests.backend.data import Chunk, JsonResponse
|
||||
|
||||
|
||||
def _sse_event(data: dict[str, Any]) -> Chunk:
|
||||
return f"data: {json.dumps(data, separators=(',', ':'))}".encode()
|
||||
|
||||
|
||||
def anthropic_request_content_blocks(payload: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
# Flatten every structured content block across a request's messages
|
||||
# (text/thinking/tool_use/tool_result blocks).
|
||||
return [
|
||||
block
|
||||
for message in payload["messages"]
|
||||
if isinstance(message["content"], list)
|
||||
for block in message["content"]
|
||||
]
|
||||
|
||||
|
||||
def anthropic_message(
|
||||
text: str,
|
||||
*,
|
||||
input_tokens: int = 12,
|
||||
output_tokens: int = 3,
|
||||
stop_reason: str = "end_turn",
|
||||
) -> JsonResponse:
|
||||
return {
|
||||
"content": [{"type": "text", "text": text}],
|
||||
"usage": {"input_tokens": input_tokens, "output_tokens": output_tokens},
|
||||
"stop_reason": stop_reason,
|
||||
}
|
||||
|
||||
|
||||
def anthropic_tool_use(
|
||||
name: str,
|
||||
tool_input: dict[str, Any],
|
||||
*,
|
||||
tool_id: str = "toolu_1",
|
||||
input_tokens: int = 20,
|
||||
output_tokens: int = 5,
|
||||
) -> JsonResponse:
|
||||
return {
|
||||
"content": [
|
||||
{"type": "tool_use", "id": tool_id, "name": name, "input": tool_input}
|
||||
],
|
||||
"usage": {"input_tokens": input_tokens, "output_tokens": output_tokens},
|
||||
"stop_reason": "tool_use",
|
||||
}
|
||||
|
||||
|
||||
def anthropic_reasoning_tool_use_stream(
|
||||
name: str,
|
||||
arguments: str,
|
||||
*,
|
||||
reasoning: str = "thinking...",
|
||||
signature: str = "sig",
|
||||
tool_id: str = "toolu_1",
|
||||
input_tokens: int = 20,
|
||||
output_tokens: int = 5,
|
||||
) -> list[Chunk]:
|
||||
return [
|
||||
_sse_event(e)
|
||||
for e in (
|
||||
{
|
||||
"type": "message_start",
|
||||
"message": {"usage": {"input_tokens": input_tokens}},
|
||||
},
|
||||
{
|
||||
"type": "content_block_start",
|
||||
"index": 0,
|
||||
"content_block": {"type": "thinking", "thinking": reasoning},
|
||||
},
|
||||
{
|
||||
"type": "content_block_delta",
|
||||
"index": 0,
|
||||
"delta": {"type": "signature_delta", "signature": signature},
|
||||
},
|
||||
{"type": "content_block_stop", "index": 0},
|
||||
{
|
||||
"type": "content_block_start",
|
||||
"index": 1,
|
||||
"content_block": {"type": "tool_use", "id": tool_id, "name": name},
|
||||
},
|
||||
{
|
||||
"type": "content_block_delta",
|
||||
"index": 1,
|
||||
"delta": {"type": "input_json_delta", "partial_json": arguments},
|
||||
},
|
||||
{"type": "content_block_stop", "index": 1},
|
||||
{
|
||||
"type": "message_delta",
|
||||
"delta": {"stop_reason": "tool_use"},
|
||||
"usage": {"output_tokens": output_tokens},
|
||||
},
|
||||
{"type": "message_stop"},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def anthropic_text_stream(
|
||||
text: str, *, input_tokens: int = 12, output_tokens: int = 3
|
||||
) -> list[Chunk]:
|
||||
return [
|
||||
_sse_event(e)
|
||||
for e in (
|
||||
{
|
||||
"type": "message_start",
|
||||
"message": {"usage": {"input_tokens": input_tokens}},
|
||||
},
|
||||
{
|
||||
"type": "content_block_start",
|
||||
"index": 0,
|
||||
"content_block": {"type": "text", "text": ""},
|
||||
},
|
||||
{
|
||||
"type": "content_block_delta",
|
||||
"index": 0,
|
||||
"delta": {"type": "text_delta", "text": text},
|
||||
},
|
||||
{"type": "content_block_stop", "index": 0},
|
||||
{
|
||||
"type": "message_delta",
|
||||
"delta": {"stop_reason": "end_turn"},
|
||||
"usage": {"output_tokens": output_tokens},
|
||||
},
|
||||
{"type": "message_stop"},
|
||||
)
|
||||
]
|
||||
|
|
@ -1,7 +1,41 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from tests.backend.data import Chunk, JsonResponse, ResultData, Url
|
||||
|
||||
|
||||
def mistral_completion(
|
||||
content: str,
|
||||
*,
|
||||
prompt_tokens: int = 100,
|
||||
completion_tokens: int = 50,
|
||||
tool_calls: list[dict[str, Any]] | None = None,
|
||||
) -> JsonResponse:
|
||||
return {
|
||||
"id": "cmpl_test",
|
||||
"created": 1234567890,
|
||||
"model": "devstral-latest",
|
||||
"object": "chat.completion",
|
||||
"usage": {
|
||||
"prompt_tokens": prompt_tokens,
|
||||
"completion_tokens": completion_tokens,
|
||||
"total_tokens": prompt_tokens + completion_tokens,
|
||||
},
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"finish_reason": "tool_calls" if tool_calls else "stop",
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": content,
|
||||
"tool_calls": tool_calls,
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
SIMPLE_CONVERSATION_PARAMS: list[tuple[Url, JsonResponse, ResultData]] = [
|
||||
(
|
||||
"https://api.mistral.ai",
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ import json
|
|||
from typing import Any
|
||||
|
||||
from tests.backend.data import Chunk, JsonResponse, ResultData, Url
|
||||
|
||||
OPENAI_RESPONSES_TEST_BASE_URL = "https://api.openai.com"
|
||||
from tests.constants import OPENAI_BASE_URL
|
||||
|
||||
|
||||
def _sse_event(data: dict[str, Any] | str) -> Chunk:
|
||||
|
|
@ -90,9 +89,134 @@ def _function_call_item(
|
|||
}
|
||||
|
||||
|
||||
def openai_message_item(
|
||||
text: str, *, phase: str | None = None, message_id: str = "msg_1"
|
||||
) -> dict[str, Any]:
|
||||
return _message_output_item(message_id, text, phase=phase)
|
||||
|
||||
|
||||
def openai_function_call_item(
|
||||
name: str, arguments: str, *, item_id: str = "fc_1", call_id: str = "call_1"
|
||||
) -> dict[str, Any]:
|
||||
return _function_call_item(item_id, call_id, name, arguments)
|
||||
|
||||
|
||||
def openai_response(
|
||||
output: list[dict[str, Any]],
|
||||
*,
|
||||
input_tokens: int = 10,
|
||||
output_tokens: int = 2,
|
||||
response_id: str = "resp_1",
|
||||
model: str = "gpt-test",
|
||||
) -> JsonResponse:
|
||||
return {
|
||||
"id": response_id,
|
||||
"object": "response",
|
||||
"created_at": 1234567890,
|
||||
"model": model,
|
||||
"output": output,
|
||||
"usage": {
|
||||
"input_tokens": input_tokens,
|
||||
"output_tokens": output_tokens,
|
||||
"total_tokens": input_tokens + output_tokens,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def openai_sse(*events: dict[str, Any] | str) -> list[Chunk]:
|
||||
return [_sse_event(event) for event in events]
|
||||
|
||||
|
||||
def openai_reasoning_tool_call_stream(
|
||||
name: str,
|
||||
arguments: str,
|
||||
*,
|
||||
reasoning: str = "thinking...",
|
||||
call_id: str = "call_1",
|
||||
item_id: str = "fc_1",
|
||||
input_tokens: int = 20,
|
||||
output_tokens: int = 5,
|
||||
) -> list[Chunk]:
|
||||
return openai_sse(
|
||||
{"type": "response.created", "response": {"id": "resp_1", "output": []}},
|
||||
{
|
||||
"type": "response.output_item.added",
|
||||
"output_index": 0,
|
||||
"item": _stream_message_item("msg_r", phase="commentary"),
|
||||
},
|
||||
{
|
||||
"type": "response.reasoning_summary_text.delta",
|
||||
"output_index": 0,
|
||||
"delta": reasoning,
|
||||
},
|
||||
{
|
||||
"type": "response.output_item.added",
|
||||
"output_index": 1,
|
||||
"item": _function_call_item(
|
||||
item_id, call_id, name, "", status="in_progress"
|
||||
),
|
||||
},
|
||||
{
|
||||
"type": "response.function_call_arguments.delta",
|
||||
"output_index": 1,
|
||||
"call_id": call_id,
|
||||
"delta": arguments,
|
||||
},
|
||||
{
|
||||
"type": "response.function_call_arguments.done",
|
||||
"output_index": 1,
|
||||
"call_id": call_id,
|
||||
"name": name,
|
||||
"arguments": arguments,
|
||||
},
|
||||
{
|
||||
"type": "response.output_item.done",
|
||||
"output_index": 1,
|
||||
"item": _function_call_item(item_id, call_id, name, arguments),
|
||||
},
|
||||
{
|
||||
"type": "response.completed",
|
||||
"response": openai_response(
|
||||
[_function_call_item(item_id, call_id, name, arguments)],
|
||||
input_tokens=input_tokens,
|
||||
output_tokens=output_tokens,
|
||||
),
|
||||
},
|
||||
"[DONE]",
|
||||
)
|
||||
|
||||
|
||||
def openai_text_stream(
|
||||
text: str, *, input_tokens: int = 10, output_tokens: int = 2
|
||||
) -> list[Chunk]:
|
||||
return openai_sse(
|
||||
{"type": "response.created", "response": {"id": "resp_1", "output": []}},
|
||||
{
|
||||
"type": "response.output_item.added",
|
||||
"output_index": 0,
|
||||
"item": _stream_message_item("msg_1"),
|
||||
},
|
||||
{
|
||||
"type": "response.output_text.delta",
|
||||
"output_index": 0,
|
||||
"content_index": 0,
|
||||
"delta": text,
|
||||
},
|
||||
{
|
||||
"type": "response.completed",
|
||||
"response": openai_response(
|
||||
[openai_message_item(text)],
|
||||
input_tokens=input_tokens,
|
||||
output_tokens=output_tokens,
|
||||
),
|
||||
},
|
||||
"[DONE]",
|
||||
)
|
||||
|
||||
|
||||
SIMPLE_CONVERSATION_PARAMS: list[tuple[Url, JsonResponse, ResultData]] = [
|
||||
(
|
||||
OPENAI_RESPONSES_TEST_BASE_URL,
|
||||
OPENAI_BASE_URL,
|
||||
{
|
||||
"id": "resp_fake_id_1234",
|
||||
"object": "response",
|
||||
|
|
@ -113,7 +237,7 @@ SIMPLE_CONVERSATION_PARAMS: list[tuple[Url, JsonResponse, ResultData]] = [
|
|||
|
||||
TOOL_CONVERSATION_PARAMS: list[tuple[Url, JsonResponse, ResultData]] = [
|
||||
(
|
||||
OPENAI_RESPONSES_TEST_BASE_URL,
|
||||
OPENAI_BASE_URL,
|
||||
{
|
||||
"id": "resp_fake_id_9012",
|
||||
"object": "response",
|
||||
|
|
@ -144,7 +268,7 @@ TOOL_CONVERSATION_PARAMS: list[tuple[Url, JsonResponse, ResultData]] = [
|
|||
|
||||
STREAMED_SIMPLE_CONVERSATION_PARAMS: list[tuple[Url, list[Chunk], list[ResultData]]] = [
|
||||
(
|
||||
OPENAI_RESPONSES_TEST_BASE_URL,
|
||||
OPENAI_BASE_URL,
|
||||
[
|
||||
_sse_event({
|
||||
"type": "response.created",
|
||||
|
|
@ -235,7 +359,7 @@ STREAMED_SIMPLE_CONVERSATION_PARAMS: list[tuple[Url, list[Chunk], list[ResultDat
|
|||
|
||||
COMMENTARY_CONVERSATION_PARAMS: list[tuple[Url, JsonResponse, ResultData]] = [
|
||||
(
|
||||
OPENAI_RESPONSES_TEST_BASE_URL,
|
||||
OPENAI_BASE_URL,
|
||||
{
|
||||
"id": "resp_thinking_1234",
|
||||
"object": "response",
|
||||
|
|
@ -268,7 +392,7 @@ STREAMED_COMMENTARY_CONVERSATION_PARAMS: list[
|
|||
tuple[Url, list[Chunk], list[ResultData]]
|
||||
] = [
|
||||
(
|
||||
OPENAI_RESPONSES_TEST_BASE_URL,
|
||||
OPENAI_BASE_URL,
|
||||
[
|
||||
_sse_event({
|
||||
"type": "response.created",
|
||||
|
|
@ -419,7 +543,7 @@ STREAMED_COMMENTARY_CONVERSATION_PARAMS: list[
|
|||
|
||||
STREAMED_TOOL_CONVERSATION_PARAMS: list[tuple[Url, list[Chunk], list[ResultData]]] = [
|
||||
(
|
||||
OPENAI_RESPONSES_TEST_BASE_URL,
|
||||
OPENAI_BASE_URL,
|
||||
[
|
||||
_sse_event({
|
||||
"type": "response.created",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue