Pular para o conteúdo

SDK Node (floopy-sdk)

floopy-sdk e o cliente oficial Node/TypeScript do gateway Floopy. Ele envolve o pacote openai por composicao (sem fork, sem reimplementacao) e adiciona metodos tipados para cada endpoint exclusivo do Floopy.

Terminal window
pnpm add floopy-sdk # ou: npm i floopy-sdk / bun add floopy-sdk
import { Floopy } from "floopy-sdk";
const floopy = new Floopy({
apiKey: process.env.FLOOPY_API_KEY!,
});
const response = await floopy.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello from Floopy!" }],
});
console.log(response.choices[0]?.message?.content);

floopy.chat, floopy.embeddings e floopy.models delegam para um cliente openai pre-configurado para o gateway. Os tipos sao identicos aos do pacote openai.

Use options para ativar comportamentos do gateway de forma tipada. Eles viram headers Floopy-* aplicados a toda chamada do cliente:

const floopy = new Floopy({
apiKey: process.env.FLOOPY_API_KEY!,
options: {
cache: { enabled: true, bucketMaxSize: 3 },
promptId: "cd4249d5-44d5-46c8-8961-9eb3861e1f7e",
promptVersion: "1",
llmSecurityEnabled: true,
},
});
OpcaoHeaderFuncao
cache.enabledFloopy-Cache-EnabledLiga/desliga cache exato + semantico
cache.bucketMaxSizeFloopy-Cache-Bucket-Max-SizeTamanho maximo do bucket semantico
promptIdFloopy-Prompt-IdPrompt armazenado a resolver
promptVersionFloopy-Prompt-VersionVersao fixada do promptId
llmSecurityEnabledfloopy-llm-security-enabledPre-check do firewall LLM

Override por chamada: cada metodo aceita requestOptions no segundo argumento.

Cada um mapeia um endpoint publico /v1/*. Erros sao subclasses de FloopyError.

const r = await floopy.chat.completions.create({ /* ... */ });
await floopy.feedback.submit({ score: 9, useful: true, sessionId: r.id });
const decision = await floopy.decisions.get(requestId);
const page = await floopy.decisions.list({ from, to, limit: 50 });
for await (const d of floopy.decisions.iterate({ from })) { /* uma decisao */ }
for await (const p of floopy.decisions.pages({ from })) { /* uma pagina */ }
const exp = await floopy.experiments.create({
name: "cost-vs-quality",
variantARoutingRuleId: ruleA,
variantBRoutingRuleId: ruleB,
});
const results = await floopy.experiments.results(exp.id);
await floopy.experiments.rollback(exp.id);

create e rollback injetam automaticamente o header X-Floopy-Confirm: experiments que o gateway exige.

const current = await floopy.constraints.get();
await floopy.constraints.put({ costLimitMonthlyUsd: 100 });

put e full-replace: campos omitidos sao resetados para null.

for await (const row of floopy.export.decisions({ from, to })) {
// JSONL streamado, parseado e tipado
}
const { rows, trailer } = floopy.export.decisionsWithTrailer({ from, to });
for await (const r of rows) { /* ... */ }
console.log(trailer.value); // populado apos o iterador terminar
const run = await floopy.evaluations.create({ datasetId, model: "gpt-4o" });
const status = await floopy.evaluations.get(run.id);
const page = await floopy.evaluations.results(run.id, { limit: 100 });
await floopy.evaluations.cancel(run.id);
const explain = await floopy.routing.explain({ model, messages });
console.log(explain.wouldSelect, explain.firewallDecision);

Apenas para o plano Pro. wouldSelect e null quando o firewall bloquearia a requisicao.

O streaming de chat e delegado ao openai-node e retorna AsyncIterable<ChatCompletionChunk>:

const stream = await floopy.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "stream a haiku" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

floopy.export.decisions e um iterador async sobre o stream JSONL do gateway, respeitando o trailer.

import {
FloopyAuthError,
FloopyPlanError,
FloopyRateLimitError,
FloopyValidationError,
FloopyServerError,
} from "floopy-sdk";
try {
await floopy.export.decisions({ from, to });
} catch (err) {
if (err instanceof FloopyRateLimitError) {
await sleep((err.retryAfterSeconds ?? 1) * 1000);
} else if (err instanceof FloopyPlanError) {
console.error(`Upgrade do plano: feature ${err.feature} nao esta disponivel`);
} else throw err;
}

chat.completions e embeddings lancam subclasses de OpenAI.APIError do SDK upstream.

const floopy = new Floopy({
apiKey: process.env.FLOOPY_API_KEY!,
baseURL: "https://gateway.internal.acme.com/v1",
});

O SDK esta em 0.x enquanto a interface estabiliza. Em breve:

  • Helper de React hooks (floopy-sdk/react).
  • Entrypoints Edge / Deno.
  • Geracao automatica de tipos a partir dos modelos Rust do gateway (hoje os tipos sao escritos a mao e validados por testes).