Pular para o conteúdo
Entrar Começar

SDK Rust (floopy-sdk)

O floopy-sdk e o SDK Rust oficial do Floopy. Ele encapsula o crate oficial async-openai e o aponta para o gateway do Floopy, entao chat/embeddings/models continuam sendo um substituto direto 1:1, enquanto os recursos exclusivos do Floopy (auditoria, experimentos, constraints, exportacao de decisoes, feedback, roteamento em dry-run, sessoes) ganham metodos async tipados de primeira classe.

Prefere a abordagem sem SDK? A pagina Rust mostra como usar o crate async-openai puro com os headers do Floopy. Use o floopy-sdk quando voce tambem quiser os recursos tipados do Floopy e um unico cliente para ambos.

O crate e publicado como floopy-sdk e importado como floopy. E totalmente async (Tokio). Requer Rust >= 1.82.

Terminal window
cargo add floopy-sdk async-openai tokio --features tokio/macros,tokio/rt-multi-thread

O async-openai e reexportado como floopy::async_openai, entao voce tambem pode depender apenas do floopy-sdk e acessar os tipos por ele.

use floopy::Floopy;
use floopy::async_openai::types::chat::{
ChatCompletionRequestUserMessageArgs, CreateChatCompletionRequestArgs,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Floopy::new(std::env::var("FLOOPY_API_KEY")?)?;
let request = CreateChatCompletionRequestArgs::default()
.model("gpt-4o")
.messages(vec![ChatCompletionRequestUserMessageArgs::default()
.content("Ola do Floopy!")
.build()?
.into()])
.build()?;
let response = client.openai().chat().create(request).await?;
println!("{:?}", response.choices[0].message.content);
Ok(())
}

Defina FLOOPY_API_KEY no seu ambiente. Voce pode criar uma no dashboard.

use async_openai::{Client, config::OpenAIConfig};
let client = Client::with_config(
OpenAIConfig::new().with_api_key(std::env::var("OPENAI_API_KEY")?),
);
use floopy::Floopy;
let fl = Floopy::new(std::env::var("FLOOPY_API_KEY")?)?;
let client = fl.openai();
let response = client.chat().create(request).await?;

client.openai() retorna um async_openai::Client construido sob demanda e ja apontado para o gateway, entao os tipos e o comportamento em runtime sao identicos. Atualizacoes do upstream chegam ate voce com cargo update, sem forks ou divergencia de versao.

As FloopyOptions mapeiam para headers Floopy-* e sao enviadas em todas as requisicoes (chamadas compativeis com OpenAI e tambem as exclusivas do Floopy). Sobrescritas por chamada vao por um argumento RequestOptions no final de todo metodo de recurso.

use floopy::{Floopy, FloopyOptions, CacheOptions};
let client = Floopy::builder(std::env::var("FLOOPY_API_KEY")?)
.options(FloopyOptions {
cache: Some(CacheOptions { enabled: Some(true), bucket_max_size: Some(3) }),
prompt_id: Some("cd4249d5-44d5-46c8-8961-9eb3861e1f7e".into()),
prompt_version: Some("1".into()),
llm_security_enabled: Some(true),
})
.build()?;
OpcaoHeaderProposito
cache.enabledFloopy-Cache-EnabledLiga cache exato + semantico
cache.bucket_max_sizeFloopy-Cache-Bucket-Max-SizeMax. de entradas por bucket semantico
prompt_idFloopy-Prompt-IdPrompt armazenado a resolver
prompt_versionFloopy-Prompt-VersionVersao fixada para prompt_id
llm_security_enabledfloopy-llm-security-enabledPre-checagem do firewall LLM

Veja a Referencia de Headers para a lista completa.

Cada recurso mapeia para um endpoint publico /v1/* do gateway e e tipado de ponta a ponta. Paginacao e exportacao sao futures::Stream.

use floopy::types::*;
use futures::StreamExt;
// Feedback
client.feedback().submit(
FeedbackSubmitParams { score: 9, useful: true, session_id: None }, None,
).await?;
// Decisoes (Streams paginados)
let d = client.decisions().get("req_123", None).await?;
let stream = client.decisions().iter(DecisionListParams::default(), None);
futures::pin_mut!(stream);
while let Some(decision) = stream.next().await { let _ = decision?; }
// Experimentos (header X-Floopy-Confirm: experiments automatico)
let exp = client.experiments().create(ExperimentCreateParams {
name: "cost-vs-quality".into(),
variant_a_routing_rule_id: "rule_a".into(),
variant_b_routing_rule_id: "rule_b".into(),
description: None, split_percentage: None,
}, None).await?;
client.experiments().rollback(&exp.id, None).await?;
// Constraints (PUT full-replace)
client.constraints().put(
&OrgConstraints { cost_limit_monthly_usd: Some(100.0), ..Default::default() }, None,
).await?;
// Exportacao (JSONL em streaming + trailer)
let mut export = client.export()
.decisions_with_trailer(ExportDecisionsParams::new("a", "b"), None);
while let Some(row) = export.next().await { let _ = row?; }
println!("{:?}", export.trailer());
// Avaliacoes
let run = client.evaluations().create(EvaluationCreateParams {
dataset_id: "ds_1".into(), model: "gpt-4o".into(), prompt_id: None, config: None,
}, None).await?;
// Roteamento em dry-run (plano Pro)
let explain = client.routing()
.explain(RoutingExplainParams::new("gpt-4o", vec![]), None).await?;
// Sessoes — restaura uma conversa armazenada
let session = client.sessions().get("sess_1", None).await?;

Toda chamada exclusiva do Floopy retorna Result<T, floopy::Error>:

use floopy::{Error, Floopy};
use floopy::types::DecisionListParams;
match client.decisions().list(&DecisionListParams::default(), None).await {
Ok(page) => { /* ... */ }
Err(Error::RateLimit(d)) => {
let secs = d.retry_after_seconds.unwrap_or(1);
tokio::time::sleep(std::time::Duration::from_secs(secs)).await;
}
Err(Error::Plan(d)) => eprintln!("faca upgrade: recurso {:?} fora do plano", d.feature),
Err(e) => eprintln!("{e}"),
}

Error::status(), Error::request_id(), Error::feature() e Error::retry_after_seconds() estao disponiveis em todas as variantes. Erros de chat/embeddings sao emitidos pelo async-openai (async_openai::error::OpenAIError), nao por este crate.

  • A chave de API so e enviada no header Authorization e nunca aparece no Debug; o SDK nunca registra corpos de requisicao ou resposta.
  • A verificacao de certificado TLS fica ativa por padrao (rustls + webpki-roots).
  • As releases sao publicadas no crates.io via Trusted Publishing (OIDC) — sem token de registry de longa duracao no caminho de publicacao.

Veja o guia de Seguranca para controles do lado do gateway.