@rowan-agent/models

中文文档
0.14.0发布于 2026/11/02MITTypeScriptESM + CJS零依赖构建来源已验证

Model descriptors, protocol Provider dispatch, SSE streaming, and cost calculation. The Agent Runtime uses this package through ModelConfig or ModelRef + StreamFn; it does not depend on Agent lifecycle state.

原始使用文档
文档目录7 节
  1. Model registry
  2. Provider registry
  3. Provider authentication
  4. Protocol types
  5. ProviderCallContext
  6. ToolProgress
  7. Source structure

@rowan-agent/models

Model descriptors, protocol Provider dispatch, SSE streaming, and cost calculation. The Agent Runtime uses this package through ModelConfig or ModelRef + StreamFn; it does not depend on Agent lifecycle state.

Model registry

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() parses provider/model; registerModel() registers custom models. streamByRef() handles registered models, while createModelStream() returns a Runtime-compatible StreamFn. Both dispatch only through the model's protocol and do not retain the old Provider factory.

Provider registry

import { registerApiProvider } from "@rowan-agent/models";

registerApiProvider({ protocol: "my-api", stream: myStream });

Built-in protocols are openai-completions, openai-responses, openai-codex-responses, and anthropic-messages. Provider transport handles headers, timeouts, aborts, structured errors, and retries consistently.

Provider authentication

ModelConfig and ProviderConfig accept one optional, serializable auth mode. Its absence keeps the existing static apiKey behavior:

// 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" }

Named flows are "xai", "github-copilot", and "openai-codex". They never put tokens in configuration. The host supplies an owner-controlled credential store to the stream:

const streamModel = createModelStream(config, {
  oauthCredentialStore: {
    async load(providerId) {
      // Return OAuthCredential | undefined.
    },
    async save(providerId, credential) {
      // Persist the rotated credential before returning.
    },
  },
});

Before each HTTP attempt, an OAuth stream loads the provider's credential, refreshes it when it expires within 60 seconds, saves a rotated credential before use, and single-flights refresh per provider id. A failed refresh fails the request rather than reusing a stale token. A missing credential raises OAuthSignInRequiredError with code: "sign_in_required".

Start login with startOAuthLogin(flow, options). Browser flows expose url; device flows expose userCode and verificationUri. Save the resolved credential under the same provider id used by the model configuration:

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?) is the same refresh path used by request authentication.

Protocol types

This package defines model requests and responses, content blocks, Tool calls, and stream events. Agent identities, Runs, Durable Events, and Tool lifecycle contracts belong to @rowan-agent/agent.

type StreamFn = (
  request: LlmRequest,
  ctx: ProviderCallContext,
) => AsyncIterable<LlmStreamEvent>;

ProviderCallContext

Stream functions receive a ProviderCallContext with:

  • signal: AbortSignal — the run-level cancellation signal.
  • run: { id, agentId, scope, cwd } — active execution metadata.
  • internal?: boolean — true when the call works on a copy of the conversation (an internal model loop). Its messages are not written to history, so a provider that keeps conversation state between calls must not advance it. Absent means a normal conversation call.
  • interact(request): Promise<JsonValue> — request live interaction from the user.
  • tools.list(): readonly LlmToolDefinition[] — registered tool definitions with metadata.
  • tools.call(name, args, options?): Promise<ToolResult> — invoke a registered tool.
    • options.signal?: AbortSignal — aborts that single tool call without cancelling the Run.
    • options.onUpdate?(toolCall: ToolCall, progress?: ToolProgress): void — receives the merged ToolCall every time it changes during execution (start, each progress-driven present update, final). The raw progress object is passed when the update was triggered by a progress report.
  • tools.report(update: ToolCall | ToolCallUpdate): void — report external tool execution.

ToolProgress

Progress reports use the standard MCP notifications/progress shape:

type ToolProgress = {
  progress: number;
  total?: number;
  message?: string;
  _meta?: JsonObject;
};
  • Shape is validated (finite numbers); invalid reports are dropped with a warning without failing the tool call.
  • Tool-private progress data goes under _meta keys.
  • Continuous output must be reported cumulatively (e.g. a tail), because transient updates coalesce per toolCallId.

Source structure

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

版本与发布记录

@rowan-agent/models 共发布 28 个版本,首次发布于 2026/06/09;过去 12 个月发布了 28 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.14.0latest2026/11/021 天前
0.13.02026/10/2410 天前
0.12.02026/10/1915 天前
0.11.02026/10/1915 天前
0.10.02026/10/1321 天前
0.9.02026/10/1321 天前

关于 @rowan-agent/models 的常见问题

@rowan-agent/models 是什么?

模型描述符、协议提供程序调度、SSE流和成本计算。代理运行时通过 ModelConfig 或者 ModelRef + StreamFn;它不依赖于代理生命周期状态。

如何安装 @rowan-agent/models?

在项目目录运行 npm install @rowan-agent/models,或使用 pnpm add / yarn add / bun add。

@rowan-agent/models 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@rowan-agent/models 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@rowan-agent/models 可以商用吗?

@rowan-agent/models 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@rowan-agent/models 还在维护吗?

最新版本 0.14.0 发布于 2026/11/02(1 天前);至今共发布 28 个版本,其中过去 12 个月发布了 28 个;首次发布于 2026/06/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。