@rowan-agent /模型
模型描述符、协议提供程序调度、SSE流和成本
计算。代理运行时通过 ModelConfig 或者
ModelRef + StreamFn;它不依赖于代理生命周期状态。
模型注册
import { registerModel, resolveModel, stream } from "@rowan-agent/models";
registerModel({
id: "gpt-4o",
provider: "openai",
protocol: "openai-responses",
baseUrl: "https://api.openai.com/v1",
apiKey: process.env.OPENAI_API_KEY!,
reasoning: false,
thinkingLevel: "off",
input: ["text"],
headers: { "X-Model-Route": "default" },
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128_000,
maxTokens: 4096,
});
const model = resolveModel("openai/gpt-4o");
for await (const event of stream(model!, request, ctx)) {
// consume LlmStreamEvent
}
resolveModel() 解析 provider/model; registerModel() 注册自定义
模型。 streamByRef() 处理注册模型,而 createModelStream()
返回与运行时兼容的 StreamFn。两者都只通过模型调度
protocol 并且不保留旧的Provider工厂。
供应商注册表
import { registerApiProvider } from "@rowan-agent/models";
registerApiProvider({ protocol: "my-api", stream: myStream });
内置协议包括 openai-completions, openai-responses,
openai-codex-responses, anthropic-messages。提供程序传输句柄
标头、超时、中止、结构化错误和重试一致。
供应商认证
ModelConfig 和 ProviderConfig 接受一个可选的、可序列化的 auth
模式。它的缺席保持了现有的静态 apiKey 行为:
// Absent: Authorization: Bearer <apiKey> (or x-api-key for Anthropic).
{ provider: "openai", apiKey: process.env.OPENAI_API_KEY! }
// Keyless local server: no Authorization or x-api-key header.
{ provider: "ollama", baseUrl: "http://127.0.0.1:11434/v1", auth: "none" }
// Subscription login. The provider id keys the stored credential.
{ provider: "xai", baseUrl: "https://cli-chat-proxy.grok.com/v1", auth: "xai" }
命名流是 "xai", "github-copilot", "openai-codex"。他们从来没有
在配置中放入令牌。主机提供所有者控制的凭据
存储到流:
const streamModel = createModelStream(config, {
oauthCredentialStore: {
async load(providerId) {
// Return OAuthCredential | undefined.
},
async save(providerId, credential) {
// Persist the rotated credential before returning.
},
},
});
在每次HTTP尝试之前,OAuth流加载提供者的凭据,
当它在60秒内过期时刷新它,保存一个旋转的凭据
在使用之前,单航班刷新每个提供商id。刷新失败
请求而不是重用陈旧的令牌。缺少证书加薪
OAuthSignInRequiredError 与 code: "sign_in_required".
开始登录 startOAuthLogin(flow, options)。浏览器流公开 url;
设备流暴露 userCode 和 verificationUri。保存已解析的文件
与模型配置使用的提供者id相同的凭据:
const session = await startOAuthLogin("xai");
console.log(session.url ?? `${session.verificationUri} (${session.userCode})`);
const credential = await session.credential;
await store.save("xai", credential);
// session.cancel() aborts an unfinished login and closes any listener.
refreshOAuthCredential(flow, credential, options?) 刷新路径是否相同
由请求身份验证使用。
协议类型
这个包定义了模型请求和响应、内容块、工具调用、
和流事件。代理身份、运行、持久事件和工具生命周期
合同属于 @rowan-agent/agent.
type StreamFn = (
request: LlmRequest,
ctx: ProviderCallContext,
) => AsyncIterable<LlmStreamEvent>;
ProviderCallContext
流函数接收 ProviderCallContext :
signal: AbortSignal-运行级取消信号。run: { id, agentId, scope, cwd }-活动的执行元数据。internal?: boolean- - - - - -true当调用在会话的副本上工作时(内部模型循环)。它的消息不会写入历史记录,因此在调用之间保持会话状态的提供者不能推进它。缺席意味着正常通话。interact(request): Promise<JsonValue>-请求用户实时交互。tools.list(): readonly LlmToolDefinition[]-使用元数据注册工具定义。tools.call(name, args, options?): Promise<ToolResult>—调用已注册的工具。options.signal?: AbortSignal-在不取消运行的情况下终止单个工具调用。options.onUpdate?(toolCall: ToolCall, progress?: ToolProgress): void-接收合并的ToolCall,每次它在执行期间发生变化(开始,每个进度驱动)present更新最后一个)。原始的progress对象在由进度报告触发更新时传递。
tools.report(update: ToolCall | ToolCallUpdate): void-报告外部工具执行情况。
ToolProgress
进度报告使用标准的MCP notifications/progress 形状:
type ToolProgress = {
progress: number;
total?: number;
message?: string;
_meta?: JsonObject;
};
- 形状验证(有限数);无效报告将被丢弃,并伴有警告,而不会导致工具调用失败。
- 工具私有进度数据消失
_meta钥匙。 - 连续的输出必须累加地报告(例如,尾部),因为瞬态更新每次合并
toolCallId.
源结构
src/
├── protocol.ts # Model/LLM request and response types
├── auth.ts # Auth modes, credentials, and the credential-store seam
├── models.ts # Model registry
├── registry.ts # Protocol dispatch
├── sse.ts # SSE parser
├── oauth/ # Login, refresh, polling, and provider request auth
└── providers/ # Built-in HTTP providers and shared transport