link-assistant-router 1.4.6

Link.Assistant.Router — Claude MAX OAuth proxy and token gateway for Anthropic APIs
Documentation
use super::*;

#[test]
fn chat_tool_contract_and_two_turn_history_are_exact() {
    let schema = json!({
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
    });
    let request = chat_to_gemini_request_checked(&json!({
        "messages": [
            {"role": "user", "content": "weather?"},
            {"role": "assistant", "content": null, "tool_calls": [{
                "id": "call_weather", "type": "function",
                "function": {"name": "weather", "arguments": "{\"city\":\"Lisbon\"}"}
            }]},
            {"role": "tool", "tool_call_id": "call_weather", "content": "{\"c\":21}"},
            {"role": "user", "content": "summarize"}
        ],
        "tools": [{"type": "function", "function": {
            "name": "weather", "description": "look up weather", "parameters": schema,
            "strict": false
        }}],
        "tool_choice": "required"
    }))
    .unwrap();

    assert_eq!(
        request["tools"],
        json!([{"functionDeclarations": [{
            "name": "weather", "description": "look up weather", "parameters": schema
        }]}])
    );
    assert_eq!(
        request["toolConfig"],
        json!({"functionCallingConfig": {"mode": "ANY"}})
    );
    assert_eq!(
        request["contents"],
        json!([
            {"role": "user", "parts": [{"text": "weather?"}]},
            {"role": "model", "parts": [{"functionCall": {
                "id": "call_weather", "name": "weather", "args": {"city": "Lisbon"}
            }}]},
            {"role": "user", "parts": [{"functionResponse": {
                "id": "call_weather", "name": "weather", "response": {"c": 21}
            }}]},
            {"role": "user", "parts": [{"text": "summarize"}]}
        ])
    );
}

#[test]
fn gemini_generation_controls_and_structured_output_map_exactly() {
    let request = chat_to_gemini_request_checked(&json!({
        "messages": [{"role": "user", "content": "answer"}],
        "stop": ["END"],
        "frequency_penalty": 1.25,
        "presence_penalty": -0.5,
        "seed": 1234,
        "top_k": 17,
        "response_format": {"type": "json_schema", "json_schema": {
            "name": "answer", "strict": true, "schema": {"type": "object"}
        }},
        "parallel_tool_calls": true,
        "n": 1,
        "modalities": ["text"],
        "logprobs": false,
        "top_logprobs": 0
    }))
    .unwrap();

    assert_eq!(request["generationConfig"]["stopSequences"], json!(["END"]));
    assert_eq!(request["generationConfig"]["frequencyPenalty"], 1.25);
    assert_eq!(request["generationConfig"]["presencePenalty"], -0.5);
    assert_eq!(request["generationConfig"]["seed"], 1234);
    assert_eq!(request["generationConfig"]["topK"], 17);
    assert_eq!(
        request["generationConfig"]["responseMimeType"],
        "application/json"
    );
    assert_eq!(
        request["generationConfig"]["responseJsonSchema"]["type"],
        "object"
    );
}

#[test]
fn responses_structured_output_reaches_gemini_generation_config() {
    let chat = responses_to_chat_checked(&json!({
        "model": "gemini-test",
        "input": "answer",
        "text": {"format": {
            "type": "json_schema", "name": "answer", "strict": true,
            "schema": {"type": "object"}
        }}
    }))
    .unwrap();
    let request = chat_to_gemini_request_checked(&chat).unwrap();
    assert_eq!(
        request["generationConfig"]["responseMimeType"],
        "application/json"
    );
    assert_eq!(
        request["generationConfig"]["responseJsonSchema"]["type"],
        "object"
    );
}

