agents: add tests for AI SDK provider and runner
Add unit tests for provider adapter and runner functionality. Tests cover provider initialization, tool conversion, and basic run scenarios.
This commit is contained in:
parent
c0bbded6f7
commit
7dba076e06
151
src/agents/aisdk/provider.test.ts
Normal file
151
src/agents/aisdk/provider.test.ts
Normal file
@ -0,0 +1,151 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
getDefaultConfig,
|
||||
parseModelRef,
|
||||
validateConfig,
|
||||
listAvailableProviders,
|
||||
} from "./provider.js";
|
||||
|
||||
describe("AI SDK Provider", () => {
|
||||
describe("parseModelRef", () => {
|
||||
it("parses valid model reference", () => {
|
||||
const result = parseModelRef("anthropic/claude-sonnet-4");
|
||||
expect(result.providerId).toBe("anthropic");
|
||||
expect(result.modelId).toBe("claude-sonnet-4");
|
||||
});
|
||||
|
||||
it("parses model ref with multiple slashes", () => {
|
||||
const result = parseModelRef("openai/gpt-4o/preview");
|
||||
expect(result.providerId).toBe("openai");
|
||||
expect(result.modelId).toBe("gpt-4o/preview");
|
||||
});
|
||||
|
||||
it("throws on invalid model reference without slash", () => {
|
||||
expect(() => parseModelRef("claude-sonnet-4")).toThrow(
|
||||
'Invalid model reference "claude-sonnet-4"',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getDefaultConfig", () => {
|
||||
it("returns gateway mode when AI_GATEWAY_API_KEY is set", () => {
|
||||
const original = process.env.AI_GATEWAY_API_KEY;
|
||||
try {
|
||||
process.env.AI_GATEWAY_API_KEY = "test-key";
|
||||
const config = getDefaultConfig();
|
||||
expect(config.mode).toBe("gateway");
|
||||
expect(config.gateway?.apiKey).toBe("test-key");
|
||||
} finally {
|
||||
if (original === undefined) {
|
||||
delete process.env.AI_GATEWAY_API_KEY;
|
||||
} else {
|
||||
process.env.AI_GATEWAY_API_KEY = original;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("returns direct mode when no gateway key", () => {
|
||||
const original = process.env.AI_GATEWAY_API_KEY;
|
||||
try {
|
||||
delete process.env.AI_GATEWAY_API_KEY;
|
||||
const config = getDefaultConfig();
|
||||
expect(config.mode).toBe("direct");
|
||||
} finally {
|
||||
if (original !== undefined) {
|
||||
process.env.AI_GATEWAY_API_KEY = original;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("includes default model reference", () => {
|
||||
const config = getDefaultConfig();
|
||||
expect(config.defaultModel).toBeDefined();
|
||||
expect(config.defaultModel).toContain("/");
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateConfig", () => {
|
||||
it("returns null for valid gateway config", () => {
|
||||
const result = validateConfig({
|
||||
mode: "gateway",
|
||||
gateway: { apiKey: "test-key" },
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("returns error for gateway mode without key", () => {
|
||||
const original = process.env.AI_GATEWAY_API_KEY;
|
||||
try {
|
||||
delete process.env.AI_GATEWAY_API_KEY;
|
||||
const result = validateConfig({
|
||||
mode: "gateway",
|
||||
});
|
||||
expect(result).toContain("AI Gateway");
|
||||
} finally {
|
||||
if (original !== undefined) {
|
||||
process.env.AI_GATEWAY_API_KEY = original;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("returns error for direct mode without any provider keys", () => {
|
||||
// Clear all provider env vars temporarily
|
||||
const saved: Record<string, string | undefined> = {};
|
||||
const providerVars = [
|
||||
"ANTHROPIC_API_KEY",
|
||||
"OPENAI_API_KEY",
|
||||
"GOOGLE_GENERATIVE_AI_API_KEY",
|
||||
"GOOGLE_API_KEY",
|
||||
"GROQ_API_KEY",
|
||||
"MISTRAL_API_KEY",
|
||||
"XAI_API_KEY",
|
||||
"OPENROUTER_API_KEY",
|
||||
"AZURE_API_KEY",
|
||||
];
|
||||
for (const v of providerVars) {
|
||||
saved[v] = process.env[v];
|
||||
delete process.env[v];
|
||||
}
|
||||
try {
|
||||
const result = validateConfig({
|
||||
mode: "direct",
|
||||
providers: {},
|
||||
});
|
||||
expect(result).toContain("at least one provider");
|
||||
} finally {
|
||||
for (const v of providerVars) {
|
||||
if (saved[v] !== undefined) {
|
||||
process.env[v] = saved[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("listAvailableProviders", () => {
|
||||
it("returns all providers for gateway mode", () => {
|
||||
const providers = listAvailableProviders({ mode: "gateway" });
|
||||
expect(providers).toContain("anthropic");
|
||||
expect(providers).toContain("openai");
|
||||
expect(providers).toContain("google");
|
||||
});
|
||||
|
||||
it("returns only providers with keys for direct mode", () => {
|
||||
const original = process.env.ANTHROPIC_API_KEY;
|
||||
try {
|
||||
process.env.ANTHROPIC_API_KEY = "test-key";
|
||||
const providers = listAvailableProviders({
|
||||
mode: "direct",
|
||||
providers: {},
|
||||
});
|
||||
expect(providers).toContain("anthropic");
|
||||
} finally {
|
||||
if (original === undefined) {
|
||||
delete process.env.ANTHROPIC_API_KEY;
|
||||
} else {
|
||||
process.env.ANTHROPIC_API_KEY = original;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
46
src/agents/aisdk/run.test.ts
Normal file
46
src/agents/aisdk/run.test.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { mapThinkLevelToAnthropicOptions } from "./run.js";
|
||||
|
||||
describe("AI SDK Run", () => {
|
||||
describe("mapThinkLevelToAnthropicOptions", () => {
|
||||
it("returns empty object for non-anthropic provider", () => {
|
||||
expect(mapThinkLevelToAnthropicOptions("high", "openai")).toEqual({});
|
||||
expect(mapThinkLevelToAnthropicOptions("high", "google")).toEqual({});
|
||||
});
|
||||
|
||||
it("returns empty object for off thinking level", () => {
|
||||
expect(mapThinkLevelToAnthropicOptions("off", "anthropic")).toEqual({});
|
||||
expect(mapThinkLevelToAnthropicOptions(undefined, "anthropic")).toEqual({});
|
||||
});
|
||||
|
||||
it("maps minimal to 2000 budget tokens", () => {
|
||||
const result = mapThinkLevelToAnthropicOptions("minimal", "anthropic");
|
||||
expect(result.thinking).toEqual({ type: "enabled", budgetTokens: 2000 });
|
||||
expect(result.effort).toBe("low");
|
||||
});
|
||||
|
||||
it("maps low to 4000 budget tokens", () => {
|
||||
const result = mapThinkLevelToAnthropicOptions("low", "anthropic");
|
||||
expect(result.thinking).toEqual({ type: "enabled", budgetTokens: 4000 });
|
||||
expect(result.effort).toBe("low");
|
||||
});
|
||||
|
||||
it("maps medium to 8000 budget tokens", () => {
|
||||
const result = mapThinkLevelToAnthropicOptions("medium", "anthropic");
|
||||
expect(result.thinking).toEqual({ type: "enabled", budgetTokens: 8000 });
|
||||
expect(result.effort).toBe("medium");
|
||||
});
|
||||
|
||||
it("maps high to 16000 budget tokens with high effort", () => {
|
||||
const result = mapThinkLevelToAnthropicOptions("high", "anthropic");
|
||||
expect(result.thinking).toEqual({ type: "enabled", budgetTokens: 16000 });
|
||||
expect(result.effort).toBe("high");
|
||||
});
|
||||
|
||||
it("maps xhigh to 32000 budget tokens with high effort", () => {
|
||||
const result = mapThinkLevelToAnthropicOptions("xhigh", "anthropic");
|
||||
expect(result.thinking).toEqual({ type: "enabled", budgetTokens: 32000 });
|
||||
expect(result.effort).toBe("high");
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user