File size: 2,108 Bytes
3d2a871
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use anyhow::Result;
use aws_sdk_bedrockruntime::{Client, primitives::Blob};
use serde_json::{json, Value};

pub const MODEL_ID: &str = "us.anthropic.claude-sonnet-4-6";

pub async fn invoke(
    client: &Client,
    system:   &str,
    messages: &[(&str, &str)],
    max_tokens: u32,
) -> Result<String> {
    invoke_with_model(client, MODEL_ID, system, messages, max_tokens).await
}

pub async fn invoke_with_model(
    client:    &Client,
    model_id:  &str,
    system:    &str,
    messages:  &[(&str, &str)],
    max_tokens: u32,
) -> Result<String> {
    let msgs: Vec<Value> = messages.iter().map(|(role, content)| {
        json!({ "role": role, "content": content })
    }).collect();

    // Mistral models use a different request format
    let is_mistral = model_id.starts_with("mistral.");
    let body = if is_mistral {
        // Devstral uses OpenAI-compatible messages format
        let mut mistral_msgs = vec![json!({"role": "system", "content": system})];
        for (role, content) in messages {
            mistral_msgs.push(json!({"role": role, "content": content}));
        }
        json!({
            "messages": mistral_msgs,
            "max_tokens": max_tokens,
            "temperature": 0.7,
        })
    } else {
        json!({
            "anthropic_version": "bedrock-2023-05-31",
            "max_tokens": max_tokens,
            "system": system,
            "messages": msgs,
        })
    };

    let resp = client
        .invoke_model()
        .model_id(model_id)
        .content_type("application/json")
        .body(Blob::new(serde_json::to_vec(&body)?))
        .send()
        .await?;

    let resp_body: Value = serde_json::from_slice(resp.body().as_ref())?;

    // Mistral returns choices[0].message.content, Claude returns content[0].text
    let text = if is_mistral {
        resp_body["choices"][0]["message"]["content"]
            .as_str()
            .unwrap_or("")
            .to_string()
    } else {
        resp_body["content"][0]["text"]
            .as_str()
            .unwrap_or("")
            .to_string()
    };

    Ok(text)
}