support jev

This commit is contained in:
Frank
2026-09-18 11:57:10 -04:00
parent 3dd1b30539
commit 1573a7b608
8 changed files with 103 additions and 1 deletions
@@ -8,9 +8,11 @@ const paths: Record<string, string | undefined> = {
"POST /zen/v1/chat/completions": "/openai/v1/chat/completions",
"POST /zen/v1/responses": "/openai/v1/responses",
"POST /zen/v1/messages": "/anthropic/v1/messages",
"POST /zen/systemone/v1/systemone": "/systemone/v1/systemone",
"POST /zen/go/v1/chat/completions": "/go/openai/v1/chat/completions",
"POST /zen/go/v1/responses": "/go/openai/v1/responses",
"POST /zen/go/v1/messages": "/go/anthropic/v1/messages",
"POST /zen/go/systemone/v1/systemone": "/go/systemone/v1/systemone",
"GET /zen/v1/models": "/v1/models",
"GET /zen/go/v1/models": "/go/v1/models",
"GET /zen/go/v1/usage": "/go/v1/usage",
@@ -0,0 +1,13 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/routes/zen/util/handler"
export function POST(input: APIEvent) {
return handler(input, {
format: "systemone",
modelList: "lite",
parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1],
parseModel: (url: string, body: any) => body.model,
parseVariant: () => undefined,
parseIsStream: () => false,
})
}
@@ -0,0 +1,13 @@
import type { APIEvent } from "@solidjs/start/server"
import { handler } from "~/routes/zen/util/handler"
export function POST(input: APIEvent) {
return handler(input, {
format: "systemone",
modelList: "full",
parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1],
parseModel: (url: string, body: any) => body.model,
parseVariant: () => undefined,
parseIsStream: () => false,
})
}
@@ -33,6 +33,7 @@ import { anthropicHelper } from "./provider/anthropic"
import { googleHelper } from "./provider/google"
import { openaiHelper } from "./provider/openai"
import { oaCompatHelper } from "./provider/openai-compatible"
import { systemoneHelper } from "./provider/systemone"
import { createRateLimiter as createIpRateLimiter } from "./ipRateLimiter"
import { createRateLimiter as createKeyRateLimiter } from "./keyRateLimiter"
import { createTrialLimiter } from "./trialLimiter"
@@ -685,6 +686,7 @@ export async function handler(
if (format === "anthropic") return anthropicHelper(opts)
if (format === "google") return googleHelper(opts)
if (format === "openai") return openaiHelper(opts)
if (format === "systemone") return systemoneHelper(opts)
return oaCompatHelper(opts)
})(),
}
@@ -0,0 +1,30 @@
import { ProviderHelper } from "./provider"
type Usage = {
input_tokens?: number
output_tokens?: number
}
export const systemoneHelper: ProviderHelper = () => ({
format: "systemone",
modifyUrl: (providerApi: string) => providerApi.replace(/\/$/, "") + "/systemone",
modifyHeaders: (headers: Headers, apiKey: string, stickyId: string) => {
headers.set("authorization", `Bearer ${apiKey}`)
headers.set("x-session-affinity", stickyId)
},
modifyBody: (body: Record<string, any>) => body,
createBinaryStreamDecoder: () => undefined,
createUsageParser: () => ({
parse: (_chunk: string) => {},
retrieve: () => undefined,
}),
extractUsage: (response: any) => response.usage,
normalizeUsage: (usage: Usage) => ({
inputTokens: usage.input_tokens ?? 0,
outputTokens: usage.output_tokens ?? 0,
reasoningTokens: undefined,
cacheReadTokens: undefined,
cacheWrite5mTokens: undefined,
cacheWrite1hTokens: undefined,
}),
})
@@ -5,15 +5,27 @@ import { anthropicHelper } from "../src/routes/zen/util/provider/anthropic"
import { googleHelper } from "../src/routes/zen/util/provider/google"
import { oaCompatHelper } from "../src/routes/zen/util/provider/openai-compatible"
import { openaiHelper } from "../src/routes/zen/util/provider/openai"
import { systemoneHelper } from "../src/routes/zen/util/provider/systemone"
const providers = {
anthropic: anthropicHelper({ reqModel: "claude-haiku-4-5", providerModel: "claude-haiku-4-5" }),
google: googleHelper({ reqModel: "gemini-3-flash", providerModel: "gemini-3-flash" }),
openai: openaiHelper({ reqModel: "gpt-5", providerModel: "gpt-5" }),
"oa-compat": oaCompatHelper({ reqModel: "gpt-5-nano", providerModel: "gpt-5-nano" }),
systemone: systemoneHelper({ reqModel: "jev-1.13", providerModel: "jev-latest" }),
} satisfies Record<ZenData.Format, ReturnType<ProviderHelper>>
describe("provider usage extraction", () => {
test("prepares SystemOne requests", () => {
const headers = new Headers()
providers.systemone.modifyHeaders(headers, "secret", "session")
expect(providers.systemone.modifyUrl("https://api.typesafe.ai/v1/"))
.toBe("https://api.typesafe.ai/v1/systemone")
expect(headers.get("authorization")).toBe("Bearer secret")
expect(headers.get("x-session-affinity")).toBe("session")
})
test("extracts Google non-stream usage metadata", () => {
const usage = providers.google.extractUsage({
usageMetadata: {
@@ -66,6 +78,21 @@ describe("provider usage extraction", () => {
})
})
test("extracts SystemOne usage", () => {
expect(
providers.systemone.normalizeUsage(
providers.systemone.extractUsage({ usage: { input_tokens: 312, output_tokens: 48 } }),
),
).toEqual({
inputTokens: 312,
outputTokens: 48,
reasoningTokens: undefined,
cacheReadTokens: undefined,
cacheWrite5mTokens: undefined,
cacheWrite1hTokens: undefined,
})
})
test("parses OpenAI stream cache write usage", () => {
const usageParser = providers.openai.createUsageParser()
usageParser.parse(
+1 -1
View File
@@ -8,7 +8,7 @@ import { Actor } from "./actor"
import { Resource } from "@opencode-ai/console-resource"
export namespace ZenData {
const FormatSchema = z.enum(["anthropic", "google", "openai", "oa-compat"])
const FormatSchema = z.enum(["anthropic", "google", "openai", "oa-compat", "systemone"])
export type Format = z.infer<typeof FormatSchema>
const ModelCostSchema = z.object({
+15
View File
@@ -47,3 +47,18 @@ describe("ZenData cost200K threshold", () => {
expect(entry(data).cost200K?.threshold).toBe(272_000)
})
})
test("accepts the SystemOne provider format", () => {
expect(
ZenData.validate({
...base,
providers: {
systemone: {
api: "https://api.typesafe.ai/v1",
apiKey: "test",
format: "systemone",
},
},
}).providers.systemone.format,
).toBe("systemone")
})