Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ Models and Adapters for these providers are shipped out of the box:
As well as adapters for commonly supported [Open Responses](https://www.openresponses.org/) and
[OpenAI Completions](https://developers.openai.com/api/docs/guides/completions) API's so you can easily BYO models.

Provider model constructors accept options like `apiKey` and `baseUrl`. If you do not pass an API key explicitly,
Provider model factories accept options like `apiKey` and `baseUrl`. If you do not pass an API key explicitly,
provider-specific environment variables are used where supported.

```ts
import z from "npm:zod";
import { Agent, OpenAIModel, Tool } from "jsr:@alphaxiv/agents";
import { Agent, Tool } from "jsr:@alphaxiv/agents";
import { openAIModel } from "jsr:@alphaxiv/agents/openai";

const calculator = new Tool({
name: "calculator",
Expand All @@ -50,7 +51,7 @@ const calculator = new Tool({
});

const agent = new Agent({
model: new OpenAIModel({ model: "gpt-4.1-mini" }), // Or via shorthand "openai:gpt-4.1-mini"
model: openAIModel({ model: "gpt-4.1-mini" }), // Or via shorthand "openai:gpt-4.1-mini"
instructions: "You are a helpful assistant. Use the calculator when math is needed.",
tools: [calculator],
});
Expand All @@ -77,10 +78,11 @@ If you provide an `output` Zod schema, the agent guarantees that the output will

```ts
import z from "npm:zod";
import { Agent, GeminiModel } from "jsr:@alphaxiv/agents";
import { Agent } from "jsr:@alphaxiv/agents";
import { geminiModel } from "jsr:@alphaxiv/agents/gemini";

const paperExtractor = new Agent({
model: new GeminiModel({ model: "gemini-2.0-flash" }),
model: geminiModel({ model: "gemini-2.0-flash" }),
instructions: "Extract the paper title and abstract from the raw text.",
output: z.object({
title: z.string(),
Expand Down Expand Up @@ -111,7 +113,8 @@ Tool names are normalized internally so provider-specific restrictions do not le

```ts
import z from "npm:zod";
import { Agent, AnthropicModel, Tool } from "jsr:@alphaxiv/agents";
import { Agent, Tool } from "jsr:@alphaxiv/agents";
import { anthropicModel } from "jsr:@alphaxiv/agents/anthropic";

const getImage = new Tool({
name: "get_image",
Expand All @@ -131,7 +134,7 @@ const getImage = new Tool({
});

const agent = new Agent({
model: new AnthropicModel({ model: "claude-haiku-4-5" }),
model: anthropicModel({ model: "claude-haiku-4-5" }),
instructions: "You are a helpful assistant.",
tools: [getImage],
});
Expand All @@ -143,7 +146,8 @@ If a tool already knows the final answer, return `new ModelOutput(...)` to end t

```ts
import z from "npm:zod";
import { Agent, ModelOutput, OpenAIModel, Tool } from "jsr:@alphaxiv/agents";
import { Agent, ModelOutput, Tool } from "jsr:@alphaxiv/agents";
import { openAIModel } from "jsr:@alphaxiv/agents/openai";

const reportHelpfulIds = new Tool({
name: "report_helpful_ids",
Expand All @@ -155,7 +159,7 @@ const reportHelpfulIds = new Tool({
});

const agent = new Agent({
model: new OpenAIModel({ model: "gpt-4.1-mini" }),
model: openAIModel({ model: "gpt-4.1-mini" }),
instructions: "Find relevant ids, then call report_helpful_ids.",
tools: [reportHelpfulIds],
});
Expand All @@ -173,12 +177,14 @@ type that occured and will automatically determine whether to retry, fallback to
differently.

```ts
import { Agent, AnthropicModel, OpenAIModel } from "jsr:@alphaxiv/agents";
import { Agent } from "jsr:@alphaxiv/agents";
import { anthropicModel } from "jsr:@alphaxiv/agents/anthropic";
import { openAIModel } from "jsr:@alphaxiv/agents/openai";

const agent = new Agent({
model: [
new OpenAIModel({ model: "gpt-4.1-mini" }),
new AnthropicModel({ model: "claude-haiku-4-5" }),
openAIModel({ model: "gpt-4.1-mini" }),
anthropicModel({ model: "claude-haiku-4-5" }),
],
instructions: "You are a reliable assistant.",
});
Expand All @@ -191,8 +197,8 @@ You can customize the retry strategy to match your needs:
```ts
const agent = new Agent({
model: [
new OpenAIModel({ model: "gpt-5.4-mini" }),
new AnthropicModel({ model: "claude-haiku-4-5" }),
openAIModel({ model: "gpt-5.4-mini" }),
anthropicModel({ model: "claude-haiku-4-5" }),
],
instructions: "You are a helpful assistant.",
retryStrategy: {
Expand Down Expand Up @@ -237,10 +243,11 @@ Use `agent.stream(...)` when you want token-by-token output, reasoning deltas, a

```ts
import process from "node:process";
import { Agent, OpenAIModel } from "jsr:@alphaxiv/agents";
import { Agent } from "jsr:@alphaxiv/agents";
import { openAIModel } from "jsr:@alphaxiv/agents/openai";

const agent = new Agent({
model: new OpenAIModel({ model: "gpt-5.4-mini" }),
model: openAIModel({ model: "gpt-5.4-mini" }),
instructions: "You are a helpful assistant.",
});

Expand Down Expand Up @@ -268,7 +275,8 @@ Built-in way to convert agents into a CLI app.

```ts
import z from "npm:zod";
import { Agent, cli, OpenAIModel, Tool } from "jsr:@alphaxiv/agents";
import { Agent, cli, Tool } from "jsr:@alphaxiv/agents";
import { openAIModel } from "jsr:@alphaxiv/agents/openai";

const echo = new Tool({
name: "echo",
Expand All @@ -278,7 +286,7 @@ const echo = new Tool({
});

const agent = new Agent({
model: new OpenAIModel({ model: "gpt-4.1-mini" }),
model: openAIModel({ model: "gpt-4.1-mini" }),
instructions: "You are a helpful assistant.",
tools: [echo],
});
Expand All @@ -299,10 +307,11 @@ The built-in CLI supports:
Pass files directly as chat items.

```ts
import { Agent, OpenRouterModel } from "jsr:@alphaxiv/agents";
import { Agent } from "jsr:@alphaxiv/agents";
import { openrouterModel } from "jsr:@alphaxiv/agents/openrouter";

const agent = new Agent({
model: new OpenRouterModel({ model: "openrouter:meta-llama/llama-4-maverick" }),
model: openrouterModel({ model: "meta-llama/llama-4-maverick" }),
instructions: "You are a helpful assistant.",
});

Expand Down
45 changes: 20 additions & 25 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alphaxiv/agents",
"version": "0.5.11",
"version": "0.6.0",
"license": "MIT",
"fmt": {
"lineWidth": 120
Expand All @@ -10,31 +10,17 @@
"./cli": "./src/cli.ts",
"./client": "./src/client.ts",

"./adapters/anthropic": "./src/adapters/anthropic/adapter.ts",
"./anthropic": "./src/adapters/anthropic/model.ts",
"./anthropic": "./src/adapters/anthropic/adapter.ts",
"./google-genai": "./src/adapters/google_genai/adapter.ts",
"./gemini": "./src/adapters/gemini/adapter.ts",
"./vertex-ai": "./src/adapters/vertex_ai/adapter.ts",
"./openai_completions": "./src/adapters/openai_completions/adapter.ts",
"./open_responses": "./src/adapters/open_responses/adapter.ts",
"./openrouter": "./src/adapters/openrouter/adapter.ts",
"./tributary": "./src/adapters/tributary/adapter.ts",
"./openai": "./src/adapters/openai/adapter.ts",
"./sid": "./src/adapters/sid/adapter.ts",

"./adapters/google-genai": "./src/adapters/google_genai/adapter.ts",

"./adapters/gemini": "./src/adapters/gemini/adapter.ts",
"./gemini": "./src/adapters/gemini/model.ts",

"./adapters/vertex-ai": "./src/adapters/vertex_ai/adapter.ts",
"./vertex-ai": "./src/adapters/vertex_ai/model.ts",

"./adapters/openai_completions": "./src/adapters/openai_completions/adapter.ts",
"./adapters/open_responses": "./src/adapters/open_responses/adapter.ts",

"./adapters/openrouter": "./src/adapters/openrouter/adapter.ts",
"./openrouter": "./src/adapters/openrouter/model.ts",

"./adapters/tributary": "./src/adapters/tributary/adapter.ts",
"./tributary": "./src/adapters/tributary/model.ts",

"./adapters/openai": "./src/adapters/openai/adapter.ts",
"./openai": "./src/adapters/openai/model.ts",

"./adapters/sid": "./src/adapters/sid/adapter.ts",
"./sid": "./src/adapters/sid/model.ts",
"./sid/tools": "./src/adapters/sid/tools.ts"
},
"tasks": {
Expand All @@ -55,5 +41,14 @@
"@std/uuid": "jsr:@std/uuid@^1.1.0",
"openai": "npm:openai@^6.33.0",
"zod": "npm:zod@^4.3.6"
},
"publish": {
"include": [
"LICENSE",
"README.md",
"mod.ts",
"src/**/*.ts",
"tests/**/*.ts"
]
}
}
47 changes: 47 additions & 0 deletions examples/custom-providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Agent } from "@alphaxiv/agents";
import { openResponsesModel } from "@alphaxiv/agents/open_responses";
import { openAICompletionsModel } from "@alphaxiv/agents/openai_completions";

// OpenAI chat completions
{
const model = openAICompletionsModel({
model: "qwen/qwen3-coder-next",
openAIOptions: {
baseURL: "http://localhost:1234/v1",
apiKey: "n/a",
},
});

const agent = new Agent({
model,
instructions: "you say the number 8",
});

const result = await agent.run(
`On a scale of 1 to 10 how would you rate the JSR package @alphaxiv/agents`,
);

console.log(result);
}

// For LMStudio, prefer open responses so you get reasoning
{
const model = openResponsesModel({
model: "qwen/qwen3-coder-next",
openAIOptions: {
baseURL: "http://localhost:1234/v1",
apiKey: "n/a",
},
});

const agent = new Agent({
model,
instructions: "you say the number 8",
});

const result = await agent.run(
`On a scale of 1 to 10 how would you rate the JSR package @alphaxiv/agents`,
);

console.log(result);
}
10 changes: 5 additions & 5 deletions examples/tracing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import process from "node:process";
import z from "zod";
import {
Agent,
AnthropicModel,
type ChatItem,
OpenAIModel,
type PartialTraceEvent,
registerGlobalTracer,
Tool,
type TraceEvent,
withTrace,
} from "../mod.ts";
import { anthropicModel } from "@alphaxiv/agents/anthropic";
import { openAIModel } from "@alphaxiv/agents/openai";

const snackMenu = [
{ name: "miso ramen cup", calories: 420, prepMinutes: 6, price: 8 },
Expand Down Expand Up @@ -70,8 +70,8 @@ async function main() {
const subagent = new Agent({
name: "Snack Specialist",
model: [
new OpenAIModel({ model: "gpt-5.4-nano" }),
new AnthropicModel({ model: "claude-sonnet-4-6", thinkingLevel: "adaptive" }),
openAIModel({ model: "gpt-5.4-nano" }),
anthropicModel({ model: "claude-sonnet-4-6", thinkingLevel: "adaptive" }),
],
instructions: [
"You are the snack specialist.",
Expand Down Expand Up @@ -101,7 +101,7 @@ async function main() {

const agent = new Agent({
name: "Main Agent",
model: new AnthropicModel({ model: "claude-sonnet-4-6", thinkingLevel: "adaptive" }),
model: anthropicModel({ model: "claude-sonnet-4-6", thinkingLevel: "adaptive" }),
instructions: [
"You coordinate requests for a snack specialist.",
"Always call delegate_specialist exactly once before answering.",
Expand Down
25 changes: 2 additions & 23 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,12 @@ export type { CliIo, CliOptions } from "./src/cli.ts";
export { ModelOutput, Tool } from "./src/tool.ts";
export type { AnyTool, ExecuteContext, ExecuteFunc, ExecuteFuncInput, ExecuteResult } from "./src/tool.ts";

export { Adapter } from "./src/adapters/adapter.ts";
export type { Adapter } from "./src/adapters/adapter.ts";
export type { AdapterOptions, AdapterStreamOptions } from "./src/adapters/adapter.ts";

export { Model } from "./src/adapters/model.ts";
export type { ModelOptions } from "./src/adapters/model.ts";

export { resolveModel } from "./src/adapters/model_resolver.ts";
export type { ModelLike, ModelString } from "./src/adapters/model_resolver.ts";
export type { AdapterLike, ModelString } from "./src/adapters/model_resolver.ts";

export { AnthropicModel } from "./src/adapters/anthropic/model.ts";
export type { AnthropicModelOptions } from "./src/adapters/anthropic/model.ts";
export type {
AnthropicModels,
EffortLevel,
Expand All @@ -42,32 +37,16 @@ export type {
ThinkingLevel,
} from "./src/adapters/anthropic/models.ts";

export { GeminiModel } from "./src/adapters/gemini/model.ts";
export type { GeminiModelOptions } from "./src/adapters/gemini/model.ts";

export { OpenAIModel } from "./src/adapters/openai/model.ts";
export type { OpenAIModelOptions } from "./src/adapters/openai/model.ts";
export type {
OpenAIModelModality,
OpenAIModels,
OpenAIReasoningEffort,
SupportedReasoningEffort,
} from "./src/adapters/openai/models.ts";

export { OpenRouterModel } from "./src/adapters/openrouter/model.ts";
export type { OpenRouterModelOptions } from "./src/adapters/openrouter/model.ts";
export type { OpenRouterModels, OpenRouterReasoningEffort } from "./src/adapters/openrouter/models.ts";

export type { SidModels } from "./src/adapters/sid/adapter.ts";
export { SidModel } from "./src/adapters/sid/model.ts";
export type { SidModelOptions } from "./src/adapters/sid/model.ts";

export { TributaryModel } from "./src/adapters/tributary/model.ts";
export type { TributaryModelOptions } from "./src/adapters/tributary/model.ts";
export type { TributaryModels } from "./src/adapters/tributary/models.ts";

export { VertexAiModel } from "./src/adapters/vertex_ai/model.ts";
export type { VertexAiModelOptions, VertexAiModelPriority } from "./src/adapters/vertex_ai/model.ts";

export { SidEmbeddingSearchTool, SidReportHelpfulIdsTool, SidTextSearchTool } from "./src/adapters/sid/tools.ts";

Expand Down
21 changes: 9 additions & 12 deletions src/adapters/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,13 @@ export interface AdapterStreamOptions<zO, zI> {
signal: AbortSignal;
}

export abstract class Adapter<SupportedModels extends string> {
abstract name: string;
model: SupportedModels;

constructor(options: AdapterOptions<SupportedModels>) {
this.model = options.model;
}

abstract stream<zO, zI>(options: AdapterStreamOptions<zO, zI>): AdapterStreamIterator;

export type Adapter<zO, zI> = {
/** Name of the provider */
provider: string;
/** Name of the model on the provider */
model: string;
/** Function to actually stream the results */
stream: (options: AdapterStreamOptions<zO, zI>) => AdapterStreamIterator;
/**
* Classify an error using provider-specific error types.
* Override this in adapter implementations to provide precise error classification.
Expand All @@ -41,5 +38,5 @@ export abstract class Adapter<SupportedModels extends string> {
* @param error The error thrown during a model call
* @returns ClassifiedError if the adapter can classify it, null to fall back to heuristics
*/
classifyError?(error: unknown): ClassifiedError | null;
}
classifyError?: (error: unknown) => ClassifiedError | null;
};
Loading
Loading