#[test]
fn responses_tool_contract_and_two_turn_history_are_exact() {
    let body = json!({
        "model": "live-model",
        "input": [
            {"role": "user", "content": [{"type": "input_text", "text": "weather?"}]},
            {"type": "function_call", "call_id": "call_7", "name": "weather",
             "arguments": "{\"city\":\"Hanoi\"}"},
            {"type": "function_call_output", "call_id": "call_7", "output": "{\"c\":31}"}
        ],
        "tools": [{"type": "function", "name": "weather", "description": "weather",
            "parameters": {"type": "object"}, "strict": false}],
        "tool_choice": {"type": "function", "name": "weather"}
    });
    let chat = responses_to_chat_checked(&body).unwrap();
    assert_eq!(
        chat["tool_choice"],
        json!({"type": "function", "function": {"name": "weather"}})
    );
    let request = chat_to_gemini_request_checked(&chat).unwrap();
    assert_eq!(
        request["tools"],
        json!([{"functionDeclarations": [{
            "name": "weather", "description": "weather", "parameters": {"type": "object"}
        }]}])
    );
    assert_eq!(
        request["toolConfig"],
        json!({"functionCallingConfig": {"mode": "ANY", "allowedFunctionNames": ["weather"]}})
    );
    assert_eq!(
        request["contents"][1]["parts"][0]["functionCall"],
        json!({"id": "call_7", "name": "weather", "args": {"city": "Hanoi"}})
    );
    assert_eq!(
        request["contents"][2]["parts"][0]["functionResponse"],
        json!({"id": "call_7", "name": "weather", "response": {"c": 31}})
    );
}

#[test]
fn chat_and_responses_images_preserve_mime_uri_and_order() {
    let chat = json!({"messages": [{"role": "user", "content": [
        {"type": "text", "text": "before"},
        {"type": "image_url", "image_url": {"url": "data:image/png;base64,QUJD"}},
        {"type": "text", "text": "between"},
        {"type": "image_url", "image_url": {"url": "https://images.test/a.webp"}}
    ]}]});
    let expected = json!([
        {"text": "before"},
        {"inlineData": {"mimeType": "image/png", "data": "QUJD"}},
        {"text": "between"},
        {"fileData": {"fileUri": "https://images.test/a.webp"}}
    ]);
    assert_eq!(
        chat_to_gemini_request_checked(&chat).unwrap()["contents"][0]["parts"],
        expected
    );

    let responses = json!({"input": [{"role": "user", "content": [
        {"type": "input_image", "image_url": "data:image/png;base64,QUJD"},
        {"type": "input_text", "text": "after"}
    ]}]});
    let chat = responses_to_chat_checked(&responses).unwrap();
    assert_eq!(
        chat_to_gemini_request_checked(&chat).unwrap()["contents"][0]["parts"],
        json!([
            {"inlineData": {"mimeType": "image/png", "data": "QUJD"}},
            {"text": "after"}
        ])
    );
}

#[test]
fn gemini_images_preserve_image_only_and_mixed_turns() {
    let chat = gemini_request_to_chat_checked(
        "model",
        &json!({"contents": [
            {"role": "user", "parts": [{
                "inlineData": {"mimeType": "image/png", "data": "QUJD"}
            }]},
            {"role": "model", "parts": [{"text": "seen"}]},
            {"role": "user", "parts": [
                {"text": "before"},
                {"fileData": {"mimeType": "image/webp", "fileUri": "https://images.test/a.webp"}},
                {"text": "after"}
            ]}
        ]}),
    )
    .unwrap();
    let messages = chat["messages"].as_array().unwrap();
    assert_eq!(messages.len(), 3);
    assert_eq!(
        messages[0]["content"],
        json!([{"type": "image_url", "image_url": {
            "url": "data:image/png;base64,QUJD"
        }}])
    );
    assert_eq!(
        messages[2]["content"],
        json!([
            {"type": "text", "text": "before"},
            {"type": "image_url", "image_url": {"url": "https://images.test/a.webp"}},
            {"type": "text", "text": "after"}
        ])
    );
}

#[test]
fn anthropic_images_reach_the_same_gemini_parts() {
    let body = json!({"messages": [{"role": "user", "content": [
        {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "QUJD"}},
        {"type": "text", "text": "middle"},
        {"type": "image", "source": {"type": "url", "url": "https://images.test/b.jpg"}}
    ]}]});
    crate::bridge_request::validate_anthropic_request(
        &body,
        crate::bridge_request::BridgeTarget::Gemini,
    )
    .unwrap();
    let chat = crate::bridge_request::anthropic_to_chat_request(&body, "model");
    assert_eq!(
        chat_to_gemini_request_checked(&chat).unwrap()["contents"][0]["parts"],
        json!([
            {"inlineData": {"mimeType": "image/png", "data": "QUJD"}},
            {"text": "middle"},
            {"fileData": {"fileUri": "https://images.test/b.jpg"}}
        ])
    );
}

