mooncat-ai
v0.2.2
Published
Mooncat AI toolkit — pi-ai based llmCall, image generation, and flue-style agent runtime.
Readme
@mooncat/ai
A Mooncat AI toolkit built on @earendil-works/pi-ai + @earendil-works/pi-agent-core.
Three independent entrypoints:
llmCall— the simplest stable wrapper over pi-ai'scompleteSimple.imageGenerate— provider-dispatched image generation (Replicate).defineAgent/createAgentRuntime— an agent runtime on top of pi-agent-core'sAgentHarness.
Design rationale
pi-aiis the single LLM kernel. NoLlmProviderabstraction is layered on top — pi-ai already is a provider/model abstraction, so wrapping it again would be duplicate abstraction.pi-agent-coreis the agent base. It ships a fullAgentHarness(prompt/skill/compact/steer/subscribe),Session,loadSkills, compaction, andNodeExecutionEnv.@mooncat/ai/agentis a thin taste-aligned wrapper, not a reimplementation.- flue is a taste reference only. The tool parameter schemas, truncation policy, and
defineAgent(() => ({...}))ergonomics are borrowed from flue; its session/conversation/workflow/cloudflare shell is not. - Image generation is decoupled from LLMs. pi-ai does ship image-gen primitives, but they're tied to its provider catalog. Keeping image gen standalone lets it evolve independently.
Install
npm install @mooncat/ai
# peer deps (already pulled in, listed for clarity):
# @earendil-works/pi-ai ^0.80.2 @earendil-works/pi-agent-core ^0.80.2 zod ^3LLM call
mooncat-ai 建在 pi-ai 上。pi-ai 内置了 38 个 provider、1029 个模型(xiaomi/mimo、deepseek、openai、anthropic、moonshot、qwen…),baseUrl/api/cost/compat 全部预填好。
两条路径,分开用,不要混:
路径 A:用内置模型(绝大多数情况) — useBuiltin
内置 provider 只需注入 apiKey,不要手写 baseUrl/model(手写会整片覆盖内置定义,baseUrl 配错会导致请求发到错地址静默失败)。
import { llmCall, useBuiltin } from "@mooncat/ai";
// mimo 是 xiaomi 内置 provider 下的模型;deepseek 也是内置。只注 key。
const { models } = useBuiltin({
credentials: {
xiaomi: { apiKey: process.env.XIAOMI_API_KEY }, // → xiaomi/mimo-v2.5
deepseek: { apiKey: process.env.DEEPSEEK_API_KEY }, // → deepseek/deepseek-chat
},
});
const { text } = await llmCall({
model: "xiaomi/mimo-v2.5", // 直接用内置,baseUrl/cost/compat 全是 pi-ai 预填
input: "Summarize this",
system: "You are a concise assistant.",
models,
});常见内置 provider:xiaomi(mimo)、deepseek、openai、anthropic、moonshot、google、mistral、groq、fireworks… env var 命名是 <PROVIDER>_API_KEY(如 XIAOMI_API_KEY)。
查可用内置:
listBuiltinProviders()列全部 provider id;listBuiltinModels("xiaomi")列某 provider 的模型。 关键:mimo 的 provider id 是 xiaomi(不是 mimo)——xiaomi/mimo-v2.5,key 注到credentials.xiaomi。
路径 B:自定义全新 provider(pi-ai 没有的) — useCustom
仅用于:自建 vLLM、私有 endpoint、pi-ai 未收录的小众 provider。useCustom 校验 provider id 不撞内置——撞了(如 providers.xiaomi)硬报错,提示改用 useBuiltin。
import { llmCall, useCustom } from "@mooncat/ai";
const { models } = useCustom({
providers: {
mylocal: { // id 必须不在内置目录(撞了报错)
api: "openai-completions",
baseUrl: "http://localhost:8000/v1",
apiKey: "sk-...",
models: [{ id: "my-model", contextWindow: 32000 }],
},
},
});
await llmCall({ model: "mylocal/my-model", input: "...", models });同时用内置 + 自定义 — combineModels
import { useBuiltin, useCustom, combineModels } from "@mooncat/ai";
const a = useBuiltin({ credentials: { xiaomi: { apiKey } } });
const b = useCustom({ providers: { mylocal: { /* ... */ } } });
const { models } = combineModels(a, b); // xiaomi/* 和 mylocal/* 都可用Structured output (zod schema)
import { z } from "zod";
const result = await llmCall({
model: "deepseek/deepseek-chat",
input: "Extract product info for: Ceramic Mug — $12.99",
models, // 上面的 models(useBuiltin 的)
schema: z.object({ title: z.string(), price: z.number() }),
});
// → { title: "Ceramic Mug", price: 12.99 }Vision (image input)
await llmCall({
model: "xiaomi/mimo-v2-omni", // 内置支持 vision 的模型
input: "Describe this image",
models,
images: [{ data: base64String, mimeType: "image/png" }],
});⚠️ 不要用
providers去配内置 provider。providers.{内置id}会覆盖 pi-ai 预填的 baseUrl/model,曾导致 mimo 被当自定义手写、baseUrl 猜错、请求静默失败。内置的一律走useBuiltin({credentials})。
createModels({providers, credentials})(旧 API,混在一起)已 deprecated,保留只为向后兼容——新代码用useBuiltin/useCustom。
Image generation
import { imageGenerate } from "@mooncat/ai/image";
const { images } = await imageGenerate({
provider: "replicate",
model: "black-forest-labs/flux-schnell",
prompt: "a clean product photo of a ceramic mug",
size: "1024x1024",
});
// images[0].data is base64; .mimeType is inferred from the output URL.Agent runtime
import { defineAgent, createAgentRuntime } from "@mooncat/ai/agent";
const assistant = defineAgent(() => ({
model: "deepseek/deepseek-chat",
instructions: "You are a project analysis assistant.",
}));
const runtime = await createAgentRuntime({
cwd: "D:/Code/demo",
// 路径 A:内置 provider 走 credentials(不手写 baseUrl)
modelConfig: {
credentials: { deepseek: { apiKey: process.env.DEEPSEEK_API_KEY } },
},
});
const session = await runtime.session(assistant);
// session is a raw pi-agent-core AgentHarness — no facade.
session.subscribe(async (event) => {
if (event.type === "text") process.stdout.write(event.text);
});
const message = await session.prompt("Analyze this project.");
for (const block of message.content) {
if (block.type === "text") console.log(block.text);
}
// Other AgentHarness APIs work directly:
// await session.skill("summarize");
// await session.compact();
// await session.steer("Also check the tests.");The default toolset is read / write / edit / bash / grep / glob (ported from flue). The task (subagent delegation) tool is coming in v2.
Package layout
src/
├── llm/ llmCall, model resolver (ModelConfig → pi-ai Models), zod→JSON Schema
├── image/ imageGenerate + providers/replicate
├── agent/ defineAgent, createAgentRuntime, tools/{read,write,edit,bash,grep,glob}
├── config/ ModelConfig / ProviderConfig public types
└── index.ts top-level barrel (llm + image + agent + config)License
Apache-2.0
