@codefionn/llmleaf-客户端
TypeScript / JavaScript 客户端 叶子 LLM 代理服务器.
在 HTTP 上说 llmleaf 的 OpenAI/ OpenRouter 形状的 JSON(参见 ../SPEC.md) (中文(简体) ).
零运行时间依赖度超过 @bufbuild/protobuf 运行时间,它运行 任何地方
全球 fetch 编号 : ReadableStream 编号 : FormData 存在 – 节点20+, Deno, Bun, 浏览器.
安装
npm install @codefionn/llmleaf-client
示例
import { LlmleafClient, Role } from "@codefionn/llmleaf-client";
const client = new LlmleafClient({
baseUrl: "https://gateway.example.com",
apiKey: process.env.LLMLEAF_API_KEY!,
timeoutMs: 30_000, // optional; 0/omitted = no timeout. Also: adminToken, fetch
});
// Non-streaming chat
const res = await client.chat({
model: "gpt-4o-mini",
messages: [{ role: Role.USER, content: "Say hi." }],
});
console.log(res.choices[0]?.message.content);
// Streaming chat — async iterable of chunks, stops at `data: [DONE]`
for await (const chunk of client.chatStream({
model: "gpt-4o-mini",
messages: [{ role: Role.USER, content: "Count to 5." }],
})) {
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
}
// Responses dialect (POST /v1/responses) — `input` is a bare string or an item array
const resp = await client.responses({
model: "gpt-4o-mini",
input: [{ type: "message", role: "user", content: "Say hi." }],
});
// Streaming responses — typed events, NO `[DONE]`; stops on the terminal
// response.completed / .incomplete / .failed event; unknown event types are skipped
for await (const event of client.responsesStream({
model: "gpt-4o-mini",
input: "Count to 5.",
})) {
if (event.type === "response.output_text.delta") process.stdout.write(event.delta ?? "");
}
流媒体工具调用被曝光为 choice.delta.toolCalls按选择索引排列的组块
和每个 ToolCallDelta.index; 保留 id 编号 : type / 函数 name 随时随地,并附上
function.arguments 片段按到达顺序排列,直到 finishReason === FinishReason.TOOL_CALLS。 。 。 .
终点
await client.chat(req); // POST /v1/chat/completions
client.chatStream(req); // stream:true, async iterable of chunks
await client.responses(req); // POST /v1/responses (OpenAI Responses dialect)
client.responsesStream(req); // stream:true, async iterable of typed events (no [DONE])
await client.embeddings(req); // base64 vectors decoded to floats
await client.rerank(req); // POST /v1/rerank; results by relevance (plain JSON)
await client.decisions(req); // POST /v1/decisions; structured decision answers
await client.listModels({ type: "llm" });
await client.speech(req); // -> { bytes, contentType }
await client.voices("tts-1");
await client.transcribe(file, req); // multipart; json/verbose_json -> object, text/srt/vtt -> tr.text
await client.createBatch(req);
await client.getBatch(id);
await client.cancelBatch(id);
client.batchResults(id); // async iterable of result lines
自由形式字段( E)extra, (中文(简体) ), responseFormat.jsonSchema, (中文(简体) ), functionDef.parameters,)为生
JSON 字符串——通过 JSON.stringify(obj) 和相接相接的运算值;
extra 键在请求的顶端合并.
决定
const decision = await client.decisions({
model: "jev",
state: { turn: 2 },
questions: {
route: { type: "choice", instructions: "Which route?", criteria: { left: null, right: null } },
},
});
console.log(decision.answers.route);
state, (中文(简体) ), questions,答案,和决定元数据使用本地JSON值. extra 是一个
结构化对象合并到正文; 无法覆盖 model, (中文(简体) ), state,或 questions。 。 。 .
错误
任何非-2xx 响应都会丢出一个键入 ApiError数字 :
import { ApiError } from "@codefionn/llmleaf-client";
try {
await client.chat(req);
} catch (e) {
if (e instanceof ApiError) console.error(e.status, e.message); // 403 "model not allowed"
}
运行示例
examples/basic.ts 进行聊天、流线和模型列表:
LLMLEAF_BASE_URL=https://gateway.example.com LLMLEAF_API_KEY=sk-… npx tsx examples/basic.ts
从原生再生
生成的文件( E)src/gen/llmleaf/v1/llmleaf_pb.ts)是犯法的
原型变化 :
npm install # fetch the @bufbuild/protoc-gen-es plugin
npm run gen # runs scripts/gen.sh (needs protoc on PATH)
页:1
- 线上绘图是手写(
src/wire.ts因为Protobuf -es的JSON密码发出 骆驼Case +SCREAMING_CASE,这不是 OpenAI 线条(snake case + 小写符号). 生成的描述符在gen导出用于反射 . - 解码器是宽大处理的(允许出/出田)。 不得复试.
chatStream编号 :batchResults需要一个能流的fetch。实时 WebSocket 已超出范围.