#[test]
fn function_results_keep_order_and_consume_explicit_ids() {
    let request = json!({"contents": [
        {"role": "model", "parts": [
            {"functionCall": {"id": "a", "name": "same", "args": {"n": 1}}},
            {"functionCall": {"id": "b", "name": "same", "args": {"n": 2}}}
        ]},
        {"role": "user", "parts": [
            {"functionResponse": {"id": "b", "name": "same", "response": {"n": 2}}},
            {"functionResponse": {"id": "a", "name": "same", "response": {"n": 1}}},
            {"text": "after"},
            {"inlineData": {"mimeType": "image/png", "data": "QUJD"}}
        ]}
    ]});
    let chat = gemini_request_to_chat_checked("model", &request).unwrap();
    assert_eq!(chat["messages"][1]["tool_call_id"], "b");
    assert_eq!(chat["messages"][2]["tool_call_id"], "a");
    assert_eq!(
        chat["messages"][3]["content"],
        json!([
            {"type": "text", "text": "after"},
            {"type": "image_url", "image_url": {"url": "data:image/png;base64,QUJD"}}
        ])
    );

    let mut ambiguous = request.clone();
    ambiguous["contents"][1]["parts"] = json!([{
        "functionResponse": {"name": "same", "response": {}}
    }]);
    assert!(
        gemini_request_to_chat_checked("model", &ambiguous)
            .unwrap_err()
            .contains("ambiguous")
    );

    let mut reused = request;
    reused["contents"][1]["parts"] = json!([
        {"functionResponse": {"id": "a", "name": "same", "response": {}}},
        {"functionResponse": {"id": "a", "name": "same", "response": {}}}
    ]);
    assert!(gemini_request_to_chat_checked("model", &reused).is_err());
}

#[test]
fn unsupported_tools_images_and_interleaving_fail_closed() {
    let invalid_chat = [
        json!({"messages": [], "future_field": true}),
        json!({"messages": [], "tools": [{"type": "web_search"}]}),
        json!({"messages": [], "tools": [{"type": "function", "function": {
            "name": "x", "strict": true
        }}]}),
        json!({"messages": [], "tool_choice": {"type": "allowed_tools"}}),
        json!({"messages": [{"role": "user", "content": [{
            "type": "image_url", "image_url": {"url": "data:image/svg+xml;base64,QUJD"}
        }]}]}),
        json!({"messages": [{"role": "user", "content": [{
            "type": "image_url", "image_url": {"url": "data:image/png;base64,!"}
        }]}]}),
    ];
    for body in invalid_chat {
        assert!(chat_to_gemini_request_checked(&body).is_err(), "{body}");
    }

    for body in [
        json!({"contents": [], "futureField": true}),
        json!({"contents": [], "safetySettings": [{
            "category": "HARM_CATEGORY_HARASSMENT",
            "threshold": "BLOCK_LOW_AND_ABOVE"
        }]}),
        json!({"contents": [], "store": true}),
        json!({"contents": [], "store": false}),
        json!({"contents": [], "tools": [{"googleSearch": {}}]}),
        json!({"contents": [{"role": "user", "parts": [{
            "fileData": {"fileUri": "gs://private/image.png"}
        }]}]}),
        json!({"contents": [{"role": "user", "parts": [{"text": "x", "futurePart": true}]}]}),
        json!({"contents": [
            {"role": "model", "parts": [{"functionCall": {"id": "a", "name": "x", "args": {}}}]},
            {"role": "user", "parts": [
                {"text": "before"},
                {"functionResponse": {"id": "a", "name": "x", "response": {}}}
            ]}
        ]}),
    ] {
        assert!(
            gemini_request_to_chat_checked("model", &body).is_err(),
            "{body}"
        );
    }

    assert!(responses_to_chat_checked(&json!({"input": "x", "future_field": true})).is_err());
}

#[test]
fn gemini_cached_content_is_rejected_before_cross_provider_translation() {
    let error = gemini_request_to_chat_checked(
        "model",
        &json!({
            "cachedContent":"cachedContents/synthetic-cache",
            "contents":[{"role":"user","parts":[{"text":"continue"}]}]
        }),
    )
    .unwrap_err();
    assert!(error.contains("cachedContent"), "{error}");
}