From 80e73f5727ab5fe1902fabf3d6ca17380f58d555 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Apr 2026 13:10:42 +0000 Subject: [PATCH 001/146] @CHLK has signed the CLA in code-yeongyu/oh-my-openagent#3455 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index e16dee644..c39cbfbdb 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2831,6 +2831,14 @@ "created_at": "2026-04-15T05:03:42Z", "repoId": 1108837393, "pullRequestNo": 3440 + }, + { + "name": "CHLK", + "id": 30882682, + "comment_id": 4252344048, + "created_at": "2026-04-15T13:10:30Z", + "repoId": 1108837393, + "pullRequestNo": 3455 } ] } \ No newline at end of file From a1842f2de7ae25a1a01bf93a1ed82e21998dd340 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 13:51:58 +0900 Subject: [PATCH 002/146] feat(tool-metadata): add shared metadata contract and bridge Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/features/tool-metadata-store/index.ts | 7 + .../tool-metadata-store/integration.test.ts | 96 ++++++++++++ .../publish-tool-metadata.test.ts | 76 +++++++++ .../publish-tool-metadata.ts | 28 ++++ .../recover-tool-metadata.test.ts | 47 ++++++ .../recover-tool-metadata.ts | 18 +++ .../resolve-tool-call-id.test.ts | 88 +++++++++++ .../resolve-tool-call-id.ts | 26 ++++ .../task-metadata-contract.test.ts | 116 ++++++++++++++ .../task-metadata-contract.ts | 144 ++++++++++++++++++ 10 files changed, 646 insertions(+) create mode 100644 src/features/tool-metadata-store/integration.test.ts create mode 100644 src/features/tool-metadata-store/publish-tool-metadata.test.ts create mode 100644 src/features/tool-metadata-store/publish-tool-metadata.ts create mode 100644 src/features/tool-metadata-store/recover-tool-metadata.test.ts create mode 100644 src/features/tool-metadata-store/recover-tool-metadata.ts create mode 100644 src/features/tool-metadata-store/resolve-tool-call-id.test.ts create mode 100644 src/features/tool-metadata-store/resolve-tool-call-id.ts create mode 100644 src/features/tool-metadata-store/task-metadata-contract.test.ts create mode 100644 src/features/tool-metadata-store/task-metadata-contract.ts diff --git a/src/features/tool-metadata-store/index.ts b/src/features/tool-metadata-store/index.ts index f9c4e28ad..cc89a9f72 100644 --- a/src/features/tool-metadata-store/index.ts +++ b/src/features/tool-metadata-store/index.ts @@ -5,3 +5,10 @@ export { storeToolMetadata, } from "./store" export type { PendingToolMetadata } from "./store" +export { resolveToolCallID } from "./resolve-tool-call-id" +export type { ToolCallIDCarrier } from "./resolve-tool-call-id" +export { buildTaskMetadataBlock, extractTaskLink, parseTaskMetadataBlock } from "./task-metadata-contract" +export type { TaskLink } from "./task-metadata-contract" +export { publishToolMetadata } from "./publish-tool-metadata" +export { recoverToolMetadata } from "./recover-tool-metadata" +export type { ToolMetadataPublisherContext } from "./publish-tool-metadata" diff --git a/src/features/tool-metadata-store/integration.test.ts b/src/features/tool-metadata-store/integration.test.ts new file mode 100644 index 000000000..2604a5edf --- /dev/null +++ b/src/features/tool-metadata-store/integration.test.ts @@ -0,0 +1,96 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +import { clearPendingStore, getPendingStoreSize } from "./store" +import { publishToolMetadata } from "./publish-tool-metadata" +import { recoverToolMetadata } from "./recover-tool-metadata" + +describe("tool-metadata-store integration", () => { + beforeEach(() => { + clearPendingStore() + }) + + test("#given stored metadata #when publishing then recovering #then the round trip preserves the payload", async () => { + // given + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_123" }, payload) + const recovered = recoverToolMetadata("ses_parent", { callID: "call_123" }) + + // then + expect(recovered).toEqual(payload) + }) + + test("#given call id casing mismatch #when publishing and recovering #then canonical resolution still matches", async () => { + // given + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + await publishToolMetadata({ sessionID: "ses_parent", callId: "call_case" }, payload) + const recovered = recoverToolMetadata("ses_parent", { callID: "call_case" }) + + // then + expect(recovered).toEqual(payload) + }) + + test("#given blank call id #when publishing #then nothing is stored", async () => { + // given + const payload = { title: "Task" } + + // when + const result = await publishToolMetadata({ sessionID: "ses_parent", callID: " " }, payload) + const recovered = recoverToolMetadata("ses_parent", { callID: "call_blank" }) + + // then + expect(result).toEqual({ stored: false }) + expect(recovered).toBeUndefined() + expect(getPendingStoreSize()).toBe(0) + }) + + test("#given missing call id #when publishing #then nothing is stored", async () => { + // given + const payload = { title: "Task" } + + // when + const result = await publishToolMetadata({ sessionID: "ses_parent" }, payload) + + // then + expect(result).toEqual({ stored: false }) + expect(getPendingStoreSize()).toBe(0) + }) + + test("#given same session with different call ids #when publishing twice #then each entry stays isolated", async () => { + // given + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_a" }, { title: "A" }) + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_b" }, { title: "B" }) + + // when + const recoveredA = recoverToolMetadata("ses_parent", { callID: "call_a" }) + const recoveredB = recoverToolMetadata("ses_parent", { callID: "call_b" }) + + // then + expect(recoveredA).toEqual({ title: "A" }) + expect(recoveredB).toEqual({ title: "B" }) + }) + + test("#given stale metadata #when a fresh entry is stored after the timeout #then stale entries are cleaned up", async () => { + // given + const originalDateNow = Date.now + let now = 0 + Date.now = () => now + + try { + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_old" }, { title: "Old" }) + now = 15 * 60 * 1000 + 1 + + // when + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_new" }, { title: "New" }) + + // then + expect(recoverToolMetadata("ses_parent", { callID: "call_old" })).toBeUndefined() + expect(recoverToolMetadata("ses_parent", { callID: "call_new" })).toEqual({ title: "New" }) + } finally { + Date.now = originalDateNow + } + }) +}) diff --git a/src/features/tool-metadata-store/publish-tool-metadata.test.ts b/src/features/tool-metadata-store/publish-tool-metadata.test.ts new file mode 100644 index 000000000..704fe2392 --- /dev/null +++ b/src/features/tool-metadata-store/publish-tool-metadata.test.ts @@ -0,0 +1,76 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +import { clearPendingStore, consumeToolMetadata } from "./store" +import { publishToolMetadata } from "./publish-tool-metadata" + +describe("publishToolMetadata", () => { + beforeEach(() => { + clearPendingStore() + }) + + test("#given metadata context and call id #when publishing #then it awaits metadata and stores the payload", async () => { + // given + const calls: string[] = [] + let metadataFinished = false + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + const result = await publishToolMetadata( + { + sessionID: "ses_parent", + callID: "call_123", + metadata: async input => { + calls.push(input.title ?? "") + await new Promise(resolve => setTimeout(resolve, 1)) + metadataFinished = true + }, + }, + payload + ) + + // then + expect(result).toEqual({ stored: true }) + expect(metadataFinished).toBe(true) + expect(calls).toEqual(["Task"]) + expect(consumeToolMetadata("ses_parent", "call_123")).toEqual(payload) + }) + + test("#given legacy call id variant #when publishing #then it stores with the canonical resolver", async () => { + // given + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + const result = await publishToolMetadata( + { + sessionID: "ses_parent", + callId: " call_legacy ", + }, + payload + ) + + // then + expect(result).toEqual({ stored: true }) + expect(consumeToolMetadata("ses_parent", "call_legacy")).toEqual(payload) + }) + + test("#given missing call id #when publishing #then it still emits metadata but skips storing", async () => { + // given + let metadataCalls = 0 + + // when + const result = await publishToolMetadata( + { + sessionID: "ses_parent", + metadata: () => { + metadataCalls += 1 + }, + }, + { title: "Task" } + ) + + // then + expect(result).toEqual({ stored: false }) + expect(metadataCalls).toBe(1) + expect(consumeToolMetadata("ses_parent", "call_missing")).toBeUndefined() + }) +}) diff --git a/src/features/tool-metadata-store/publish-tool-metadata.ts b/src/features/tool-metadata-store/publish-tool-metadata.ts new file mode 100644 index 000000000..84e69155e --- /dev/null +++ b/src/features/tool-metadata-store/publish-tool-metadata.ts @@ -0,0 +1,28 @@ +import { log } from "../../shared/logger" +import { resolveToolCallID, type ToolCallIDCarrier } from "./resolve-tool-call-id" +import { storeToolMetadata, type PendingToolMetadata } from "./store" + +export interface ToolMetadataPublisherContext extends ToolCallIDCarrier { + sessionID: string + metadata?: (input: PendingToolMetadata) => void | Promise +} + +export async function publishToolMetadata( + ctx: ToolMetadataPublisherContext, + payload: PendingToolMetadata +): Promise<{ stored: boolean }> { + await ctx.metadata?.(payload) + + const callID = resolveToolCallID(ctx) + if (!callID) { + log("[tool-metadata-store] Skipping metadata store publish because tool call ID is unavailable", { + sessionID: ctx.sessionID, + hasTitle: typeof payload.title === "string", + hasMetadata: payload.metadata !== undefined, + }) + return { stored: false } + } + + storeToolMetadata(ctx.sessionID, callID, payload) + return { stored: true } +} diff --git a/src/features/tool-metadata-store/recover-tool-metadata.test.ts b/src/features/tool-metadata-store/recover-tool-metadata.test.ts new file mode 100644 index 000000000..e97e87eea --- /dev/null +++ b/src/features/tool-metadata-store/recover-tool-metadata.test.ts @@ -0,0 +1,47 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +import { recoverToolMetadata } from "./recover-tool-metadata" +import { clearPendingStore, storeToolMetadata } from "./store" + +describe("recoverToolMetadata", () => { + beforeEach(() => { + clearPendingStore() + }) + + test("#given stored metadata and call id variant #when recovering #then it finds the stored payload", () => { + // given + const payload = { title: "Recovered", metadata: { sessionId: "ses_child" } } + storeToolMetadata("ses_parent", "call_123", payload) + + // when + const recovered = recoverToolMetadata("ses_parent", { callId: " call_123 " }) + + // then + expect(recovered).toEqual(payload) + }) + + test("#given direct string call id #when recovering #then it consumes the stored payload", () => { + // given + const payload = { title: "Recovered" } + storeToolMetadata("ses_parent", "call_456", payload) + + // when + const recovered = recoverToolMetadata("ses_parent", "call_456") + + // then + expect(recovered).toEqual(payload) + }) + + test("#given missing or blank call id #when recovering #then it returns undefined", () => { + // given + storeToolMetadata("ses_parent", "call_789", { title: "Recovered" }) + + // when + const missing = recoverToolMetadata("ses_parent", undefined) + const blank = recoverToolMetadata("ses_parent", { callID: " " }) + + // then + expect(missing).toBeUndefined() + expect(blank).toBeUndefined() + }) +}) diff --git a/src/features/tool-metadata-store/recover-tool-metadata.ts b/src/features/tool-metadata-store/recover-tool-metadata.ts new file mode 100644 index 000000000..17a2278e6 --- /dev/null +++ b/src/features/tool-metadata-store/recover-tool-metadata.ts @@ -0,0 +1,18 @@ +import { consumeToolMetadata, type PendingToolMetadata } from "./store" +import { resolveToolCallID, type ToolCallIDCarrier } from "./resolve-tool-call-id" + +export function recoverToolMetadata( + sessionID: string, + source: ToolCallIDCarrier | string | undefined +): PendingToolMetadata | undefined { + if (typeof source === "string") { + return consumeToolMetadata(sessionID, source) + } + + const callID = source ? resolveToolCallID(source) : undefined + if (!callID) { + return undefined + } + + return consumeToolMetadata(sessionID, callID) +} diff --git a/src/features/tool-metadata-store/resolve-tool-call-id.test.ts b/src/features/tool-metadata-store/resolve-tool-call-id.test.ts new file mode 100644 index 000000000..2ad63a516 --- /dev/null +++ b/src/features/tool-metadata-store/resolve-tool-call-id.test.ts @@ -0,0 +1,88 @@ +import { describe, expect, test } from "bun:test" + +import { resolveToolCallID, type ToolCallIDCarrier } from "./resolve-tool-call-id" + +describe("resolveToolCallID", () => { + function makeCtx(overrides: Partial = {}): ToolCallIDCarrier { + return { + ...overrides, + } + } + + test("#given callID is set #when resolving #then it returns callID", () => { + // given + const ctx = makeCtx({ callID: "call_abc" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_abc") + }) + + test("#given only callId is set #when resolving #then it returns callId", () => { + // given + const ctx = makeCtx({ callId: "call_def" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_def") + }) + + test("#given only call_id is set #when resolving #then it returns call_id", () => { + // given + const ctx = makeCtx({ call_id: "call_ghi" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_ghi") + }) + + test("#given surrounding whitespace #when resolving #then it trims the value", () => { + // given + const ctx = makeCtx({ callID: " call_trimmed " }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_trimmed") + }) + + test("#given blank callID #when resolving #then it returns undefined", () => { + // given + const ctx = makeCtx({ callID: "" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBeUndefined() + }) + + test("#given whitespace callID #when resolving #then it returns undefined", () => { + // given + const ctx = makeCtx({ callID: " " }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBeUndefined() + }) + + test("#given no call id variants #when resolving #then it returns undefined", () => { + // given + const ctx = makeCtx() + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBeUndefined() + }) +}) diff --git a/src/features/tool-metadata-store/resolve-tool-call-id.ts b/src/features/tool-metadata-store/resolve-tool-call-id.ts new file mode 100644 index 000000000..d5879ae5f --- /dev/null +++ b/src/features/tool-metadata-store/resolve-tool-call-id.ts @@ -0,0 +1,26 @@ +import { log } from "../../shared/logger" + +export interface ToolCallIDCarrier { + callID?: string + callId?: string + call_id?: string +} + +function normalizeCallID(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined + } + + const trimmed = value.trim() + return trimmed === "" ? undefined : trimmed +} + +export function resolveToolCallID(ctx: ToolCallIDCarrier): string | undefined { + const resolved = normalizeCallID(ctx.callID) ?? normalizeCallID(ctx.callId) ?? normalizeCallID(ctx.call_id) + + if (!resolved) { + log("[tool-metadata-store] Missing tool call ID for metadata correlation") + } + + return resolved +} diff --git a/src/features/tool-metadata-store/task-metadata-contract.test.ts b/src/features/tool-metadata-store/task-metadata-contract.test.ts new file mode 100644 index 000000000..2cf2aaa7c --- /dev/null +++ b/src/features/tool-metadata-store/task-metadata-contract.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, test } from "bun:test" + +import { buildTaskMetadataBlock, extractTaskLink, parseTaskMetadataBlock } from "./task-metadata-contract" + +describe("buildTaskMetadataBlock", () => { + test("#given only session id #when building #then it preserves the frozen block format", () => { + // given + const link = { sessionId: "ses_abc" } + + // when + const block = buildTaskMetadataBlock(link) + + // then + expect(block).toBe("\nsession_id: ses_abc\n") + }) + + test("#given extended task metadata #when building #then it emits optional lines in order", () => { + // given + const link = { + sessionId: "ses_bg_123", + taskId: "bg_123", + backgroundTaskId: "bg_123", + agent: "explore", + category: "quick", + } + + // when + const block = buildTaskMetadataBlock(link) + + // then + expect(block).toBe( + "\nsession_id: ses_bg_123\ntask_id: bg_123\nbackground_task_id: bg_123\nsubagent: explore\ncategory: quick\n" + ) + }) +}) + +describe("parseTaskMetadataBlock", () => { + test("#given a task metadata block #when parsing #then it extracts the structured link", () => { + // given + const text = "\nsession_id: ses_sync_123\ntask_id: task_123\nbackground_task_id: bg_123\nsubagent: oracle\ncategory: deep\n" + + // when + const parsed = parseTaskMetadataBlock(text) + + // then + expect(parsed).toEqual({ + sessionId: "ses_sync_123", + taskId: "task_123", + backgroundTaskId: "bg_123", + agent: "oracle", + category: "deep", + }) + }) + + test("#given text without metadata #when parsing #then it returns an empty link", () => { + // given + const text = "Task completed without metadata" + + // when + const parsed = parseTaskMetadataBlock(text) + + // then + expect(parsed).toEqual({}) + }) +}) + +describe("extractTaskLink", () => { + test("#given metadata session aliases #when extracting #then metadata wins over output text", () => { + // given + const metadata = { + sessionID: "ses_meta_123", + task_id: "task_meta_123", + background_task_id: "bg_meta_123", + subagent: "atlas", + category: "unspecified-high", + } + const output = "\nsession_id: ses_text_456\n" + + // when + const extracted = extractTaskLink(metadata, output) + + // then + expect(extracted).toEqual({ + sessionId: "ses_meta_123", + taskId: "task_meta_123", + backgroundTaskId: "bg_meta_123", + agent: "atlas", + category: "unspecified-high", + }) + }) + + test("#given missing metadata #when extracting #then it falls back to task metadata text", () => { + // given + const output = "Task completed.\n\n\nsession_id: ses_text_456\nsubagent: oracle\n" + + // when + const extracted = extractTaskLink(undefined, output) + + // then + expect(extracted).toEqual({ + sessionId: "ses_text_456", + agent: "oracle", + }) + }) + + test("#given explicit session id output #when extracting #then it preserves Session ID compatibility", () => { + // given + const output = "Background task launched.\n\nSession ID: ses_bg_789" + + // when + const extracted = extractTaskLink(undefined, output) + + // then + expect(extracted).toEqual({ sessionId: "ses_bg_789" }) + }) +}) diff --git a/src/features/tool-metadata-store/task-metadata-contract.ts b/src/features/tool-metadata-store/task-metadata-contract.ts new file mode 100644 index 000000000..4044482e5 --- /dev/null +++ b/src/features/tool-metadata-store/task-metadata-contract.ts @@ -0,0 +1,144 @@ +import { log } from "../../shared/logger" + +export interface TaskLink { + sessionId?: string + taskId?: string + backgroundTaskId?: string + agent?: string + category?: string +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + +function readString(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined + } + + const trimmed = value.trim() + return trimmed === "" ? undefined : trimmed +} + +function readSessionIdFromMetadata(metadata: Record): string | undefined { + return readString(metadata.sessionId) ?? readString(metadata.sessionID) ?? readString(metadata.session_id) +} + +function readTaskIdFromMetadata(metadata: Record): string | undefined { + return readString(metadata.taskId) ?? readString(metadata.taskID) ?? readString(metadata.task_id) +} + +function readBackgroundTaskIdFromMetadata(metadata: Record): string | undefined { + return readString(metadata.backgroundTaskId) + ?? readString(metadata.backgroundTaskID) + ?? readString(metadata.background_task_id) +} + +function readAgentFromMetadata(metadata: Record): string | undefined { + return readString(metadata.agent) ?? readString(metadata.subagent) +} + +function readCategoryFromMetadata(metadata: Record): string | undefined { + return readString(metadata.category) +} + +function extractTaskMetadataContent(text: string): string | undefined { + const blocks = [...text.matchAll(/([\s\S]*?)<\/task_metadata>/gi)] + return blocks.at(-1)?.[1] +} + +function extractExplicitSessionId(text: string): string | undefined { + const matches = [...text.matchAll(/Session ID:\s*(ses_[a-zA-Z0-9_-]+)/g)] + return matches.at(-1)?.[1] +} + +export function buildTaskMetadataBlock(link: TaskLink): string { + const lines: string[] = [] + + if (link.sessionId) { + lines.push(`session_id: ${link.sessionId}`) + } + if (link.taskId) { + lines.push(`task_id: ${link.taskId}`) + } + if (link.backgroundTaskId) { + lines.push(`background_task_id: ${link.backgroundTaskId}`) + } + if (link.agent) { + lines.push(`subagent: ${link.agent}`) + } + if (link.category) { + lines.push(`category: ${link.category}`) + } + + return `\n${lines.join("\n")}\n` +} + +export function parseTaskMetadataBlock(text: string): TaskLink { + const blockContent = extractTaskMetadataContent(text) ?? text + const lines = blockContent + .split("\n") + .map(line => line.trim()) + .filter(Boolean) + + const parsed: TaskLink = {} + + for (const line of lines) { + const separatorIndex = line.indexOf(":") + if (separatorIndex === -1) { + continue + } + + const key = line.slice(0, separatorIndex).trim().toLowerCase() + const value = readString(line.slice(separatorIndex + 1)) + + if (!value) { + continue + } + + if (key === "session_id") { + parsed.sessionId = value + } else if (key === "task_id") { + parsed.taskId = value + } else if (key === "background_task_id") { + parsed.backgroundTaskId = value + } else if (key === "subagent" || key === "agent") { + parsed.agent = value + } else if (key === "category") { + parsed.category = value + } + } + + return parsed +} + +export function extractTaskLink(metadata: unknown, outputText: string): TaskLink { + if (isRecord(metadata)) { + const metadataLink: TaskLink = { + sessionId: readSessionIdFromMetadata(metadata), + taskId: readTaskIdFromMetadata(metadata), + backgroundTaskId: readBackgroundTaskIdFromMetadata(metadata), + agent: readAgentFromMetadata(metadata), + category: readCategoryFromMetadata(metadata), + } + + if (metadataLink.sessionId || metadataLink.taskId || metadataLink.backgroundTaskId || metadataLink.agent || metadataLink.category) { + return metadataLink + } + } + + const parsed = parseTaskMetadataBlock(outputText) + if (parsed.sessionId || parsed.taskId || parsed.backgroundTaskId || parsed.agent || parsed.category) { + log("[tool-metadata-store] Falling back to parsing") + return parsed + } + + const explicitSessionId = extractExplicitSessionId(outputText) + if (explicitSessionId) { + log("[tool-metadata-store] Falling back to explicit Session ID parsing") + return { sessionId: explicitSessionId } + } + + return {} +} From 80d3339c4c0689669c0bef38b6d4244ecf9e0f45 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 13:52:04 +0900 Subject: [PATCH 003/146] feat(background-agent): add wait-for-task-session helper Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/features/background-agent/index.ts | 2 + .../wait-for-task-session.test.ts | 95 +++++++++++++++++++ .../background-agent/wait-for-task-session.ts | 68 +++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 src/features/background-agent/wait-for-task-session.test.ts create mode 100644 src/features/background-agent/wait-for-task-session.ts diff --git a/src/features/background-agent/index.ts b/src/features/background-agent/index.ts index e1d1a9b73..d21b2faa8 100644 --- a/src/features/background-agent/index.ts +++ b/src/features/background-agent/index.ts @@ -1,2 +1,4 @@ export * from "./types" export { BackgroundManager, type SubagentSessionCreatedEvent, type OnSubagentSessionCreated } from "./manager" +export { waitForTaskSessionID } from "./wait-for-task-session" +export type { WaitForTaskSessionIDOptions } from "./wait-for-task-session" diff --git a/src/features/background-agent/wait-for-task-session.test.ts b/src/features/background-agent/wait-for-task-session.test.ts new file mode 100644 index 000000000..812d9f700 --- /dev/null +++ b/src/features/background-agent/wait-for-task-session.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, test } from "bun:test" + +import type { BackgroundTaskStatus } from "./types" +import { waitForTaskSessionID } from "./wait-for-task-session" + +interface TaskSnapshot { + sessionID?: string + status?: BackgroundTaskStatus +} + +function createManager(responses: TaskSnapshot[]) { + let index = 0 + + return { + getTask(_taskID: string): TaskSnapshot { + const response = responses[Math.min(index, responses.length - 1)] + index += 1 + return response + }, + } +} + +describe("waitForTaskSessionID", () => { + test("#given task already has a session id #when waiting #then it returns immediately", async () => { + // given + const manager = createManager([{ sessionID: "ses_ready_123", status: "running" }]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_ready") + + // then + expect(sessionID).toBe("ses_ready_123") + }) + + test("#given session appears later #when waiting #then it polls until resolved", async () => { + // given + const manager = createManager([ + { status: "running" }, + { status: "running" }, + { sessionID: "ses_late_123", status: "running" }, + ]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_late", { + intervalMs: 1, + timeoutMs: 20, + }) + + // then + expect(sessionID).toBe("ses_late_123") + }) + + test("#given aborted signal #when waiting #then it returns undefined", async () => { + // given + const controller = new AbortController() + controller.abort() + const manager = createManager([{ status: "running" }]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_abort", { + signal: controller.signal, + }) + + // then + expect(sessionID).toBeUndefined() + }) + + test("#given task never resolves #when waiting past timeout #then it returns undefined", async () => { + // given + const manager = createManager([{ status: "running" }, { status: "running" }, { status: "running" }]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_timeout", { + intervalMs: 1, + timeoutMs: 3, + }) + + // then + expect(sessionID).toBeUndefined() + }) + + test.each(["error", "cancelled", "interrupt"] satisfies BackgroundTaskStatus[])( + "#given %s task state #when waiting #then it returns undefined", + async (status: BackgroundTaskStatus) => { + // given + const manager = createManager([{ status }]) + + // when + const sessionID = await waitForTaskSessionID(manager, `bg_${status}`) + + // then + expect(sessionID).toBeUndefined() + } + ) +}) diff --git a/src/features/background-agent/wait-for-task-session.ts b/src/features/background-agent/wait-for-task-session.ts new file mode 100644 index 000000000..eb5fe49d8 --- /dev/null +++ b/src/features/background-agent/wait-for-task-session.ts @@ -0,0 +1,68 @@ +import { getTimingConfig } from "../../tools/delegate-task/timing" +import type { BackgroundTaskStatus } from "./types" + +type SessionWaitTerminalStatus = Extract +type AbortSignalLike = { aborted: boolean } + +interface TaskReader { + getTask(taskID: string): { sessionID?: string; status?: BackgroundTaskStatus } | undefined +} + +export interface WaitForTaskSessionIDOptions { + timeoutMs?: number + intervalMs?: number + signal?: AbortSignalLike +} + +function isTerminalStatus(status: BackgroundTaskStatus | undefined): status is SessionWaitTerminalStatus { + return status === "error" || status === "cancelled" || status === "interrupt" +} + +function waitForInterval(intervalMs: number): Promise { + return new Promise(resolve => { + const scheduler = globalThis as { setTimeout: (handler: () => void, timeout?: number) => unknown } + scheduler.setTimeout(resolve, intervalMs) + }) +} + +export async function waitForTaskSessionID( + manager: TaskReader, + taskID: string, + options: WaitForTaskSessionIDOptions = {} +): Promise { + const timing = getTimingConfig() + const timeoutMs = options.timeoutMs ?? timing.WAIT_FOR_SESSION_TIMEOUT_MS + const intervalMs = options.intervalMs ?? timing.WAIT_FOR_SESSION_INTERVAL_MS + + if (options.signal?.aborted) { + return undefined + } + + const initialTask = manager.getTask(taskID) + if (initialTask?.sessionID) { + return initialTask.sessionID + } + if (isTerminalStatus(initialTask?.status)) { + return undefined + } + + const deadline = Date.now() + timeoutMs + + while (Date.now() < deadline) { + if (options.signal?.aborted) { + return undefined + } + + await waitForInterval(intervalMs) + + const task = manager.getTask(taskID) + if (task?.sessionID) { + return task.sessionID + } + if (isTerminalStatus(task?.status)) { + return undefined + } + } + + return undefined +} From 4da300579778b93338573316ecabb70b030b174a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 13:52:12 +0900 Subject: [PATCH 004/146] fix(plugin): harden metadata recovery and extraction Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/atlas/subagent-session-id.test.ts | 11 +++ src/hooks/atlas/subagent-session-id.ts | 22 ++--- .../oracle-verification-detector.ts | 15 +--- src/hooks/task-resume-info/hook.ts | 19 +--- src/hooks/task-resume-info/index.test.ts | 18 ++++ src/plugin/tool-execute-after.test.ts | 62 ++++++++++++- src/plugin/tool-execute-after.ts | 86 ++++++++++++------- 7 files changed, 158 insertions(+), 75 deletions(-) diff --git a/src/hooks/atlas/subagent-session-id.test.ts b/src/hooks/atlas/subagent-session-id.test.ts index b73a0c75c..3b8c68757 100644 --- a/src/hooks/atlas/subagent-session-id.test.ts +++ b/src/hooks/atlas/subagent-session-id.test.ts @@ -90,6 +90,17 @@ describe("extractSessionIdFromMetadata", () => { expect(result).toBe("ses_plugin_abc123") }) + test("extracts legacy session aliases from tool metadata object", () => { + // given + const metadata = { sessionID: "ses_plugin_alias_123" } + + // when + const result = extractSessionIdFromMetadata(metadata) + + // then + expect(result).toBe("ses_plugin_alias_123") + }) + test("returns undefined for metadata without sessionId", () => { // given const metadata = { title: "some task" } diff --git a/src/hooks/atlas/subagent-session-id.ts b/src/hooks/atlas/subagent-session-id.ts index 95aef2aee..cc52deb88 100644 --- a/src/hooks/atlas/subagent-session-id.ts +++ b/src/hooks/atlas/subagent-session-id.ts @@ -1,30 +1,20 @@ import type { PluginInput } from "@opencode-ai/plugin" +import { extractTaskLink } from "../../features/tool-metadata-store" import { log } from "../../shared/logger" import { isSessionInBoulderLineage } from "./boulder-session-lineage" import { HOOK_NAME } from "./hook-name" export function extractSessionIdFromMetadata(metadata: unknown): string | undefined { - if (metadata && typeof metadata === "object" && "sessionId" in metadata) { - const value = (metadata as Record).sessionId - if (typeof value === "string" && value.startsWith("ses_")) { - return value - } + const sessionId = extractTaskLink(metadata, "").sessionId + if (typeof sessionId === "string" && sessionId.startsWith("ses_")) { + return sessionId } + return undefined } export function extractSessionIdFromOutput(output: string): string | undefined { - const taskMetadataBlocks = [...output.matchAll(/([\s\S]*?)<\/task_metadata>/gi)] - const lastTaskMetadataBlock = taskMetadataBlocks.at(-1)?.[1] - if (lastTaskMetadataBlock) { - const taskMetadataSessionMatch = lastTaskMetadataBlock.match(/session_id:\s*(ses_[a-zA-Z0-9_-]+)/i) - if (taskMetadataSessionMatch) { - return taskMetadataSessionMatch[1] - } - } - - const explicitSessionMatches = [...output.matchAll(/Session ID:\s*(ses_[a-zA-Z0-9_-]+)/g)] - return explicitSessionMatches.at(-1)?.[1] + return extractTaskLink(undefined, output).sessionId } export async function validateSubagentSessionId(input: { diff --git a/src/hooks/ralph-loop/oracle-verification-detector.ts b/src/hooks/ralph-loop/oracle-verification-detector.ts index 9d360282d..277ef1fe2 100644 --- a/src/hooks/ralph-loop/oracle-verification-detector.ts +++ b/src/hooks/ralph-loop/oracle-verification-detector.ts @@ -1,3 +1,4 @@ +import { extractTaskLink } from "../../features/tool-metadata-store" import { stripInvisibleAgentCharacters } from "../../shared/agent-display-names" import { ULTRAWORK_VERIFICATION_PROMISE } from "./constants" @@ -9,8 +10,6 @@ export interface OracleVerificationEvidence { const AGENT_LINE_PATTERN = /^Agent:[ \t]*(\S+)$/im const PROMISE_TAG_PATTERN = /[ \t]*(\S+?)[ \t]*<\/promise>/is -const TASK_METADATA_PATTERN = /[ \t]*([\s\S]*?)[ \t]*<\/task_metadata>/is -const SESSION_ID_LINE_PATTERN = /^session_id:[ \t]*(\S+)$/im export function parseOracleVerificationEvidence(text: string): OracleVerificationEvidence | undefined { const trimmedText = text.trim() @@ -36,17 +35,9 @@ export function parseOracleVerificationEvidence(text: string): OracleVerificatio return undefined } - const metadataMatch = trimmedText.match(TASK_METADATA_PATTERN) - let sessionID: string | undefined - if (metadataMatch) { - const metadataContent = metadataMatch[1] - const sessionIDMatch = metadataContent.match(SESSION_ID_LINE_PATTERN) - if (sessionIDMatch) { - sessionID = sessionIDMatch[1]?.trim() - } - } + const sessionID = extractTaskLink(undefined, trimmedText).sessionId - return { agent, promise, sessionID } + return { agent, promise, sessionID } } export function isOracleVerified(text: string): boolean { diff --git a/src/hooks/task-resume-info/hook.ts b/src/hooks/task-resume-info/hook.ts index 1774aef6a..392fc8761 100644 --- a/src/hooks/task-resume-info/hook.ts +++ b/src/hooks/task-resume-info/hook.ts @@ -1,20 +1,7 @@ +import { extractTaskLink } from "../../features/tool-metadata-store" + const TARGET_TOOLS = ["task", "Task", "task_tool", "call_omo_agent"] -const SESSION_ID_PATTERNS = [ - /Session ID: (ses_[a-zA-Z0-9_-]+)/, - /session_id: (ses_[a-zA-Z0-9_-]+)/, - /\s*session_id: (ses_[a-zA-Z0-9_-]+)/, - /sessionId: (ses_[a-zA-Z0-9_-]+)/, -] - -function extractSessionId(output: string): string | null { - for (const pattern of SESSION_ID_PATTERNS) { - const match = output.match(pattern) - if (match) return match[1] ?? null - } - return null -} - export function createTaskResumeInfoHook() { const toolExecuteAfter = async ( input: { tool: string; sessionID: string; callID: string }, @@ -25,7 +12,7 @@ export function createTaskResumeInfoHook() { if (outputText.startsWith("Error:") || outputText.startsWith("Failed")) return if (outputText.includes("\nto continue:")) return - const sessionId = extractSessionId(outputText) + const sessionId = extractTaskLink(output.metadata, outputText).sessionId if (!sessionId) return output.output = diff --git a/src/hooks/task-resume-info/index.test.ts b/src/hooks/task-resume-info/index.test.ts index 2d10ef757..c592bd7c6 100644 --- a/src/hooks/task-resume-info/index.test.ts +++ b/src/hooks/task-resume-info/index.test.ts @@ -78,6 +78,24 @@ describe("createTaskResumeInfoHook", () => { }) }) + describe("#given target tool with session metadata object", () => { + describe("#when output text omits session ID but metadata includes it", () => { + it("#then should append resume info from metadata", async () => { + const input = createInput("task") + const output = { + title: "task", + output: "Task completed successfully", + metadata: { sessionID: "ses_meta_123" }, + } + + await afterHook(input, output) + + expect(output.output).toContain("to continue:") + expect(output.output).toContain("ses_meta_123") + }) + }) + }) + describe("#given target tool with error output", () => { describe("#when output starts with Error:", () => { it("#then should not modify output", async () => { diff --git a/src/plugin/tool-execute-after.test.ts b/src/plugin/tool-execute-after.test.ts index cb70a91f8..7c8e9d87c 100644 --- a/src/plugin/tool-execute-after.test.ts +++ b/src/plugin/tool-execute-after.test.ts @@ -1,7 +1,13 @@ -import { describe, expect, it } from "bun:test" +import { beforeEach, describe, expect, it } from "bun:test" + +import { clearPendingStore, storeToolMetadata } from "../features/tool-metadata-store" import { createToolExecuteAfterHandler } from "./tool-execute-after" describe("createToolExecuteAfterHandler", () => { + beforeEach(() => { + clearPendingStore() + }) + it("#given truncator changes output #when tool.execute.after runs #then claudeCodeHooks receives truncated output", async () => { const callOrder: string[] = [] let claudeSawOutput = "" @@ -32,4 +38,58 @@ describe("createToolExecuteAfterHandler", () => { expect(callOrder).toEqual(["truncator", "claude"]) expect(claudeSawOutput).toBe("truncated output") }) + + it("#given stored metadata with legacy call id casing #when tool.execute.after runs #then it restores the stored metadata", async () => { + // given + storeToolMetadata("ses_parent", "call_legacy", { + title: "stored title", + metadata: { sessionId: "ses_child", agent: "oracle" }, + }) + + const handler = createToolExecuteAfterHandler({ + ctx: { directory: "/repo" } as never, + hooks: {} as never, + }) + + const output = { title: "result", output: "original output", metadata: { truncated: true } } + + // when + await handler( + { tool: "hashline_edit", sessionID: "ses_parent", callId: " call_legacy " }, + output + ) + + // then + expect(output.title).toBe("stored title") + expect(output.metadata).toEqual({ truncated: true, sessionId: "ses_child", agent: "oracle" }) + }) + + it("#given native session metadata #when stored metadata exists #then stored metadata does not overwrite native session linkage", async () => { + // given + storeToolMetadata("ses_parent", "call_native", { + title: "stored title", + metadata: { sessionId: "ses_stored", agent: "oracle" }, + }) + + const handler = createToolExecuteAfterHandler({ + ctx: { directory: "/repo" } as never, + hooks: {} as never, + }) + + const output = { + title: "result", + output: "original output", + metadata: { sessionId: "ses_native", agent: "hephaestus" }, + } + + // when + await handler( + { tool: "hashline_edit", sessionID: "ses_parent", callID: "call_native" }, + output + ) + + // then + expect(output.title).toBe("stored title") + expect(output.metadata).toEqual({ sessionId: "ses_native", agent: "hephaestus" }) + }) }) diff --git a/src/plugin/tool-execute-after.ts b/src/plugin/tool-execute-after.ts index b0c31bb47..19bb724d7 100644 --- a/src/plugin/tool-execute-after.ts +++ b/src/plugin/tool-execute-after.ts @@ -1,9 +1,8 @@ -import { consumeToolMetadata } from "../features/tool-metadata-store" +import { recoverToolMetadata } from "../features/tool-metadata-store" import type { CreatedHooks } from "../create-hooks" -import { log } from "../shared" +import { log } from "../shared/logger" import { stripInvisibleAgentCharacters } from "../shared/agent-display-names" import type { PluginContext } from "./types" -import { readState, writeState } from "../hooks/ralph-loop/storage" const VERIFICATION_ATTEMPT_PATTERN = /(.*?)<\/ulw_verification_attempt_id>/i @@ -37,20 +36,45 @@ export function createToolExecuteAfterHandler(args: { ) => Promise { const { ctx, hooks } = args + // OpenCode injects tool call ids into execute() context and after-hook input via undocumented runtime fields. + // We must treat their identity as a best-effort correlation key, not a guaranteed public contract. + return async ( - input: { tool: string; sessionID: string; callID: string }, + input: { tool: string; sessionID: string; callID?: string; callId?: string; call_id?: string }, output: { title: string; output: string; metadata: Record } | undefined, ): Promise => { if (!output) return - const stored = consumeToolMetadata(input.sessionID, input.callID) + const hookInput = { + tool: input.tool, + sessionID: input.sessionID, + callID: input.callID ?? input.callId ?? input.call_id ?? "", + } + + const nativeSessionId = getMetadataString(output.metadata, ["sessionId", "sessionID", "session_id"]) + const stored = recoverToolMetadata(input.sessionID, input) if (stored) { if (stored.title) { output.title = stored.title } if (stored.metadata) { - output.metadata = { ...output.metadata, ...stored.metadata } + if (nativeSessionId) { + log("[tool-execute-after] Native output metadata already includes session linkage; skipping stored metadata overwrite", { + tool: input.tool, + sessionID: input.sessionID, + callID: input.callID ?? input.callId ?? input.call_id, + nativeSessionId, + }) + } else { + output.metadata = { ...output.metadata, ...stored.metadata } + } } + } else if (!nativeSessionId) { + log("[tool-execute-after] Unable to recover stored metadata and no native session linkage was present", { + tool: input.tool, + sessionID: input.sessionID, + callID: input.callID ?? input.callId ?? input.call_id, + }) } if (input.tool === "task") { @@ -59,7 +83,9 @@ export function createToolExecuteAfterHandler(args: { const agent = getMetadataString(output.metadata, ["agent"]) const prompt = getMetadataString(output.metadata, ["prompt"]) const verificationAttemptId = prompt?.match(VERIFICATION_ATTEMPT_PATTERN)?.[1]?.trim() - const loopState = directory ? readState(directory) : null + const loopState = directory + ? (await import("../hooks/ralph-loop/storage")).readState(directory) + : null const isVerificationContext = (agent ? stripInvisibleAgentCharacters(agent) : agent) === "oracle" && !!sessionId @@ -83,7 +109,7 @@ export function createToolExecuteAfterHandler(args: { && verificationAttemptId && loopState.verification_attempt_id === verificationAttemptId ) { - writeState(directory, { + ;(await import("../hooks/ralph-loop/storage")).writeState(directory, { ...loopState, verification_session_id: sessionId, }) @@ -93,7 +119,7 @@ export function createToolExecuteAfterHandler(args: { verificationAttemptId, }) } else if (isVerificationContext && !verificationAttemptId) { - writeState(directory, { + ;(await import("../hooks/ralph-loop/storage")).writeState(directory, { ...loopState, verification_session_id: sessionId, }) @@ -108,26 +134,26 @@ export function createToolExecuteAfterHandler(args: { } const runToolExecuteAfterHooks = async (): Promise => { - await hooks.toolOutputTruncator?.["tool.execute.after"]?.(input, output) - await hooks.claudeCodeHooks?.["tool.execute.after"]?.(input, output) - await hooks.preemptiveCompaction?.["tool.execute.after"]?.(input, output) - await hooks.contextWindowMonitor?.["tool.execute.after"]?.(input, output) - await hooks.commentChecker?.["tool.execute.after"]?.(input, output) - await hooks.directoryAgentsInjector?.["tool.execute.after"]?.(input, output) - await hooks.directoryReadmeInjector?.["tool.execute.after"]?.(input, output) - await hooks.rulesInjector?.["tool.execute.after"]?.(input, output) - await hooks.emptyTaskResponseDetector?.["tool.execute.after"]?.(input, output) - await hooks.agentUsageReminder?.["tool.execute.after"]?.(input, output) - await hooks.categorySkillReminder?.["tool.execute.after"]?.(input, output) - await hooks.interactiveBashSession?.["tool.execute.after"]?.(input, output) - await hooks.editErrorRecovery?.["tool.execute.after"]?.(input, output) - await hooks.delegateTaskRetry?.["tool.execute.after"]?.(input, output) - await hooks.atlasHook?.["tool.execute.after"]?.(input, output) - await hooks.taskResumeInfo?.["tool.execute.after"]?.(input, output) - await hooks.readImageResizer?.["tool.execute.after"]?.(input, output) - await hooks.hashlineReadEnhancer?.["tool.execute.after"]?.(input, output) - await hooks.webfetchRedirectGuard?.["tool.execute.after"]?.(input, output) - await hooks.jsonErrorRecovery?.["tool.execute.after"]?.(input, output) + await hooks.toolOutputTruncator?.["tool.execute.after"]?.(hookInput, output) + await hooks.claudeCodeHooks?.["tool.execute.after"]?.(hookInput, output) + await hooks.preemptiveCompaction?.["tool.execute.after"]?.(hookInput, output) + await hooks.contextWindowMonitor?.["tool.execute.after"]?.(hookInput, output) + await hooks.commentChecker?.["tool.execute.after"]?.(hookInput, output) + await hooks.directoryAgentsInjector?.["tool.execute.after"]?.(hookInput, output) + await hooks.directoryReadmeInjector?.["tool.execute.after"]?.(hookInput, output) + await hooks.rulesInjector?.["tool.execute.after"]?.(hookInput, output) + await hooks.emptyTaskResponseDetector?.["tool.execute.after"]?.(hookInput, output) + await hooks.agentUsageReminder?.["tool.execute.after"]?.(hookInput, output) + await hooks.categorySkillReminder?.["tool.execute.after"]?.(hookInput, output) + await hooks.interactiveBashSession?.["tool.execute.after"]?.(hookInput, output) + await hooks.editErrorRecovery?.["tool.execute.after"]?.(hookInput, output) + await hooks.delegateTaskRetry?.["tool.execute.after"]?.(hookInput, output) + await hooks.atlasHook?.["tool.execute.after"]?.(hookInput, output) + await hooks.taskResumeInfo?.["tool.execute.after"]?.(hookInput, output) + await hooks.readImageResizer?.["tool.execute.after"]?.(hookInput, output) + await hooks.hashlineReadEnhancer?.["tool.execute.after"]?.(hookInput, output) + await hooks.webfetchRedirectGuard?.["tool.execute.after"]?.(hookInput, output) + await hooks.jsonErrorRecovery?.["tool.execute.after"]?.(hookInput, output) } if (input.tool === "extract" || input.tool === "discard") { @@ -146,7 +172,7 @@ export function createToolExecuteAfterHandler(args: { log("[tool-execute-after] Failed to process extract/discard hooks", { tool: input.tool, sessionID: input.sessionID, - callID: input.callID, + callID: input.callID ?? input.callId ?? input.call_id, error, }) } From c6a407c4861c81366bfde695ff824cd2e3356435 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 13:52:20 +0900 Subject: [PATCH 005/146] refactor(tools): migrate producers to shared metadata bridge Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../create-background-output.ts | 16 +------- .../background-task/create-background-task.ts | 8 +--- .../delegate-task/background-continuation.ts | 9 +---- src/tools/delegate-task/background-task.ts | 9 +---- .../delegate-task/resolve-call-id.test.ts | 40 ------------------- src/tools/delegate-task/resolve-call-id.ts | 5 --- src/tools/delegate-task/sync-continuation.ts | 9 +---- src/tools/delegate-task/sync-task.ts | 9 +---- .../delegate-task/unstable-agent-task.ts | 9 +---- .../hashline-edit/hashline-edit-executor.ts | 26 ++---------- 10 files changed, 17 insertions(+), 123 deletions(-) delete mode 100644 src/tools/delegate-task/resolve-call-id.test.ts delete mode 100644 src/tools/delegate-task/resolve-call-id.ts diff --git a/src/tools/background-task/create-background-output.ts b/src/tools/background-task/create-background-output.ts index 925db344a..7e8ac8f3d 100644 --- a/src/tools/background-task/create-background-output.ts +++ b/src/tools/background-task/create-background-output.ts @@ -1,6 +1,6 @@ import { tool, type ToolDefinition } from "@opencode-ai/plugin" import type { BackgroundTask } from "../../features/background-agent" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import type { BackgroundOutputArgs } from "./types" import type { BackgroundOutputClient, BackgroundOutputManager } from "./clients" import { BACKGROUND_OUTPUT_DESCRIPTION } from "./constants" @@ -23,13 +23,6 @@ type ToolContextWithMetadata = { call_id?: string } -function resolveToolCallID(ctx: ToolContextWithMetadata): string | undefined { - if (typeof ctx.callID === "string" && ctx.callID.trim() !== "") return ctx.callID - if (typeof ctx.callId === "string" && ctx.callId.trim() !== "") return ctx.callId - if (typeof ctx.call_id === "string" && ctx.call_id.trim() !== "") return ctx.call_id - return undefined -} - function formatResolvedTitle(task: BackgroundTask): string { const label = task.agent === SISYPHUS_JUNIOR_AGENT && task.category ? task.category : task.agent return `${label} - ${task.description}` @@ -80,12 +73,7 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client: ...(task.sessionID ? { sessionId: task.sessionID } : {}), } as Record, } - ctx.metadata?.(meta) - - const callID = resolveToolCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, meta) - } + await publishToolMetadata(ctx, meta) const shouldBlock = args.block === true const timeoutMs = Math.min(args.timeout ?? 60000, 600000) diff --git a/src/tools/background-task/create-background-task.ts b/src/tools/background-task/create-background-task.ts index 0d2c38f0f..cd892e6a3 100644 --- a/src/tools/background-task/create-background-task.ts +++ b/src/tools/background-task/create-background-task.ts @@ -4,7 +4,7 @@ import type { BackgroundTaskArgs } from "./types" import { BACKGROUND_TASK_DESCRIPTION } from "./constants" import { resolveMessageContext } from "../../features/hook-message-injector" import { getSessionAgent } from "../../features/claude-code-session-state" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { log } from "../../shared/logger" import { delay } from "./delay" import { getMessageDir } from "./message-dir" @@ -100,11 +100,7 @@ export function createBackgroundTask( ...(sessionId ? { sessionId } : {}), }, } - ctx.metadata?.(bgMeta) - - if (ctx.callID) { - storeToolMetadata(ctx.sessionID, ctx.callID, bgMeta) - } + await publishToolMetadata(ctx, bgMeta) return `Background task launched successfully. diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 0d365d964..dd0850439 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -1,9 +1,8 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ExecutorContext, ParentContext } from "./executor-types" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" -import { resolveCallID } from "./resolve-call-id" export async function executeBackgroundContinuation( args: DelegateTaskArgs, @@ -37,11 +36,7 @@ export async function executeBackgroundContinuation( model: task.model ? { providerID: task.model.providerID, modelID: task.model.modelID } : undefined, }, } - await ctx.metadata?.(bgContMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, bgContMeta) - } + await publishToolMetadata(ctx, bgContMeta) return `Background task continued. diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 184325ec9..73d43ad02 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -3,8 +3,7 @@ import type { ExecutorContext, ParentContext } from "./executor-types" import type { FallbackEntry } from "../../shared/model-requirements" import { getTimingConfig } from "./timing" import { buildTaskPrompt } from "./prompt-builder" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" import { SessionCategoryRegistry } from "../../shared/session-category-registry" @@ -134,11 +133,7 @@ export async function executeBackgroundTask( title: args.description, metadata, } - await ctx.metadata?.(unstableMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, unstableMeta) - } + await publishToolMetadata(ctx, unstableMeta) const taskMetadataBlock = sessionId ? `\n\n\nsession_id: ${sessionId}\ntask_id: ${task.id}\nbackground_task_id: ${task.id}\n` diff --git a/src/tools/delegate-task/resolve-call-id.test.ts b/src/tools/delegate-task/resolve-call-id.test.ts deleted file mode 100644 index 7b4da140e..000000000 --- a/src/tools/delegate-task/resolve-call-id.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { describe, test, expect } from "bun:test" -import { resolveCallID } from "./resolve-call-id" -import type { ToolContextWithMetadata } from "./types" - -describe("resolveCallID", () => { - function makeCtx(overrides: Partial = {}): ToolContextWithMetadata { - return { - sessionID: "ses_test", - messageID: "msg_test", - agent: "sisyphus", - abort: new AbortController().signal, - ...overrides, - } - } - - test("#given callID is set #then returns callID", () => { - const ctx = makeCtx({ callID: "call_abc" }) - expect(resolveCallID(ctx)).toBe("call_abc") - }) - - test("#given only callId is set #then returns callId", () => { - const ctx = makeCtx({ callId: "call_def" }) - expect(resolveCallID(ctx)).toBe("call_def") - }) - - test("#given only call_id is set #then returns call_id", () => { - const ctx = makeCtx({ call_id: "call_ghi" }) - expect(resolveCallID(ctx)).toBe("call_ghi") - }) - - test("#given callID and callId are both set #then prefers callID", () => { - const ctx = makeCtx({ callID: "preferred", callId: "fallback" }) - expect(resolveCallID(ctx)).toBe("preferred") - }) - - test("#given no call ID variants are set #then returns undefined", () => { - const ctx = makeCtx() - expect(resolveCallID(ctx)).toBeUndefined() - }) -}) diff --git a/src/tools/delegate-task/resolve-call-id.ts b/src/tools/delegate-task/resolve-call-id.ts deleted file mode 100644 index cfa3b747e..000000000 --- a/src/tools/delegate-task/resolve-call-id.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ToolContextWithMetadata } from "./types" - -export function resolveCallID(ctx: ToolContextWithMetadata): string | undefined { - return ctx.callID ?? ctx.callId ?? ctx.call_id -} diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index fa6f9f022..a8e412ece 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -1,8 +1,7 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ExecutorContext, SessionMessage } from "./executor-types" import { isPlanFamily } from "./constants" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { getTaskToastManager } from "../../features/task-toast-manager" import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions" import { getMessageDir } from "../../shared" @@ -78,11 +77,7 @@ export async function executeSyncContinuation( model: resumeModel, }, } - await ctx.metadata?.(syncContMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, syncContMeta) - } + await publishToolMetadata(ctx, syncContMeta) const allowTask = isPlanFamily(resumeAgent) const tddEnabled = sisyphusAgentConfig?.tdd diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 18d99e500..7675fa0de 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -2,8 +2,7 @@ import type { ModelFallbackInfo } from "../../features/task-toast-manager/types" import type { DelegateTaskArgs, ToolContextWithMetadata, DelegatedModelConfig } from "./types" import type { ExecutorContext, ParentContext } from "./executor-types" import { getTaskToastManager } from "../../features/task-toast-manager" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { subagentSessions, syncSubagentSessions, setSessionAgent } from "../../features/claude-code-session-state" import { log } from "../../shared/logger" import { SessionCategoryRegistry } from "../../shared/session-category-registry" @@ -130,11 +129,7 @@ export async function executeSyncTask( model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, }, } - await ctx.metadata?.(syncTaskMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, syncTaskMeta) - } + await publishToolMetadata(ctx, syncTaskMeta) let effectiveCategoryModel = categoryModel let promptError = await deps.sendSyncPrompt(client, { diff --git a/src/tools/delegate-task/unstable-agent-task.ts b/src/tools/delegate-task/unstable-agent-task.ts index 7d10780cb..7a6d46e0d 100644 --- a/src/tools/delegate-task/unstable-agent-task.ts +++ b/src/tools/delegate-task/unstable-agent-task.ts @@ -3,8 +3,7 @@ import type { ExecutorContext, ParentContext, SessionMessage } from "./executor- import { DEFAULT_SYNC_POLL_TIMEOUT_MS, getTimingConfig } from "./timing" import { buildTaskPrompt } from "./prompt-builder" import { cancelUnstableAgentTask } from "./cancel-unstable-agent-task" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDuration } from "./time-formatter" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" @@ -81,11 +80,7 @@ export async function executeUnstableAgentTask( model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, }, } - await ctx.metadata?.(bgTaskMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, bgTaskMeta) - } + await publishToolMetadata(ctx, bgTaskMeta) const startTime = new Date() const timingCfg = getTimingConfig() diff --git a/src/tools/hashline-edit/hashline-edit-executor.ts b/src/tools/hashline-edit/hashline-edit-executor.ts index b9412d89e..54509ab6c 100644 --- a/src/tools/hashline-edit/hashline-edit-executor.ts +++ b/src/tools/hashline-edit/hashline-edit-executor.ts @@ -1,5 +1,5 @@ import type { ToolContext } from "@opencode-ai/plugin/tool" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { applyHashlineEditsWithReport } from "./edit-operations" import { countLineDiffs, generateUnifiedDiff } from "./diff-utils" import { canonicalizeFileText, restoreFileText } from "./file-text-canonicalization" @@ -26,13 +26,6 @@ type ToolContextWithMetadata = ToolContextWithCallID & { metadata?: (value: unknown) => void } -function resolveToolCallID(ctx: ToolContextWithCallID): string | undefined { - if (typeof ctx.callID === "string" && ctx.callID.trim() !== "") return ctx.callID - if (typeof ctx.callId === "string" && ctx.callId.trim() !== "") return ctx.callId - if (typeof ctx.call_id === "string" && ctx.call_id.trim() !== "") return ctx.call_id - return undefined -} - function canCreateFromMissingFile(edits: HashlineEdit[]): boolean { if (edits.length === 0) return false return edits.every((edit) => (edit.op === "append" || edit.op === "prepend") && !edit.pos) @@ -143,13 +136,7 @@ export async function executeHashlineEditTool(args: HashlineEditArgs, context: T applyResult.noopEdits, applyResult.deduplicatedEdits ) - if (typeof metadataContext.metadata === "function") { - metadataContext.metadata(formattedMeta) - } - const callID = resolveToolCallID(metadataContext) - if (callID) { - storeToolMetadata(context.sessionID, callID, formattedMeta) - } + await publishToolMetadata(metadataContext, formattedMeta) if (rename && rename !== filePath) { await Bun.write(rename, formattedContent) await Bun.file(filePath).delete() @@ -173,14 +160,7 @@ export async function executeHashlineEditTool(args: HashlineEditArgs, context: T applyResult.deduplicatedEdits ) - if (typeof metadataContext.metadata === "function") { - metadataContext.metadata(meta) - } - - const callID = resolveToolCallID(metadataContext) - if (callID) { - storeToolMetadata(context.sessionID, callID, meta) - } + await publishToolMetadata(metadataContext, meta) if (rename && rename !== filePath) { return `Moved ${filePath} to ${rename}` From 7bc170fb86a4c66fee47971a8196f557ef5fa852 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 14:28:56 +0900 Subject: [PATCH 006/146] fix: installer writes hyphenated anthropic IDs, variant=max Anthropic OAuth compat (#3429, #3459) --- .../__snapshots__/model-fallback.test.ts.snap | 309 ++++++++---------- .../generate-omo-config.test.ts | 6 +- src/cli/model-fallback.test.ts | 14 +- src/cli/provider-model-id-transform.test.ts | 28 +- src/cli/provider-model-id-transform.ts | 7 +- src/hooks/anthropic-effort/hook.ts | 30 +- src/hooks/anthropic-effort/index.test.ts | 95 +++++- src/shared/index.ts | 1 + src/shared/opencode-provider-auth.test.ts | 107 ++++++ src/shared/opencode-provider-auth.ts | 84 +++++ 10 files changed, 474 insertions(+), 207 deletions(-) create mode 100644 src/shared/opencode-provider-auth.test.ts create mode 100644 src/shared/opencode-provider-auth.ts diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index 88f86f97b..92769a5b8 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -69,67 +69,62 @@ exports[`generateModelConfig single native provider uses Claude models when only "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "multimodal-looker": { "model": "opencode/gpt-5-nano", }, "oracle": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "deep": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "quick": { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "unspecified-high": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "writing": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, } @@ -140,68 +135,63 @@ exports[`generateModelConfig single native provider uses Claude models with isMa "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "multimodal-looker": { "model": "opencode/gpt-5-nano", }, "oracle": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "deep": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "quick": { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "unspecified-high": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "unspecified-low": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "writing": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, } @@ -526,14 +516,9 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "hephaestus": { @@ -547,13 +532,13 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -580,7 +565,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -597,7 +582,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { @@ -607,7 +592,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "medium", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { @@ -617,14 +602,14 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -637,7 +622,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -651,7 +636,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "quick": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "google/gemini-3-flash-preview", @@ -666,7 +651,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -683,7 +668,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -695,12 +680,12 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -710,7 +695,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, ], "model": "google/gemini-3-flash-preview", @@ -730,14 +715,9 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "hephaestus": { @@ -751,13 +731,13 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -784,7 +764,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -801,7 +781,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { @@ -811,7 +791,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "medium", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { @@ -821,14 +801,14 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -841,7 +821,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -855,7 +835,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "quick": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "google/gemini-3-flash-preview", @@ -870,7 +850,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -884,7 +864,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "unspecified-low": { @@ -897,12 +877,12 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -912,7 +892,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, ], "model": "google/gemini-3-flash-preview", @@ -1885,16 +1865,13 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ { "model": "opencode/minimax-m2.7", }, - { - "model": "anthropic/claude-haiku-4.5", - }, { "model": "opencode/claude-haiku-4-5", }, @@ -1919,13 +1896,13 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -1956,7 +1933,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -1981,7 +1958,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { @@ -2004,7 +1981,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { @@ -2020,14 +1997,14 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -2044,7 +2021,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -2062,7 +2039,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "quick": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", @@ -2083,7 +2060,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -2107,7 +2084,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -2122,7 +2099,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ @@ -2130,7 +2107,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -2144,7 +2121,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, { "model": "opencode/claude-sonnet-4-6", @@ -2412,41 +2389,36 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "librarian": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, ], "model": "zai-coding-plan/glm-4.7", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "multimodal-looker": { "model": "zai-coding-plan/glm-4.6v", }, "oracle": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { @@ -2455,42 +2427,42 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "model": "zai-coding-plan/glm-5", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "deep": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "quick": { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "unspecified-high": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], "model": "zai-coding-plan/glm-5", }, "writing": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, } @@ -2501,18 +2473,13 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { @@ -2522,7 +2489,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "multimodal-looker": { @@ -2531,7 +2498,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "oracle": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -2544,22 +2511,22 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -2573,7 +2540,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "quick": { @@ -2582,12 +2549,12 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -2600,7 +2567,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -2608,12 +2575,12 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, ], @@ -2623,7 +2590,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, ], "model": "google/gemini-3-flash-preview", @@ -3048,7 +3015,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ @@ -3058,9 +3025,6 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe { "model": "opencode/minimax-m2.7", }, - { - "model": "anthropic/claude-haiku-4.5", - }, { "model": "opencode/claude-haiku-4-5", }, @@ -3090,7 +3054,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/minimax-m2.7-highspeed", }, { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", @@ -3124,7 +3088,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { @@ -3138,7 +3102,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "xhigh", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3210,7 +3174,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3257,7 +3221,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { @@ -3295,7 +3259,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { @@ -3322,7 +3286,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { @@ -3337,7 +3301,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3372,7 +3336,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "medium", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3408,7 +3372,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gpt-5.4-mini", }, { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "github-copilot/claude-haiku-4.5", @@ -3450,7 +3414,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3491,7 +3455,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -3519,7 +3483,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ @@ -3538,7 +3502,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3562,7 +3526,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3-flash", }, { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, { "model": "github-copilot/claude-sonnet-4.6", @@ -3602,7 +3566,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ @@ -3612,9 +3576,6 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is { "model": "opencode/minimax-m2.7", }, - { - "model": "anthropic/claude-haiku-4.5", - }, { "model": "opencode/claude-haiku-4-5", }, @@ -3644,7 +3605,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/minimax-m2.7-highspeed", }, { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", @@ -3678,7 +3639,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "momus": { @@ -3692,7 +3653,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "xhigh", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3764,7 +3725,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3811,7 +3772,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus": { @@ -3849,7 +3810,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "sisyphus-junior": { @@ -3876,7 +3837,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { @@ -3891,7 +3852,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3926,7 +3887,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "medium", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -3962,7 +3923,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gpt-5.4-mini", }, { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "github-copilot/claude-haiku-4.5", @@ -4004,7 +3965,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -4051,7 +4012,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/kimi-k2.5", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, "unspecified-low": { @@ -4080,7 +4041,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ @@ -4099,7 +4060,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-6", "variant": "max", }, { @@ -4123,7 +4084,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gemini-3-flash", }, { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, { "model": "github-copilot/claude-sonnet-4.6", diff --git a/src/cli/config-manager/generate-omo-config.test.ts b/src/cli/config-manager/generate-omo-config.test.ts index 50fe4e3d8..2d13046ec 100644 --- a/src/cli/config-manager/generate-omo-config.test.ts +++ b/src/cli/config-manager/generate-omo-config.test.ts @@ -74,7 +74,7 @@ describe("generateOmoConfig - model fallback system", () => { //#then expect((result.agents as Record).librarian.model).toBe("zai-coding-plan/glm-4.7") - expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4.6") + expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4-6") }) test("uses native OpenAI models when only ChatGPT available", () => { @@ -131,7 +131,7 @@ describe("generateOmoConfig - model fallback system", () => { }> //#then - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") expect(agents.sisyphus.fallback_models).toEqual([ { model: "openai/gpt-5.4", @@ -141,7 +141,7 @@ describe("generateOmoConfig - model fallback system", () => { expect(categories.deep.model).toBe("openai/gpt-5.4") expect(categories.deep.fallback_models).toEqual([ { - model: "anthropic/claude-opus-4.6", + model: "anthropic/claude-opus-4-6", variant: "max", }, ]) diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index f1df3cc0a..7e7816100 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -381,7 +381,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-6") }) test("Sisyphus is created when multiple fallback providers are available", () => { @@ -398,7 +398,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-6") }) test("Sisyphus resolves to gpt-5.4 medium when only OpenAI is available", () => { @@ -573,13 +573,9 @@ describe("generateModelConfig", () => { // #when generateModelConfig is called const result = generateModelConfig(config) - // #then explore should not have fallback_models (only one chain entry matches) + // #then explore should not have fallback_models (only one distinct chain entry matches) expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5") - expect(result.agents?.explore?.fallback_models).toEqual([ - { - model: "anthropic/claude-haiku-4.5", - }, - ]) + expect(result.agents?.explore?.fallback_models).toBeUndefined() }) test("librarian includes fallback_models when opencode-go and Claude are both available", () => { @@ -672,7 +668,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then should prefer native anthropic over gateway - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-6") }) }) diff --git a/src/cli/provider-model-id-transform.test.ts b/src/cli/provider-model-id-transform.test.ts index d745ff097..fd2f32f07 100644 --- a/src/cli/provider-model-id-transform.test.ts +++ b/src/cli/provider-model-id-transform.test.ts @@ -165,7 +165,7 @@ describe("transformModelForProvider", () => { }) describe("anthropic provider", () => { - test("transforms claude-opus-4-6 to claude-opus-4.6", () => { + test("preserves hyphenated claude-opus-4-6 for config output (regression: installer must not write dotted IDs)", () => { // #given anthropic provider and claude-opus-4-6 model const provider = "anthropic" const model = "claude-opus-4-6" @@ -173,11 +173,11 @@ describe("transformModelForProvider", () => { // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-opus-4.6 - expect(result).toBe("claude-opus-4.6") + // #then should keep hyphenated form so Anthropic provider resolution succeeds on fresh installs + expect(result).toBe("claude-opus-4-6") }) - test("transforms claude-sonnet-4-6 to claude-sonnet-4.6", () => { + test("preserves hyphenated claude-sonnet-4-6 for config output", () => { // #given anthropic provider and claude-sonnet-4-6 model const provider = "anthropic" const model = "claude-sonnet-4-6" @@ -185,11 +185,11 @@ describe("transformModelForProvider", () => { // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-sonnet-4.6 - expect(result).toBe("claude-sonnet-4.6") + // #then should keep hyphenated form + expect(result).toBe("claude-sonnet-4-6") }) - test("transforms claude-haiku-4-5 to claude-haiku-4.5", () => { + test("preserves hyphenated claude-haiku-4-5 for config output", () => { // #given anthropic provider and claude-haiku-4-5 model const provider = "anthropic" const model = "claude-haiku-4-5" @@ -197,8 +197,8 @@ describe("transformModelForProvider", () => { // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-haiku-4.5 - expect(result).toBe("claude-haiku-4.5") + // #then should keep hyphenated form + expect(result).toBe("claude-haiku-4-5") }) }) @@ -338,14 +338,16 @@ describe("transformModelForProvider", () => { }) }) - test("uses a CLI-local transform implementation", () => { - // #given + test("uses a CLI-local transform implementation distinct from the shared runtime transform", () => { + // #given the CLI transform (used by the installer) and the shared runtime transform const cliResult = transformModelForProvider("anthropic", "claude-opus-4-6") const sharedResult = transformSharedModelForProvider("anthropic", "claude-opus-4-6") - // #when + // #when both are called with the same anthropic claude input + // #then the CLI preserves hyphenated form for config output, + // the shared runtime transform converts dash→dot for API calls expect(transformModelForProvider).not.toBe(transformSharedModelForProvider) - expect(cliResult).toBe("claude-opus-4.6") + expect(cliResult).toBe("claude-opus-4-6") expect(sharedResult).toBe("claude-opus-4.6") }) }) diff --git a/src/cli/provider-model-id-transform.ts b/src/cli/provider-model-id-transform.ts index 82942fe74..0eab2d0e2 100644 --- a/src/cli/provider-model-id-transform.ts +++ b/src/cli/provider-model-id-transform.ts @@ -54,7 +54,12 @@ export function transformModelForProvider(provider: string, model: string): stri } if (provider === "anthropic") { - return claudeVersionDot(model) + // Installer writes hyphenated IDs (claude-opus-4-6) to the config. The + // runtime provider-model-id-transform converts dash→dot when calling the + // Anthropic API. Keeping the dotted form in the config breaks fresh + // installs with ProviderModelNotFoundError because Anthropic's provider + // registers models under hyphenated IDs. + return model } return model diff --git a/src/hooks/anthropic-effort/hook.ts b/src/hooks/anthropic-effort/hook.ts index 6d4cc965c..a8f5ecb85 100644 --- a/src/hooks/anthropic-effort/hook.ts +++ b/src/hooks/anthropic-effort/hook.ts @@ -1,4 +1,4 @@ -import { log, normalizeModelID } from "../../shared" +import { isProviderUsingOAuth, log, normalizeModelID } from "../../shared" const OPUS_PATTERN = /claude-.*opus/i const EFFORT_UNSUPPORTED_PATTERN = /claude-.*haiku/i @@ -25,6 +25,16 @@ function shouldSkipForInternalAgent(agentName: string | undefined): boolean { return INTERNAL_SKIP_AGENTS.has(agentName.trim().toLowerCase()) } +/** + * Claude Pro/Max subscriptions expose a constrained OAuth API that rejects + * `output_config.effort: "max"` (supported values: low | medium | high) even on + * Opus models. Detect OAuth auth by inspecting OpenCode's auth.json. + */ +function isAnthropicOAuth(providerID: string): boolean { + if (providerID !== "anthropic") return false + return isProviderUsingOAuth(providerID) +} + interface ChatParamsInput { sessionID: string agent: { name?: string } @@ -49,8 +59,9 @@ const MAX_VARIANT_BY_TIER: Record = { default: "high", } -function clampVariant(variant: string, isOpus: boolean): string { +function clampVariant(variant: string, isOpus: boolean, isOAuth: boolean): string { if (variant !== "max") return variant + if (isOAuth) return MAX_VARIANT_BY_TIER.default return isOpus ? MAX_VARIANT_BY_TIER.opus : MAX_VARIANT_BY_TIER.default } @@ -70,16 +81,23 @@ export function createAnthropicEffortHook() { if (output.options.effort !== undefined) return const opus = isOpusModel(model.modelID) - const clamped = clampVariant(message.variant, opus) + const oauth = isAnthropicOAuth(model.providerID) + const clamped = clampVariant(message.variant, opus, oauth) output.options.effort = clamped - if (!opus) { - // Override the variant so OpenCode doesn't pass "max" to the API + const shouldOverrideMessageVariant = !opus || oauth + + if (shouldOverrideMessageVariant) { + // Override the variant so OpenCode doesn't pass "max" to the API. + // Non-Opus models cap at high; Anthropic OAuth (Claude Pro/Max) also + // caps at high even on Opus because the OAuth API only accepts + // low | medium | high. ;(message as { variant?: string }).variant = clamped - log("anthropic-effort: clamped variant max→high for non-Opus model", { + log("anthropic-effort: clamped variant max→high", { sessionID: input.sessionID, provider: model.providerID, model: model.modelID, + reason: oauth ? "anthropic-oauth" : "non-opus", }) } else { log("anthropic-effort: injected effort=max", { diff --git a/src/hooks/anthropic-effort/index.test.ts b/src/hooks/anthropic-effort/index.test.ts index cea012eb9..ef8dc944d 100644 --- a/src/hooks/anthropic-effort/index.test.ts +++ b/src/hooks/anthropic-effort/index.test.ts @@ -1,4 +1,9 @@ -import { describe, expect, it } from "bun:test" +import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test" +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import * as path from "node:path" + +import { _resetProviderAuthCacheForTesting } from "../../shared/opencode-provider-auth" import { createAnthropicEffortHook } from "./index" interface ChatParamsInput { @@ -199,4 +204,92 @@ describe("createAnthropicEffortHook", () => { expect(output.options.effort).toBe("high") }) }) + + describe("#given anthropic OAuth auth (Claude Pro/Max) — regression for #3429", () => { + let tempDataDir: string + const originalXdgDataHome = process.env.XDG_DATA_HOME + + function writeAuthFile(providerEntries: Record>): void { + const opencodeDir = path.join(tempDataDir, "opencode") + mkdirSync(opencodeDir, { recursive: true }) + writeFileSync(path.join(opencodeDir, "auth.json"), JSON.stringify(providerEntries), "utf-8") + _resetProviderAuthCacheForTesting() + } + + beforeAll(() => { + tempDataDir = path.join(tmpdir(), `anthropic-effort-oauth-${Date.now()}-${Math.random().toString(36).slice(2)}`) + mkdirSync(tempDataDir, { recursive: true }) + process.env.XDG_DATA_HOME = tempDataDir + }) + + afterAll(() => { + if (originalXdgDataHome === undefined) { + delete process.env.XDG_DATA_HOME + } else { + process.env.XDG_DATA_HOME = originalXdgDataHome + } + rmSync(tempDataDir, { recursive: true, force: true }) + _resetProviderAuthCacheForTesting() + }) + + afterEach(() => { + _resetProviderAuthCacheForTesting() + }) + + it("clamps opus-4-6 + max to high when anthropic provider uses oauth", async () => { + // given an Anthropic OAuth session and variant=max on an Opus model + writeAuthFile({ anthropic: { type: "oauth" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4-6" }) + + // when chat.params fires + await hook["chat.params"](input, output) + + // then effort must be clamped to high so Anthropic's OAuth API accepts it + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") + }) + + it("clamps dotted opus id + max to high under OAuth", async () => { + // given an Anthropic OAuth session and a dotted opus id + writeAuthFile({ anthropic: { type: "oauth" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4.6" }) + + // when chat.params fires + await hook["chat.params"](input, output) + + // then effort must be clamped to high + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") + }) + + it("still injects effort=max when anthropic auth is an API key", async () => { + // given an Anthropic API-key session (not OAuth) + writeAuthFile({ anthropic: { type: "api", key: "sk-ant-xxx" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4-6" }) + + // when chat.params fires + await hook["chat.params"](input, output) + + // then API-key users keep the original max behaviour for Opus + expect(output.options.effort).toBe("max") + expect(input.message.variant).toBe("max") + }) + + it("does not clamp when OAuth belongs to a different provider", async () => { + // given OAuth entries for unrelated providers only + writeAuthFile({ "github-copilot": { type: "oauth" }, opencode: { type: "api", key: "sk-x" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4-6", providerID: "anthropic" }) + + // when chat.params fires for the anthropic provider + await hook["chat.params"](input, output) + + // then max stays because anthropic itself is not OAuth + expect(output.options.effort).toBe("max") + expect(input.message.variant).toBe("max") + }) + }) }) diff --git a/src/shared/index.ts b/src/shared/index.ts index 826434d42..80ffa751b 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -57,6 +57,7 @@ export * from "./session-utils" export * from "./tmux" export * from "./model-suggestion-retry" export * from "./opencode-server-auth" +export * from "./opencode-provider-auth" export * from "./opencode-http-api" export * from "./port-utils" export * from "./git-worktree" diff --git a/src/shared/opencode-provider-auth.test.ts b/src/shared/opencode-provider-auth.test.ts new file mode 100644 index 000000000..56adcc9fe --- /dev/null +++ b/src/shared/opencode-provider-auth.test.ts @@ -0,0 +1,107 @@ +import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test" +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import * as path from "node:path" + +import { + _resetProviderAuthCacheForTesting, + getProviderAuthType, + isProviderUsingOAuth, +} from "./opencode-provider-auth" + +describe("opencode-provider-auth", () => { + let tempDataDir: string + const originalXdgDataHome = process.env.XDG_DATA_HOME + + function writeAuthFile(contents: string): void { + const opencodeDir = path.join(tempDataDir, "opencode") + mkdirSync(opencodeDir, { recursive: true }) + writeFileSync(path.join(opencodeDir, "auth.json"), contents, "utf-8") + _resetProviderAuthCacheForTesting() + } + + beforeAll(() => { + tempDataDir = path.join(tmpdir(), `opencode-provider-auth-${Date.now()}-${Math.random().toString(36).slice(2)}`) + mkdirSync(tempDataDir, { recursive: true }) + process.env.XDG_DATA_HOME = tempDataDir + }) + + afterAll(() => { + if (originalXdgDataHome === undefined) { + delete process.env.XDG_DATA_HOME + } else { + process.env.XDG_DATA_HOME = originalXdgDataHome + } + rmSync(tempDataDir, { recursive: true, force: true }) + _resetProviderAuthCacheForTesting() + }) + + afterEach(() => { + _resetProviderAuthCacheForTesting() + }) + + it("#given auth.json with oauth entry #then detects OAuth for that provider", () => { + // given auth.json where anthropic is OAuth + writeAuthFile(JSON.stringify({ + anthropic: { type: "oauth", refresh: "r", access: "a", expires: 1 }, + opencode: { type: "api", key: "sk-x" }, + })) + + // when isProviderUsingOAuth queries each provider + const anthropicOauth = isProviderUsingOAuth("anthropic") + const opencodeOauth = isProviderUsingOAuth("opencode") + + // then only OAuth providers return true + expect(anthropicOauth).toBe(true) + expect(opencodeOauth).toBe(false) + }) + + it("#given api-key auth.json entry #then returns the api auth type", () => { + // given auth.json with an API key for anthropic + writeAuthFile(JSON.stringify({ anthropic: { type: "api", key: "sk-ant-xxx" } })) + + // when getProviderAuthType queries the provider + const authType = getProviderAuthType("anthropic") + + // then the api type is returned + expect(authType).toBe("api") + expect(isProviderUsingOAuth("anthropic")).toBe(false) + }) + + it("#given missing auth.json #then returns undefined with no throw", () => { + // given no auth.json exists (XDG_DATA_HOME points to an empty dir) + rmSync(path.join(tempDataDir, "opencode"), { recursive: true, force: true }) + _resetProviderAuthCacheForTesting() + + // when isProviderUsingOAuth queries a provider + const anthropicOauth = isProviderUsingOAuth("anthropic") + const anthropicType = getProviderAuthType("anthropic") + + // then callers get a safe undefined/false + expect(anthropicOauth).toBe(false) + expect(anthropicType).toBeUndefined() + }) + + it("#given malformed auth.json #then does not throw and returns undefined", () => { + // given a malformed JSON auth file + writeAuthFile("not json at all") + + // when isProviderUsingOAuth queries a provider + const anthropicOauth = isProviderUsingOAuth("anthropic") + + // then detection degrades safely + expect(anthropicOauth).toBe(false) + }) + + it("#given unknown provider #then returns undefined", () => { + // given auth.json without an entry for the queried provider + writeAuthFile(JSON.stringify({ anthropic: { type: "oauth", refresh: "r", access: "a", expires: 1 } })) + + // when querying a provider that is not present + const openai = getProviderAuthType("openai") + + // then undefined + expect(openai).toBeUndefined() + expect(isProviderUsingOAuth("openai")).toBe(false) + }) +}) diff --git a/src/shared/opencode-provider-auth.ts b/src/shared/opencode-provider-auth.ts new file mode 100644 index 000000000..235bea4c8 --- /dev/null +++ b/src/shared/opencode-provider-auth.ts @@ -0,0 +1,84 @@ +import { readFileSync, statSync } from "node:fs" +import * as path from "node:path" + +import { getDataDir } from "./data-path" +import { log } from "./logger" + +/** + * Reads OpenCode's auth.json to detect the auth type used by a provider. + * + * OpenCode stores auth credentials at `/opencode/auth.json` in the + * shape `{ [providerID]: { type: "oauth" | "api" | "wellknown", ... } }`. + * + * The file is read with mtime-based caching so we do not stat/parse it on + * every chat.params invocation. + */ + +type AuthRecord = { + type?: unknown +} + +type AuthCacheEntry = { + mtimeMs: number + map: Map +} + +let cached: AuthCacheEntry | null = null + +function getAuthFilePath(): string { + return path.join(getDataDir(), "opencode", "auth.json") +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + +function loadAuthMap(): Map { + const filePath = getAuthFilePath() + + let mtimeMs: number + try { + mtimeMs = statSync(filePath).mtimeMs + } catch { + cached = null + return new Map() + } + + if (cached && cached.mtimeMs === mtimeMs) { + return cached.map + } + + try { + const raw = readFileSync(filePath, "utf-8") + const parsed: unknown = JSON.parse(raw) + const map = new Map() + if (isRecord(parsed)) { + for (const [providerID, entry] of Object.entries(parsed)) { + if (!isRecord(entry)) continue + const type = (entry as AuthRecord).type + if (typeof type === "string") { + map.set(providerID, type) + } + } + } + cached = { mtimeMs, map } + return map + } catch (error) { + log("[opencode-provider-auth] Failed to read auth.json", { + error: error instanceof Error ? error.message : String(error), + }) + return new Map() + } +} + +export function getProviderAuthType(providerID: string): string | undefined { + return loadAuthMap().get(providerID) +} + +export function isProviderUsingOAuth(providerID: string): boolean { + return getProviderAuthType(providerID) === "oauth" +} + +export function _resetProviderAuthCacheForTesting(): void { + cached = null +} From fe091ef2ae166c81107d9df17983b2fadcaae811 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 15:15:58 +0900 Subject: [PATCH 007/146] chore: bump version to 3.17.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ab4576f04..508ee5b85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode", - "version": "3.17.3", + "version": "3.17.4", "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools", "main": "./dist/index.js", "types": "dist/index.d.ts", From c9350c67fe1a9aa789e433b63a5312f237626f25 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 Apr 2026 06:27:22 +0000 Subject: [PATCH 008/146] release: v3.17.4 --- package.json | 22 +++++++++---------- packages/darwin-arm64/package.json | 2 +- packages/darwin-x64-baseline/package.json | 2 +- packages/darwin-x64/package.json | 2 +- packages/linux-arm64-musl/package.json | 2 +- packages/linux-arm64/package.json | 2 +- packages/linux-x64-baseline/package.json | 2 +- packages/linux-x64-musl-baseline/package.json | 2 +- packages/linux-x64-musl/package.json | 2 +- packages/linux-x64/package.json | 2 +- packages/windows-x64-baseline/package.json | 2 +- packages/windows-x64/package.json | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 508ee5b85..c6f4029a6 100644 --- a/package.json +++ b/package.json @@ -79,17 +79,17 @@ "typescript": "^5.7.3" }, "optionalDependencies": { - "oh-my-opencode-darwin-arm64": "3.17.2", - "oh-my-opencode-darwin-x64": "3.17.2", - "oh-my-opencode-darwin-x64-baseline": "3.17.2", - "oh-my-opencode-linux-arm64": "3.17.2", - "oh-my-opencode-linux-arm64-musl": "3.17.2", - "oh-my-opencode-linux-x64": "3.17.2", - "oh-my-opencode-linux-x64-baseline": "3.17.2", - "oh-my-opencode-linux-x64-musl": "3.17.2", - "oh-my-opencode-linux-x64-musl-baseline": "3.17.2", - "oh-my-opencode-windows-x64": "3.17.2", - "oh-my-opencode-windows-x64-baseline": "3.17.2" + "oh-my-opencode-darwin-arm64": "3.17.4", + "oh-my-opencode-darwin-x64": "3.17.4", + "oh-my-opencode-darwin-x64-baseline": "3.17.4", + "oh-my-opencode-linux-arm64": "3.17.4", + "oh-my-opencode-linux-arm64-musl": "3.17.4", + "oh-my-opencode-linux-x64": "3.17.4", + "oh-my-opencode-linux-x64-baseline": "3.17.4", + "oh-my-opencode-linux-x64-musl": "3.17.4", + "oh-my-opencode-linux-x64-musl-baseline": "3.17.4", + "oh-my-opencode-windows-x64": "3.17.4", + "oh-my-opencode-windows-x64-baseline": "3.17.4" }, "overrides": {}, "trustedDependencies": [ diff --git a/packages/darwin-arm64/package.json b/packages/darwin-arm64/package.json index de3a68cba..ccf706faf 100644 --- a/packages/darwin-arm64/package.json +++ b/packages/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-darwin-arm64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (darwin-arm64)", "license": "MIT", "repository": { diff --git a/packages/darwin-x64-baseline/package.json b/packages/darwin-x64-baseline/package.json index 7533b735d..ac965d73f 100644 --- a/packages/darwin-x64-baseline/package.json +++ b/packages/darwin-x64-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-darwin-x64-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (darwin-x64-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/darwin-x64/package.json b/packages/darwin-x64/package.json index cd086e99c..710360fdb 100644 --- a/packages/darwin-x64/package.json +++ b/packages/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-darwin-x64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (darwin-x64)", "license": "MIT", "repository": { diff --git a/packages/linux-arm64-musl/package.json b/packages/linux-arm64-musl/package.json index 8cb386b19..ade0dd78f 100644 --- a/packages/linux-arm64-musl/package.json +++ b/packages/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-arm64-musl", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)", "license": "MIT", "repository": { diff --git a/packages/linux-arm64/package.json b/packages/linux-arm64/package.json index d74e1c262..f4ac2294d 100644 --- a/packages/linux-arm64/package.json +++ b/packages/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-arm64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-arm64)", "license": "MIT", "repository": { diff --git a/packages/linux-x64-baseline/package.json b/packages/linux-x64-baseline/package.json index bf71d1299..a0d51f8bc 100644 --- a/packages/linux-x64-baseline/package.json +++ b/packages/linux-x64-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/linux-x64-musl-baseline/package.json b/packages/linux-x64-musl-baseline/package.json index 4b89d7bd6..3515050ab 100644 --- a/packages/linux-x64-musl-baseline/package.json +++ b/packages/linux-x64-musl-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64-musl-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/linux-x64-musl/package.json b/packages/linux-x64-musl/package.json index f65f8daf3..528e60b0e 100644 --- a/packages/linux-x64-musl/package.json +++ b/packages/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64-musl", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)", "license": "MIT", "repository": { diff --git a/packages/linux-x64/package.json b/packages/linux-x64/package.json index 9ce7cc1da..621ba280b 100644 --- a/packages/linux-x64/package.json +++ b/packages/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64)", "license": "MIT", "repository": { diff --git a/packages/windows-x64-baseline/package.json b/packages/windows-x64-baseline/package.json index b26c90ed1..78a9ae8f9 100644 --- a/packages/windows-x64-baseline/package.json +++ b/packages/windows-x64-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-windows-x64-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (windows-x64-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/windows-x64/package.json b/packages/windows-x64/package.json index 002bd9d5a..8b6d80e6d 100644 --- a/packages/windows-x64/package.json +++ b/packages/windows-x64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-windows-x64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (windows-x64)", "license": "MIT", "repository": { From a5ae0b838c65bc0aa355e567639c35b520cdf390 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 06:35:11 +0000 Subject: [PATCH 009/146] @omer-koren has signed the CLA in code-yeongyu/oh-my-openagent#3470 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index c39cbfbdb..780e9fe9b 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2839,6 +2839,14 @@ "created_at": "2026-04-15T13:10:30Z", "repoId": 1108837393, "pullRequestNo": 3455 + }, + { + "name": "omer-koren", + "id": 54630488, + "comment_id": 4257838546, + "created_at": "2026-04-16T06:34:57Z", + "repoId": 1108837393, + "pullRequestNo": 3470 } ] } \ No newline at end of file From 1ae32283ef3ff79fbc185575a4a707ddb99a1363 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 18:41:09 +0900 Subject: [PATCH 010/146] fix(anthropic-effort): clamp variant=max for github-copilot Claude models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub Copilot proxies Anthropic's API but does not support output_config.effort: "max" (same constraint as Anthropic OAuth). Previously the anthropic-effort hook early-returned for github-copilot provider, skipping all effort clamping. Users on github-copilot/claude-opus-4.6 with variant=max got HTTP 400 'invalid_reasoning_effort'. Fix: Remove the github-copilot early return. Treat github-copilot as a constrained provider (alongside Anthropic OAuth), clamping max→high. Rename isAnthropicOAuth→isConstrainedProvider to reflect the broader scope. Fixes the remaining user report from #3429. --- src/hooks/anthropic-effort/hook.ts | 27 ++++++++++++------------ src/hooks/anthropic-effort/index.test.ts | 22 ++++++++++++++++--- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/hooks/anthropic-effort/hook.ts b/src/hooks/anthropic-effort/hook.ts index a8f5ecb85..a545768d6 100644 --- a/src/hooks/anthropic-effort/hook.ts +++ b/src/hooks/anthropic-effort/hook.ts @@ -26,13 +26,15 @@ function shouldSkipForInternalAgent(agentName: string | undefined): boolean { } /** - * Claude Pro/Max subscriptions expose a constrained OAuth API that rejects - * `output_config.effort: "max"` (supported values: low | medium | high) even on - * Opus models. Detect OAuth auth by inspecting OpenCode's auth.json. + * Providers that expose constrained APIs rejecting `output_config.effort: "max"` + * (supported values: low | medium | high). Includes: + * - Anthropic OAuth (Claude Pro/Max via third-party clients) + * - GitHub Copilot (proxied Anthropic, doesn't support "max") */ -function isAnthropicOAuth(providerID: string): boolean { - if (providerID !== "anthropic") return false - return isProviderUsingOAuth(providerID) +function isConstrainedProvider(providerID: string): boolean { + if (providerID === "github-copilot") return true + if (providerID === "anthropic") return isProviderUsingOAuth(providerID) + return false } interface ChatParamsInput { @@ -59,9 +61,9 @@ const MAX_VARIANT_BY_TIER: Record = { default: "high", } -function clampVariant(variant: string, isOpus: boolean, isOAuth: boolean): string { +function clampVariant(variant: string, isOpus: boolean, isConstrained: boolean): string { if (variant !== "max") return variant - if (isOAuth) return MAX_VARIANT_BY_TIER.default + if (isConstrained) return MAX_VARIANT_BY_TIER.default return isOpus ? MAX_VARIANT_BY_TIER.opus : MAX_VARIANT_BY_TIER.default } @@ -76,16 +78,15 @@ export function createAnthropicEffortHook() { if (isEffortUnsupportedModel(model.modelID)) return if (message.variant !== "max") return if (!isClaudeProvider(model.providerID, model.modelID)) return - if (model.providerID === "github-copilot") return if (shouldSkipForInternalAgent(agent?.name)) return if (output.options.effort !== undefined) return const opus = isOpusModel(model.modelID) - const oauth = isAnthropicOAuth(model.providerID) - const clamped = clampVariant(message.variant, opus, oauth) + const constrained = isConstrainedProvider(model.providerID) + const clamped = clampVariant(message.variant, opus, constrained) output.options.effort = clamped - const shouldOverrideMessageVariant = !opus || oauth + const shouldOverrideMessageVariant = !opus || constrained if (shouldOverrideMessageVariant) { // Override the variant so OpenCode doesn't pass "max" to the API. @@ -97,7 +98,7 @@ export function createAnthropicEffortHook() { sessionID: input.sessionID, provider: model.providerID, model: model.modelID, - reason: oauth ? "anthropic-oauth" : "non-opus", + reason: constrained ? "constrained-provider" : "non-opus", }) } else { log("anthropic-effort: injected effort=max", { diff --git a/src/hooks/anthropic-effort/index.test.ts b/src/hooks/anthropic-effort/index.test.ts index ef8dc944d..eb164bc9b 100644 --- a/src/hooks/anthropic-effort/index.test.ts +++ b/src/hooks/anthropic-effort/index.test.ts @@ -153,7 +153,7 @@ describe("createAnthropicEffortHook", () => { expect(output.options.effort).toBeUndefined() }) - it("#given github-copilot + claude model #then effort NOT injected", async () => { + it("#given github-copilot + claude opus model #then effort clamped to high (constrained provider)", async () => { // given const hook = createAnthropicEffortHook() const { input, output } = createMockParams({ @@ -164,9 +164,25 @@ describe("createAnthropicEffortHook", () => { // when await hook["chat.params"](input, output) + // then — github-copilot is a constrained provider, clamps max→high + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") + }) + + it("#given github-copilot + claude sonnet model #then effort clamped to high", async () => { + // given + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ + providerID: "github-copilot", + modelID: "claude-sonnet-4-6", + }) + + // when + await hook["chat.params"](input, output) + // then - expect(output.options.effort).toBeUndefined() - expect(input.message.variant).toBe("max") + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") }) describe("#given haiku models (effort unsupported)", () => { From e2f7fbb4c7ab1c2bb4943b81b79aa63884111bf3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 11:45:12 +0000 Subject: [PATCH 011/146] @EnochLi15 has signed the CLA in code-yeongyu/oh-my-openagent#3473 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index 780e9fe9b..7402381a7 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2847,6 +2847,14 @@ "created_at": "2026-04-16T06:34:57Z", "repoId": 1108837393, "pullRequestNo": 3470 + }, + { + "name": "EnochLi15", + "id": 38340798, + "comment_id": 4259785224, + "created_at": "2026-04-16T11:45:01Z", + "repoId": 1108837393, + "pullRequestNo": 3473 } ] } \ No newline at end of file From 611f1cc932b56285e115281bef67c756922d30b1 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 23:02:27 +0900 Subject: [PATCH 012/146] fix(background-agent): remove descendant spawn cap --- src/features/background-agent/manager.test.ts | 13 ++++--- src/features/background-agent/manager.ts | 12 ------- .../subagent-spawn-limits.test.ts | 36 ++----------------- .../background-agent/subagent-spawn-limits.ts | 18 +--------- src/tools/delegate-task/sync-task.ts | 4 +-- 5 files changed, 13 insertions(+), 70 deletions(-) diff --git a/src/features/background-agent/manager.test.ts b/src/features/background-agent/manager.test.ts index 7ad6fea39..b0fffbf6b 100644 --- a/src/features/background-agent/manager.test.ts +++ b/src/features/background-agent/manager.test.ts @@ -2327,7 +2327,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(result).rejects.toThrow("background_task.maxDepth=3") }) - test("should block launches when maxDescendants is reached", async () => { + test("should ignore legacy maxDescendants config when launching multiple descendants", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2354,10 +2354,10 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { const result = manager.launch(input) // then - await expect(result).rejects.toThrow("background_task.maxDescendants=1") + await expect(result).resolves.toBeDefined() }) - test("should consume descendant quota for reserved sync spawns", async () => { + test("should allow spawn assertions after reserveSubagentSpawn even with legacy maxDescendants config", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2376,7 +2376,10 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { const result = manager.assertCanSpawn("session-root") // then - await expect(result).rejects.toThrow("background_task.maxDescendants=1") + await expect(result).resolves.toMatchObject({ + rootSessionID: "session-root", + childDepth: 1, + }) }) test("should fail closed when session lineage lookup fails", async () => { @@ -2407,7 +2410,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { const result = manager.launch(input) // then - await expect(result).rejects.toThrow("background_task.maxDescendants cannot be enforced safely") + await expect(result).rejects.toThrow("background_task.maxDepth cannot be enforced safely") }) test("should release descendant quota when queued task is cancelled before session starts", async () => { diff --git a/src/features/background-agent/manager.ts b/src/features/background-agent/manager.ts index a59ea9530..f418580c2 100644 --- a/src/features/background-agent/manager.ts +++ b/src/features/background-agent/manager.ts @@ -72,8 +72,6 @@ import { } from "./loop-detector" import { createSubagentDepthLimitError, - createSubagentDescendantLimitError, - getMaxRootSessionSpawnBudget, getMaxSubagentDepth, resolveSubagentSpawnContext, type SubagentSpawnContext, @@ -218,16 +216,6 @@ export class BackgroundManager { }) } - const maxRootSessionSpawnBudget = getMaxRootSessionSpawnBudget(this.config) - const descendantCount = this.rootDescendantCounts.get(spawnContext.rootSessionID) ?? 0 - if (descendantCount >= maxRootSessionSpawnBudget) { - throw createSubagentDescendantLimitError({ - rootSessionID: spawnContext.rootSessionID, - descendantCount, - maxDescendants: maxRootSessionSpawnBudget, - }) - } - return spawnContext } diff --git a/src/features/background-agent/subagent-spawn-limits.test.ts b/src/features/background-agent/subagent-spawn-limits.test.ts index e158c0dad..e3094c551 100644 --- a/src/features/background-agent/subagent-spawn-limits.test.ts +++ b/src/features/background-agent/subagent-spawn-limits.test.ts @@ -5,9 +5,6 @@ import { getMaxSubagentDepth, DEFAULT_MAX_SUBAGENT_DEPTH, createSubagentDepthLimitError, - createSubagentDescendantLimitError, - getMaxRootSessionSpawnBudget, - DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET, } from "./subagent-spawn-limits" function createMockClient(sessionGet: OpencodeClient["session"]["get"]): OpencodeClient { @@ -62,7 +59,7 @@ describe("resolveSubagentSpawnContext", () => { const result = resolveSubagentSpawnContext(client, "parent-session") // then - await expect(result).rejects.toThrow(/background_task\.maxDescendants cannot be enforced safely.*lookup failed/) + await expect(result).rejects.toThrow(/background_task\.maxDepth cannot be enforced safely.*lookup failed/) }) }) @@ -77,7 +74,7 @@ describe("resolveSubagentSpawnContext", () => { const result = resolveSubagentSpawnContext(client, "parent-session") // then - await expect(result).rejects.toThrow(/background_task\.maxDescendants cannot be enforced safely.*No session data returned/) + await expect(result).rejects.toThrow(/background_task\.maxDepth cannot be enforced safely.*No session data returned/) }) }) @@ -209,20 +206,6 @@ describe("getMaxSubagentDepth", () => { }) }) -describe("getMaxRootSessionSpawnBudget", () => { - test("returns DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET when no config", () => { - expect(getMaxRootSessionSpawnBudget()).toBe(DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET) - }) - - test("returns config.maxDescendants when provided", () => { - expect(getMaxRootSessionSpawnBudget({ maxDescendants: 10 })).toBe(10) - }) - - test("default is 50", () => { - expect(DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET).toBe(50) - }) -}) - describe("createSubagentDepthLimitError", () => { test("includes childDepth, maxDepth, and session IDs in message", () => { const error = createSubagentDepthLimitError({ @@ -239,18 +222,3 @@ describe("createSubagentDepthLimitError", () => { expect(error.message).toContain("spawn blocked") }) }) - -describe("createSubagentDescendantLimitError", () => { - test("includes descendant count, max, and root session ID", () => { - const error = createSubagentDescendantLimitError({ - rootSessionID: "root-789", - descendantCount: 50, - maxDescendants: 50, - }) - - expect(error.message).toContain("root-789") - expect(error.message).toContain("50") - expect(error.message).toContain("maxDescendants=50") - expect(error.message).toContain("spawn blocked") - }) -}) diff --git a/src/features/background-agent/subagent-spawn-limits.ts b/src/features/background-agent/subagent-spawn-limits.ts index c53a0e358..9483f3247 100644 --- a/src/features/background-agent/subagent-spawn-limits.ts +++ b/src/features/background-agent/subagent-spawn-limits.ts @@ -2,7 +2,6 @@ import type { BackgroundTaskConfig } from "../../config/schema" import type { OpencodeClient } from "./constants" export const DEFAULT_MAX_SUBAGENT_DEPTH = 3 -export const DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET = 50 export interface SubagentSpawnContext { rootSessionID: string @@ -14,10 +13,6 @@ export function getMaxSubagentDepth(config?: BackgroundTaskConfig): number { return config?.maxDepth ?? DEFAULT_MAX_SUBAGENT_DEPTH } -export function getMaxRootSessionSpawnBudget(config?: BackgroundTaskConfig): number { - return config?.maxDescendants ?? DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET -} - export async function resolveSubagentSpawnContext( client: OpencodeClient, parentSessionID: string, @@ -53,7 +48,7 @@ export async function resolveSubagentSpawnContext( } catch (error) { const reason = error instanceof Error ? error.message : String(error) throw new Error( - `Subagent spawn blocked: failed to resolve session lineage for ${parentSessionID}, so background_task.maxDescendants cannot be enforced safely. ${reason}` + `Subagent spawn blocked: failed to resolve session lineage for ${parentSessionID}, so background_task.maxDepth cannot be enforced safely. ${reason}` ) } @@ -84,14 +79,3 @@ export function createSubagentDepthLimitError(input: { `Subagent spawn blocked: child depth ${childDepth} exceeds background_task.maxDepth=${maxDepth}. Parent session: ${parentSessionID}. Root session: ${rootSessionID}. Continue in an existing subagent session instead of spawning another.` ) } - -export function createSubagentDescendantLimitError(input: { - rootSessionID: string - descendantCount: number - maxDescendants: number -}): Error { - const { rootSessionID, descendantCount, maxDescendants } = input - return new Error( - `Subagent spawn blocked: root session ${rootSessionID} already has ${descendantCount} descendants, which meets background_task.maxDescendants=${maxDescendants}. Reuse an existing session instead of spawning another.` - ) -} diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 7675fa0de..4ec84696c 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -37,7 +37,7 @@ export async function executeSyncTask( spawnReservation = await manager.reserveSubagentSpawn(parentContext.sessionID) } - // Depth/descendant guard. We must NOT silently fall back to childDepth: 1 + // Depth guard. We must NOT silently fall back to childDepth: 1 // when the manager is unavailable or lacks the spawn methods, because that // would let subagents recurse without bound. The only safe fallback is // when the manager genuinely cannot enforce limits (legacy SDK), in which @@ -51,7 +51,7 @@ export async function executeSyncTask( } else { log( "[task] WARNING: BackgroundManager has no spawn enforcement methods (reserveSubagentSpawn / assertCanSpawn). " + - "Depth and descendant limits cannot be enforced for this task. This indicates an old SDK or a misconfiguration.", + "Depth limits cannot be enforced for this task. This indicates an old SDK or a misconfiguration.", { parentSessionID: parentContext.sessionID } ) spawnContext = { From 56be458eded42237665b995de5dad91088a276a7 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 23:13:34 +0900 Subject: [PATCH 013/146] fix(config): remove obsolete maxDescendants config --- assets/oh-my-opencode.schema.json | 5 ---- src/config/schema/background-task.test.ts | 24 ----------------- src/config/schema/background-task.ts | 1 - src/features/background-agent/manager.test.ts | 26 +++++++------------ 4 files changed, 9 insertions(+), 47 deletions(-) diff --git a/assets/oh-my-opencode.schema.json b/assets/oh-my-opencode.schema.json index 89a60406d..056c84342 100644 --- a/assets/oh-my-opencode.schema.json +++ b/assets/oh-my-opencode.schema.json @@ -5673,11 +5673,6 @@ "minimum": 1, "maximum": 9007199254740991 }, - "maxDescendants": { - "type": "integer", - "minimum": 1, - "maximum": 9007199254740991 - }, "staleTimeoutMs": { "type": "number", "minimum": 60000 diff --git a/src/config/schema/background-task.test.ts b/src/config/schema/background-task.test.ts index ddfcbafec..e7f1a3f8c 100644 --- a/src/config/schema/background-task.test.ts +++ b/src/config/schema/background-task.test.ts @@ -27,30 +27,6 @@ describe("BackgroundTaskConfigSchema", () => { }) }) - describe("maxDescendants", () => { - describe("#given valid maxDescendants (50)", () => { - test("#when parsed #then returns correct value", () => { - const result = BackgroundTaskConfigSchema.parse({ maxDescendants: 50 }) - - expect(result.maxDescendants).toBe(50) - }) - }) - - describe("#given maxDescendants below minimum (0)", () => { - test("#when parsed #then throws ZodError", () => { - let thrownError: unknown - - try { - BackgroundTaskConfigSchema.parse({ maxDescendants: 0 }) - } catch (error) { - thrownError = error - } - - expect(thrownError).toBeInstanceOf(ZodError) - }) - }) - }) - describe("syncPollTimeoutMs", () => { describe("#given valid syncPollTimeoutMs (120000)", () => { test("#when parsed #then returns correct value", () => { diff --git a/src/config/schema/background-task.ts b/src/config/schema/background-task.ts index 44d16b505..4b62612fa 100644 --- a/src/config/schema/background-task.ts +++ b/src/config/schema/background-task.ts @@ -11,7 +11,6 @@ export const BackgroundTaskConfigSchema = z.object({ providerConcurrency: z.record(z.string(), z.number().min(0)).optional(), modelConcurrency: z.record(z.string(), z.number().min(0)).optional(), maxDepth: z.number().int().min(1).optional(), - maxDescendants: z.number().int().min(1).optional(), /** Stale timeout in milliseconds - interrupt tasks with no activity for this duration (default: 180000 = 3 minutes, minimum: 60000 = 1 minute) */ staleTimeoutMs: z.number().min(60000).optional(), /** Timeout for tasks that never received any progress update, falling back to startedAt (default: 1800000 = 30 minutes, minimum: 60000 = 1 minute) */ diff --git a/src/features/background-agent/manager.test.ts b/src/features/background-agent/manager.test.ts index b0fffbf6b..d76ab8aa2 100644 --- a/src/features/background-agent/manager.test.ts +++ b/src/features/background-agent/manager.test.ts @@ -2327,7 +2327,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(result).rejects.toThrow("background_task.maxDepth=3") }) - test("should ignore legacy maxDescendants config when launching multiple descendants", async () => { + test("allows multiple descendants without a root spawn cap", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2337,7 +2337,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2357,7 +2356,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(result).resolves.toBeDefined() }) - test("should allow spawn assertions after reserveSubagentSpawn even with legacy maxDescendants config", async () => { + test("allows spawn assertions after reserveSubagentSpawn without a root spawn cap", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2367,7 +2366,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) await manager.reserveSubagentSpawn("session-root") @@ -2395,7 +2393,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { ), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2413,7 +2410,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(result).rejects.toThrow("background_task.maxDepth cannot be enforced safely") }) - test("should release descendant quota when queued task is cancelled before session starts", async () => { + test("allows replacement launch when a queued task is cancelled before session starts", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2423,7 +2420,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { defaultConcurrency: 1, maxDescendants: 2 }, + { defaultConcurrency: 1 }, ) const input = { @@ -2448,7 +2445,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { expect(replacementTask.status).toBe("pending") }) - test("should release descendant quota when session creation fails before session starts", async () => { + test("allows retry after session creation fails before session starts", async () => { // given let createAttempts = 0 manager.shutdown() @@ -2475,7 +2472,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }, directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2890,7 +2886,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { } }) - test("should release descendant quota when task completes", async () => { + test("allows relaunch after task completes", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2899,7 +2895,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) stubNotifyParentSession(manager) @@ -2923,7 +2918,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(manager.launch(input)).resolves.toBeDefined() }) - test("should release descendant quota when running task is cancelled", async () => { + test("allows relaunch after running task is cancelled", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2932,7 +2927,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2953,7 +2947,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(manager.launch(input)).resolves.toBeDefined() }) - test("should release descendant quota when task errors", async () => { + test("allows relaunch after task errors", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2962,7 +2956,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2987,7 +2980,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(manager.launch(input)).resolves.toBeDefined() }) - test("should not double-decrement quota when pending task is cancelled", async () => { + test("allows repeated relaunch after pending tasks are cancelled", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2996,7 +2989,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 2 }, ) const input = { From d89e257d8ab4451e045ccf0f60bb27a03b70247e Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 16 Apr 2026 23:13:44 +0900 Subject: [PATCH 014/146] refactor(task): align continuation ids with task_id --- src/agents/atlas/default-prompt-sections.ts | 12 +++---- src/agents/atlas/gemini-prompt-sections.ts | 4 +-- src/agents/atlas/gpt-prompt-sections.ts | 4 +-- src/agents/dynamic-agent-core-sections.ts | 2 +- src/agents/hephaestus/gpt-5-3-codex.ts | 6 ++-- src/agents/hephaestus/gpt-5-4.ts | 8 ++--- src/agents/hephaestus/gpt.ts | 8 ++--- src/agents/sisyphus.ts | 16 ++++----- src/agents/sisyphus/default.ts | 16 ++++----- src/agents/sisyphus/gpt-5-4.ts | 8 ++--- .../task-metadata-contract.test.ts | 4 +-- src/hooks/atlas/verification-reminders.ts | 4 +-- .../keyword-detector/ultrawork/default.ts | 12 +++---- .../keyword-detector/ultrawork/gemini.ts | 8 ++--- src/hooks/task-resume-info/hook.ts | 7 ++-- src/hooks/task-resume-info/index.test.ts | 4 ++- src/plugin/tool-execute-before.test.ts | 17 ++++++++++ src/plugin/tool-execute-before.ts | 15 +++++++-- .../create-background-cancel.ts | 2 +- .../delegate-task/background-continuation.ts | 22 ++++++++++--- .../delegate-task/background-task.test.ts | 9 +++-- src/tools/delegate-task/background-task.ts | 11 ++++++- src/tools/delegate-task/error-formatting.ts | 6 ++-- src/tools/delegate-task/sync-continuation.ts | 33 ++++++++++++------- src/tools/delegate-task/sync-task.ts | 11 +++++-- src/tools/delegate-task/task-id.ts | 5 +++ src/tools/delegate-task/task-schema.test.ts | 1 + src/tools/delegate-task/tools.ts | 19 +++++++---- src/tools/delegate-task/types.ts | 2 ++ 29 files changed, 180 insertions(+), 96 deletions(-) create mode 100644 src/tools/delegate-task/task-id.ts diff --git a/src/agents/atlas/default-prompt-sections.ts b/src/agents/atlas/default-prompt-sections.ts index 46e2634f7..24ba9f807 100644 --- a/src/agents/atlas/default-prompt-sections.ts +++ b/src/agents/atlas/default-prompt-sections.ts @@ -150,16 +150,16 @@ task( ### 3.5 Handle Failures (USE RESUME) -**CRITICAL: When re-delegating, ALWAYS use \`session_id\` parameter.** +**CRITICAL: When re-delegating, ALWAYS use \`task_id\` parameter.** -Every \`task()\` output includes a session_id. STORE IT. +Every \`task()\` output includes a task_id. STORE IT. If task fails: 1. Identify what went wrong 2. **Resume the SAME session** - subagent has full context already: \`\`\`typescript task( - session_id="ses_xyz789", // Session from failed task + task_id="ses_xyz789", // Task ID from failed task load_skills=[...], prompt="FAILED: {error}. Fix by: {specific instruction}" ) @@ -167,7 +167,7 @@ If task fails: 3. Maximum 3 retry attempts with the SAME session 4. If blocked after 3 attempts: Document and continue to independent tasks -**Why session_id is MANDATORY for failures:** +**Why task_id is MANDATORY for failures:** - Subagent already read all files, knows the context - No repeated exploration = 70%+ token savings - Subagent knows what approaches already failed @@ -292,6 +292,6 @@ export const DEFAULT_ATLAS_CRITICAL_RULES = ` - Pass inherited wisdom to every subagent - Parallelize independent tasks - Verify with your own tools -- **Store session_id from every delegation output** -- **Use \`session_id="{session_id}"\` for retries, fixes, and follow-ups** +- **Store task_id from every delegation output** +- **Use \`task_id="{task_id}"\` for retries, fixes, and follow-ups** ` diff --git a/src/agents/atlas/gemini-prompt-sections.ts b/src/agents/atlas/gemini-prompt-sections.ts index 7a84e3d73..2ca4c2bc2 100644 --- a/src/agents/atlas/gemini-prompt-sections.ts +++ b/src/agents/atlas/gemini-prompt-sections.ts @@ -164,10 +164,10 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden ### 3.5 Handle Failures -**CRITICAL: Use \`session_id\` for retries.** +**CRITICAL: Use \`task_id\` for retries.** \`\`\`typescript -task(session_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") +task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") \`\`\` - Maximum 3 retries per task diff --git a/src/agents/atlas/gpt-prompt-sections.ts b/src/agents/atlas/gpt-prompt-sections.ts index 96977f777..1a9f39c26 100644 --- a/src/agents/atlas/gpt-prompt-sections.ts +++ b/src/agents/atlas/gpt-prompt-sections.ts @@ -169,10 +169,10 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden ### 3.5 Handle Failures -**CRITICAL: Use \`session_id\` for retries.** +**CRITICAL: Use \`task_id\` for retries.** \`\`\`typescript -task(session_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") +task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") \`\`\` - Maximum 3 retries per task diff --git a/src/agents/dynamic-agent-core-sections.ts b/src/agents/dynamic-agent-core-sections.ts index dc91fd480..416750a54 100644 --- a/src/agents/dynamic-agent-core-sections.ts +++ b/src/agents/dynamic-agent-core-sections.ts @@ -182,7 +182,7 @@ Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementatio - Single-file fix or trivial change → proceed directly - Anything else (2+ steps, unclear scope, architecture) → \`task(subagent_type="plan", ...)\` FIRST -- Use \`session_id\` to resume the same Plan Agent - ask follow-up questions aggressively +- Use \`task_id\` to resume the same Plan Agent - ask follow-up questions aggressively - If ANY part of the task is ambiguous, ask Plan Agent before guessing Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it.` diff --git a/src/agents/hephaestus/gpt-5-3-codex.ts b/src/agents/hephaestus/gpt-5-3-codex.ts index 2ca2964f7..28127bcc8 100644 --- a/src/agents/hephaestus/gpt-5-3-codex.ts +++ b/src/agents/hephaestus/gpt-5-3-codex.ts @@ -409,9 +409,9 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU Every \`task()\` output includes a session_id. **USE IT for follow-ups.** -- **Task failed/incomplete** - \`session_id="{id}", prompt="Fix: {error}"\` -- **Follow-up on result** - \`session_id="{id}", prompt="Also: {question}"\` -- **Verification failed** - \`session_id="{id}", prompt="Failed: {error}. Fix."\` +- **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\` +- **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\` +- **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\` ${ oracleSection diff --git a/src/agents/hephaestus/gpt-5-4.ts b/src/agents/hephaestus/gpt-5-4.ts index a88b6ea0f..eec4e18b4 100644 --- a/src/agents/hephaestus/gpt-5-4.ts +++ b/src/agents/hephaestus/gpt-5-4.ts @@ -312,10 +312,10 @@ Every delegation prompt needs these 6 sections: After delegation, verify by reading every file the subagent touched. Check: works as expected? follows codebase pattern? Do not trust self-reports. -Every \`task()\` returns a session_id. Use it for all follow-ups: -- Task failed/incomplete: \`session_id="{id}", prompt="Fix: {error}"\` -- Follow-up on result: \`session_id="{id}", prompt="Also: {question}"\` -- Verification failed: \`session_id="{id}", prompt="Failed: {error}. Fix."\` +Every \`task()\` returns a task_id. Use it for all follow-ups: +- Task failed/incomplete: \`task_id="{id}", prompt="Fix: {error}"\` +- Follow-up on result: \`task_id="{id}", prompt="Also: {question}"\` +- Verification failed: \`task_id="{id}", prompt="Failed: {error}. Fix."\` This preserves full context, avoids repeated exploration, saves 70%+ tokens. diff --git a/src/agents/hephaestus/gpt.ts b/src/agents/hephaestus/gpt.ts index cf1a3ea91..712bb9536 100644 --- a/src/agents/hephaestus/gpt.ts +++ b/src/agents/hephaestus/gpt.ts @@ -277,11 +277,11 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU ### Session Continuity -Every \`task()\` output includes a session_id. **USE IT for follow-ups.** +Every \`task()\` output includes a task_id. **USE IT for follow-ups.** -- **Task failed/incomplete** - \`session_id="{id}", prompt="Fix: {error}"\` -- **Follow-up on result** - \`session_id="{id}", prompt="Also: {question}"\` -- **Verification failed** - \`session_id="{id}", prompt="Failed: {error}. Fix."\` +- **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\` +- **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\` +- **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\` ${ oracleSection diff --git a/src/agents/sisyphus.ts b/src/agents/sisyphus.ts index 55b6c1c21..81a863d54 100644 --- a/src/agents/sisyphus.ts +++ b/src/agents/sisyphus.ts @@ -317,15 +317,15 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING: ### Session Continuity (MANDATORY) -Every \`task()\` output includes a session_id. **USE IT.** +Every \`task()\` output includes a task_id. **USE IT.** **ALWAYS continue when:** -- Task failed/incomplete → \`session_id=\"{session_id}\", prompt=\"Fix: {specific error}\"\` -- Follow-up question on result → \`session_id=\"{session_id}\", prompt=\"Also: {question}\"\` -- Multi-turn with same agent → \`session_id=\"{session_id}\"\` - NEVER start fresh -- Verification failed → \`session_id=\"{session_id}\", prompt=\"Failed verification: {error}. Fix.\"\` +- Task failed/incomplete → \`task_id=\"{task_id}\", prompt=\"Fix: {specific error}\"\` +- Follow-up question on result → \`task_id=\"{task_id}\", prompt=\"Also: {question}\"\` +- Multi-turn with same agent → \`task_id=\"{task_id}\"\` - NEVER start fresh +- Verification failed → \`task_id=\"{task_id}\", prompt=\"Failed verification: {error}. Fix.\"\` -**Why session_id is CRITICAL:** +**Why task_id is CRITICAL:** - Subagent has FULL conversation context preserved - No repeated file reads, exploration, or setup - Saves 70%+ tokens on follow-ups @@ -336,10 +336,10 @@ Every \`task()\` output includes a session_id. **USE IT.** task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...") // CORRECT: Resume preserves everything -task(session_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") +task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") \`\`\` -**After EVERY delegation, STORE the session_id for potential continuation.** +**After EVERY delegation, STORE the task_id for potential continuation.** ### Code Changes: - Match existing patterns (if codebase is disciplined) diff --git a/src/agents/sisyphus/default.ts b/src/agents/sisyphus/default.ts index 14895b124..52e237f7c 100644 --- a/src/agents/sisyphus/default.ts +++ b/src/agents/sisyphus/default.ts @@ -389,15 +389,15 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING: ### Session Continuity (MANDATORY) -Every \`task()\` output includes a session_id. **USE IT.** +Every \`task()\` output includes a task_id. **USE IT.** **ALWAYS continue when:** -- Task failed/incomplete → \`session_id="{session_id}", prompt="Fix: {specific error}"\` -- Follow-up question on result → \`session_id="{session_id}", prompt="Also: {question}"\` -- Multi-turn with same agent → \`session_id="{session_id}"\` - NEVER start fresh -- Verification failed → \`session_id="{session_id}", prompt="Failed verification: {error}. Fix."\` +- Task failed/incomplete → \`task_id="{task_id}", prompt="Fix: {specific error}"\` +- Follow-up question on result → \`task_id="{task_id}", prompt="Also: {question}"\` +- Multi-turn with same agent → \`task_id="{task_id}"\` - NEVER start fresh +- Verification failed → \`task_id="{task_id}", prompt="Failed verification: {error}. Fix."\` -**Why session_id is CRITICAL:** +**Why task_id is CRITICAL:** - Subagent has FULL conversation context preserved - No repeated file reads, exploration, or setup - Saves 70%+ tokens on follow-ups @@ -408,10 +408,10 @@ Every \`task()\` output includes a session_id. **USE IT.** task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...") // CORRECT: Resume preserves everything -task(session_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") +task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") \`\`\` -**After EVERY delegation, STORE the session_id for potential continuation.** +**After EVERY delegation, STORE the task_id for potential continuation.** ### Code Changes: - Match existing patterns (if codebase is disciplined) diff --git a/src/agents/sisyphus/gpt-5-4.ts b/src/agents/sisyphus/gpt-5-4.ts index 9e8219015..4667e3466 100644 --- a/src/agents/sisyphus/gpt-5-4.ts +++ b/src/agents/sisyphus/gpt-5-4.ts @@ -387,10 +387,10 @@ Post-delegation: delegation never substitutes for verification. Always run \` { // given const link = { sessionId: "ses_bg_123", - taskId: "bg_123", + taskId: "ses_bg_123", backgroundTaskId: "bg_123", agent: "explore", category: "quick", @@ -29,7 +29,7 @@ describe("buildTaskMetadataBlock", () => { // then expect(block).toBe( - "\nsession_id: ses_bg_123\ntask_id: bg_123\nbackground_task_id: bg_123\nsubagent: explore\ncategory: quick\n" + "\nsession_id: ses_bg_123\ntask_id: ses_bg_123\nbackground_task_id: bg_123\nsubagent: explore\ncategory: quick\n" ) }) }) diff --git a/src/hooks/atlas/verification-reminders.ts b/src/hooks/atlas/verification-reminders.ts index b00618ecd..9bde55b9d 100644 --- a/src/hooks/atlas/verification-reminders.ts +++ b/src/hooks/atlas/verification-reminders.ts @@ -29,7 +29,7 @@ Your completion will NOT be recorded until you complete ALL of the following: If anything fails while closing this out, resume the same session immediately: \`\`\`typescript -task(session_id="${sessionId}", load_skills=[], prompt="fix: checkbox not recorded correctly") +task(task_id="${sessionId}", load_skills=[], prompt="fix: checkbox not recorded correctly") \`\`\` **Your completion is NOT tracked until the checkbox is marked in the plan file.** @@ -47,7 +47,7 @@ ${VERIFICATION_REMINDER} **If ANY verification fails, use this immediately:** \`\`\` -task(session_id="${sessionId}", load_skills=[], prompt="fix: [describe the specific failure]") +task(task_id="${sessionId}", load_skills=[], prompt="fix: [describe the specific failure]") \`\`\` ${buildReuseHint(sessionId)}` diff --git a/src/hooks/keyword-detector/ultrawork/default.ts b/src/hooks/keyword-detector/ultrawork/default.ts index 37790d9ea..0c95c5f1e 100644 --- a/src/hooks/keyword-detector/ultrawork/default.ts +++ b/src/hooks/keyword-detector/ultrawork/default.ts @@ -115,15 +115,15 @@ task(subagent_type="plan", load_skills=[], run_in_background=false, prompt=" { await afterHook(input, output) expect(output.output).toContain("to continue:") + expect(output.output).toContain('task(task_id="ses_abc123"') expect(output.output).toContain("ses_abc123") }) @@ -74,6 +75,7 @@ describe("createTaskResumeInfoHook", () => { await afterHook(input, output) expect(output.output).toContain("run_in_background=false") + expect(output.output).toContain('task_id="ses_abc123"') }) }) }) @@ -120,7 +122,7 @@ describe("createTaskResumeInfoHook", () => { const output = { title: "task", output: - 'Done.\nSession ID: ses_abc123\nto continue: task(session_id="ses_abc123", load_skills=[], prompt="...")', + 'Done.\nSession ID: ses_abc123\nto continue: task(task_id="ses_abc123", load_skills=[], run_in_background=false, prompt="...")', metadata: {}, } diff --git a/src/plugin/tool-execute-before.test.ts b/src/plugin/tool-execute-before.test.ts index 80daa79a8..f1f3a30b5 100644 --- a/src/plugin/tool-execute-before.test.ts +++ b/src/plugin/tool-execute-before.test.ts @@ -161,6 +161,23 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBe("explore") }) + test("normalizes task_id into the canonical resume argument", async () => { + //#given + const ctx = createCtxWithSessionMessages([ + { info: { role: "assistant", agent: "oracle" } }, + ]) + const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) + const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } + const output = { args: { task_id: "ses_resume_123", description: "Continue task", prompt: "fix it" } as Record } + + //#when + await handler(input, output) + + //#then + expect(output.args.task_id).toBe("ses_resume_123") + expect(output.args.subagent_type).toBe("oracle") + }) + test("falls back to 'continue' when session has no agent info", async () => { //#given const ctx = createCtxWithSessionMessages([ diff --git a/src/plugin/tool-execute-before.ts b/src/plugin/tool-execute-before.ts index 68b1545ea..dcd47f222 100644 --- a/src/plugin/tool-execute-before.ts +++ b/src/plugin/tool-execute-before.ts @@ -100,12 +100,21 @@ export function createToolExecuteBeforeHandler(args: { const argsObject = output.args const category = typeof argsObject.category === "string" ? argsObject.category : undefined const subagentType = typeof argsObject.subagent_type === "string" ? argsObject.subagent_type : undefined - const sessionId = typeof argsObject.session_id === "string" ? argsObject.session_id : undefined + const taskId = + typeof argsObject.task_id === "string" + ? argsObject.task_id + : typeof argsObject.session_id === "string" + ? argsObject.session_id + : undefined + + if (taskId && typeof argsObject.task_id !== "string") { + argsObject.task_id = taskId + } if (category) { argsObject.subagent_type = "sisyphus-junior" - } else if (!subagentType && sessionId) { - const resolvedAgent = await resolveSessionAgent(ctx.client, sessionId) + } else if (!subagentType && taskId) { + const resolvedAgent = await resolveSessionAgent(ctx.client, taskId) argsObject.subagent_type = resolvedAgent ?? "continue" } diff --git a/src/tools/background-task/create-background-cancel.ts b/src/tools/background-task/create-background-cancel.ts index 49fc4e5bb..a61c280f8 100644 --- a/src/tools/background-task/create-background-cancel.ts +++ b/src/tools/background-task/create-background-cancel.ts @@ -59,7 +59,7 @@ export function createBackgroundCancel(manager: BackgroundManager, _client: Back To continue a cancelled task, use: \`\`\` -task(session_id="", prompt="Continue: ") +task(task_id="", prompt="Continue: ") \`\`\` Continuable sessions: diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index dd0850439..becf732b9 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -3,6 +3,8 @@ import type { ExecutorContext, ParentContext } from "./executor-types" import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { getTaskID } from "./task-id" export async function executeBackgroundContinuation( args: DelegateTaskArgs, @@ -13,8 +15,13 @@ export async function executeBackgroundContinuation( const { manager } = executorCtx try { + const taskID = getTaskID(args) + if (!taskID) { + throw new Error("task_id is required to continue a background task") + } + const task = await manager.resume({ - sessionId: args.session_id!, + sessionId: taskID, prompt: args.prompt, parentSessionID: parentContext.sessionID, parentMessageID: parentContext.messageID, @@ -31,6 +38,8 @@ export async function executeBackgroundContinuation( load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, + taskId: task.sessionID, + backgroundTaskId: task.id, sessionId: task.sessionID, command: args.command, model: task.model ? { providerID: task.model.providerID, modelID: task.model.modelID } : undefined, @@ -50,14 +59,17 @@ System notifies on completion. Use \`background_output\` with task_id="${task.id Do NOT call background_output now. Wait for notification first. - -session_id: ${task.sessionID} -${task.agent ? `subagent: ${task.agent}\n` : ""}` +${buildTaskMetadataBlock({ + sessionId: task.sessionID, + taskId: task.sessionID, + backgroundTaskId: task.id, + agent: task.agent, + })}` } catch (error) { return formatDetailedError(error, { operation: "Continue background task", args, - sessionID: args.session_id, + sessionID: getTaskID(args), }) } } diff --git a/src/tools/delegate-task/background-task.test.ts b/src/tools/delegate-task/background-task.test.ts index 84a7bc644..3837dbb6e 100644 --- a/src/tools/delegate-task/background-task.test.ts +++ b/src/tools/delegate-task/background-task.test.ts @@ -104,11 +104,14 @@ describeFn("executeBackgroundTask output/session metadata compatibility", () => //#then - output and metadata should include canonical session linkage expectFn(result).toContain("") expectFn(result).toContain("session_id: ses_sub_123") - expectFn(result).toContain("task_id: bg_resolved") + expectFn(result).toContain("task_id: ses_sub_123") expectFn(result).toContain("background_task_id: bg_resolved") + expectFn(result).toContain("subagent: explore") expectFn(result).toContain("Background Task ID: bg_resolved") expectFn(metadataCalls).toHaveLength(1) expectFn(metadataCalls[0].metadata.sessionId).toBe("ses_sub_123") + expectFn(metadataCalls[0].metadata.taskId).toBe("ses_sub_123") + expectFn(metadataCalls[0].metadata.backgroundTaskId).toBe("bg_resolved") }) testFn("captures late-resolved session id and emits synced metadata", async () => { @@ -152,10 +155,12 @@ describeFn("executeBackgroundTask output/session metadata compatibility", () => //#then - late session id still propagates to task metadata contract expectFn(result).toContain("session_id: ses_late_123") - expectFn(result).toContain("task_id: bg_late") + expectFn(result).toContain("task_id: ses_late_123") expectFn(result).toContain("background_task_id: bg_late") expectFn(metadataCalls).toHaveLength(1) expectFn(metadataCalls[0].metadata.sessionId).toBe("ses_late_123") + expectFn(metadataCalls[0].metadata.taskId).toBe("ses_late_123") + expectFn(metadataCalls[0].metadata.backgroundTaskId).toBe("bg_late") }) testFn("passes question-deny session permission when launching delegate task", async () => { diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 73d43ad02..17b3bd632 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -10,6 +10,7 @@ import { SessionCategoryRegistry } from "../../shared/session-category-registry" import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied-session-permission" import { setSessionFallbackChain } from "../../hooks/model-fallback/hook" import { stripAgentListSortPrefix } from "../../shared/agent-display-names" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" function continueSessionSetup(args: { taskID: string @@ -125,6 +126,8 @@ export async function executeBackgroundTask( description: args.description, run_in_background: args.run_in_background, command: args.command, + ...(sessionId ? { taskId: sessionId } : {}), + backgroundTaskId: task.id, ...(sessionId ? { sessionId } : {}), ...(categoryModel ? { model: { providerID: categoryModel.providerID, modelID: categoryModel.modelID } } : {}), } @@ -136,7 +139,13 @@ export async function executeBackgroundTask( await publishToolMetadata(ctx, unstableMeta) const taskMetadataBlock = sessionId - ? `\n\n\nsession_id: ${sessionId}\ntask_id: ${task.id}\nbackground_task_id: ${task.id}\n` + ? `\n\n${buildTaskMetadataBlock({ + sessionId, + taskId: sessionId, + backgroundTaskId: task.id, + agent: task.agent, + category: args.category, + })}` : "" return `Background task launched. diff --git a/src/tools/delegate-task/error-formatting.ts b/src/tools/delegate-task/error-formatting.ts index f2c24abc5..9b7b98ab2 100644 --- a/src/tools/delegate-task/error-formatting.ts +++ b/src/tools/delegate-task/error-formatting.ts @@ -1,4 +1,5 @@ import type { DelegateTaskArgs } from "./types" +import { getTaskID } from "./task-id" /** * Context for error formatting. @@ -35,8 +36,9 @@ export function formatDetailedError(error: unknown, ctx: ErrorContext): string { lines.push(`- subagent_type: ${ctx.args.subagent_type ?? "(none)"}`) lines.push(`- run_in_background: ${ctx.args.run_in_background}`) lines.push(`- load_skills: [${ctx.args.load_skills?.join(", ") ?? ""}]`) - if (ctx.args.session_id) { - lines.push(`- session_id: ${ctx.args.session_id}`) + const taskID = getTaskID(ctx.args) + if (taskID) { + lines.push(`- task_id: ${taskID}`) } } diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index a8e412ece..45b06ea88 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -12,6 +12,8 @@ import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continua import { setSessionTools } from "../../shared/session-tools-store" import { normalizeSDKResponse } from "../../shared" import { buildTaskPrompt } from "./prompt-builder" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { getTaskID } from "./task-id" export async function executeSyncContinuation( args: DelegateTaskArgs, @@ -21,7 +23,11 @@ export async function executeSyncContinuation( ): Promise { const { client, syncPollTimeoutMs, sisyphusAgentConfig } = executorCtx const toastManager = getTaskToastManager() - const taskId = `resume_sync_${args.session_id!.slice(0, 8)}` + const continuationID = getTaskID(args) + if (!continuationID) { + throw new Error("task_id is required to continue a sync task") + } + const taskId = `resume_sync_${continuationID.slice(0, 8)}` const startTime = new Date() if (toastManager) { @@ -42,7 +48,7 @@ export async function executeSyncContinuation( try { try { - const messagesResp = await client.session.messages({ path: { id: args.session_id! } }) + const messagesResp = await client.session.messages({ path: { id: continuationID } }) const messages = normalizeSDKResponse(messagesResp, [] as SessionMessage[]) anchorMessageCount = messages.length for (let i = messages.length - 1; i >= 0; i--) { @@ -55,7 +61,7 @@ export async function executeSyncContinuation( } } } catch { - const resumeMessageDir = getMessageDir(args.session_id!) + const resumeMessageDir = getMessageDir(continuationID) const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null resumeAgent = resumeMessage?.agent resumeModel = resumeMessage?.model?.providerID && resumeMessage?.model?.modelID @@ -71,7 +77,8 @@ export async function executeSyncContinuation( load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, - sessionId: args.session_id, + taskId: continuationID, + sessionId: continuationID, sync: true, command: args.command, model: resumeModel, @@ -88,10 +95,10 @@ export async function executeSyncContinuation( question: false, ...(resumeAgent ? getAgentToolRestrictions(resumeAgent) : {}), } - setSessionTools(args.session_id!, tools) + setSessionTools(continuationID, tools) await promptWithModelSuggestionRetry(client, { - path: { id: args.session_id! }, + path: { id: continuationID }, body: { ...(resumeAgent !== undefined ? { agent: resumeAgent } : {}), ...(resumeModel !== undefined ? { model: resumeModel } : {}), @@ -105,12 +112,12 @@ export async function executeSyncContinuation( toastManager.removeTask(taskId) } const errorMessage = promptError instanceof Error ? promptError.message : String(promptError) - return `Failed to send continuation prompt: ${errorMessage}\n\nSession ID: ${args.session_id}` + return `Failed to send continuation prompt: ${errorMessage}\n\nTask ID: ${continuationID}` } try { const pollError = await deps.pollSyncSession(ctx, client, { - sessionID: args.session_id!, + sessionID: continuationID, agentToUse: resumeAgent ?? "continue", toastManager, taskId, @@ -120,7 +127,7 @@ export async function executeSyncContinuation( return pollError } - const result = await deps.fetchSyncResult(client, args.session_id!, anchorMessageCount) + const result = await deps.fetchSyncResult(client, continuationID, anchorMessageCount) if (!result.ok) { return result.error } @@ -133,9 +140,11 @@ export async function executeSyncContinuation( ${result.textContent || "(No text output)"} - -session_id: ${args.session_id} -${resumeAgent ? `subagent: ${resumeAgent}\n` : ""}` +${buildTaskMetadataBlock({ + sessionId: continuationID, + taskId: continuationID, + agent: resumeAgent, + })}` } finally { if (toastManager) { toastManager.removeTask(taskId) diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 4ec84696c..6cd42bb93 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -11,6 +11,7 @@ import { formatDetailedError } from "./error-formatting" import { syncTaskDeps, type SyncTaskDeps } from "./sync-task-deps" import { setSessionFallbackChain, clearSessionFallbackChain } from "../../hooks/model-fallback/hook" import { retrySyncPromptWithFallbacks } from "./sync-task-fallback" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" export async function executeSyncTask( args: DelegateTaskArgs, @@ -122,6 +123,7 @@ export async function executeSyncTask( load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, + taskId: sessionID, sessionId: sessionID, sync: true, spawnDepth: spawnContext.childDepth, @@ -210,9 +212,12 @@ Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}${mod ${result.textContent || "(No text output)"} - -session_id: ${sessionID} -` +${buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + agent: agentToUse, + category: args.category, + })}` } finally { if (toastManager && taskId !== undefined) { toastManager.removeTask(taskId) diff --git a/src/tools/delegate-task/task-id.ts b/src/tools/delegate-task/task-id.ts new file mode 100644 index 000000000..71ec223a6 --- /dev/null +++ b/src/tools/delegate-task/task-id.ts @@ -0,0 +1,5 @@ +import type { DelegateTaskArgs } from "./types" + +export function getTaskID(args: Pick): string | undefined { + return args.task_id ?? args.session_id +} diff --git a/src/tools/delegate-task/task-schema.test.ts b/src/tools/delegate-task/task-schema.test.ts index 0a6f1c7ee..c50d175bc 100644 --- a/src/tools/delegate-task/task-schema.test.ts +++ b/src/tools/delegate-task/task-schema.test.ts @@ -41,6 +41,7 @@ function createDelegateTask(...args: Parameters Date: Thu, 16 Apr 2026 23:18:38 +0900 Subject: [PATCH 015/146] refactor(task): drop session_id resume alias --- src/plugin/tool-execute-before.test.ts | 12 +++++------ src/plugin/tool-execute-before.ts | 11 +--------- src/tools/delegate-task/AGENTS.md | 4 ++-- .../background-continuation.test.ts | 4 ++-- .../metadata-model-unification.test.ts | 4 ++-- .../delegate-task/sync-continuation.test.ts | 20 +++++++++---------- src/tools/delegate-task/task-id.ts | 4 ++-- src/tools/delegate-task/tools.test.ts | 18 ++++++++--------- src/tools/delegate-task/tools.ts | 7 +------ src/tools/delegate-task/types.ts | 2 -- 10 files changed, 35 insertions(+), 51 deletions(-) diff --git a/src/plugin/tool-execute-before.test.ts b/src/plugin/tool-execute-before.test.ts index f1f3a30b5..76d11a33b 100644 --- a/src/plugin/tool-execute-before.test.ts +++ b/src/plugin/tool-execute-before.test.ts @@ -143,7 +143,7 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBe("sisyphus-junior") }) - test("resolves subagent_type from session first message when session_id provided without subagent_type", async () => { + test("resolves subagent_type from session first message when task_id is provided without subagent_type", async () => { //#given const ctx = createCtxWithSessionMessages([ { info: { role: "user" } }, @@ -152,7 +152,7 @@ describe("createToolExecuteBeforeHandler", () => { ]) const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } - const output = { args: { session_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } + const output = { args: { task_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } //#when await handler(input, output) @@ -186,7 +186,7 @@ describe("createToolExecuteBeforeHandler", () => { ]) const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } - const output = { args: { session_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } + const output = { args: { task_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } //#when await handler(input, output) @@ -195,12 +195,12 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBe("continue") }) - test("preserves subagent_type when session_id is provided with explicit subagent_type", async () => { + test("preserves subagent_type when task_id is provided with explicit subagent_type", async () => { //#given const ctx = createCtxWithSessionMessages() const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } - const output = { args: { session_id: "ses_abc123", subagent_type: "explore", description: "Continue explore" } as Record } + const output = { args: { task_id: "ses_abc123", subagent_type: "explore", description: "Continue explore" } as Record } //#when await handler(input, output) @@ -223,7 +223,7 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBeUndefined() }) - test("does not set subagent_type when neither category nor session_id is provided and subagent_type is present", async () => { + test("does not set subagent_type when neither category nor task_id is provided and subagent_type is present", async () => { //#given const ctx = createCtxWithSessionMessages() const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) diff --git a/src/plugin/tool-execute-before.ts b/src/plugin/tool-execute-before.ts index dcd47f222..5c54fba7b 100644 --- a/src/plugin/tool-execute-before.ts +++ b/src/plugin/tool-execute-before.ts @@ -100,16 +100,7 @@ export function createToolExecuteBeforeHandler(args: { const argsObject = output.args const category = typeof argsObject.category === "string" ? argsObject.category : undefined const subagentType = typeof argsObject.subagent_type === "string" ? argsObject.subagent_type : undefined - const taskId = - typeof argsObject.task_id === "string" - ? argsObject.task_id - : typeof argsObject.session_id === "string" - ? argsObject.session_id - : undefined - - if (taskId && typeof argsObject.task_id !== "string") { - argsObject.task_id = taskId - } + const taskId = typeof argsObject.task_id === "string" ? argsObject.task_id : undefined if (category) { argsObject.subagent_type = "sisyphus-junior" diff --git a/src/tools/delegate-task/AGENTS.md b/src/tools/delegate-task/AGENTS.md index f160a7d7b..e928a37e6 100644 --- a/src/tools/delegate-task/AGENTS.md +++ b/src/tools/delegate-task/AGENTS.md @@ -32,7 +32,7 @@ sync-task.ts → sync-session-creator.ts → sync-prompt-sender.ts → sync-session-poller.ts → sync-result-fetcher.ts ``` -Each file handles one step. `sync-continuation.ts` handles session continuation (resume with session_id). +Each file handles one step. `sync-continuation.ts` handles session continuation (resume with task_id). ## BACKGROUND EXECUTION @@ -40,7 +40,7 @@ Each file handles one step. `sync-continuation.ts` handles session continuation background-task.ts → BackgroundManager.launch() → (async polling) → background-continuation.ts ``` -`background-continuation.ts` handles `session_id` resume for existing background tasks. +`background-continuation.ts` handles `task_id` resume for existing background tasks. ## CATEGORY RESOLUTION diff --git a/src/tools/delegate-task/background-continuation.test.ts b/src/tools/delegate-task/background-continuation.test.ts index f97c2d143..2b0e768c9 100644 --- a/src/tools/delegate-task/background-continuation.test.ts +++ b/src/tools/delegate-task/background-continuation.test.ts @@ -30,7 +30,7 @@ describe("executeBackgroundContinuation - subagent metadata", () => { } const args = { - session_id: "ses_resumed_123", + task_id: "ses_resumed_123", prompt: "continue working", description: "resume oracle", load_skills: [], @@ -76,7 +76,7 @@ describe("executeBackgroundContinuation - subagent metadata", () => { } const args = { - session_id: "ses_resumed_456", + task_id: "ses_resumed_456", prompt: "continue", description: "resume task", load_skills: [], diff --git a/src/tools/delegate-task/metadata-model-unification.test.ts b/src/tools/delegate-task/metadata-model-unification.test.ts index 2cb67a8d2..fbd407015 100644 --- a/src/tools/delegate-task/metadata-model-unification.test.ts +++ b/src/tools/delegate-task/metadata-model-unification.test.ts @@ -122,7 +122,7 @@ describe("metadata model unification", () => { const ctx = makeMockCtx() const args: DelegateTaskArgs = { description: "continue", prompt: "keep going", - load_skills: [], run_in_background: true, session_id: "ses_resumed", + load_skills: [], run_in_background: true, task_id: "ses_resumed", } await executeBackgroundContinuation(args, ctx, { @@ -144,7 +144,7 @@ describe("metadata model unification", () => { const ctx = makeMockCtx() const args: DelegateTaskArgs = { description: "continue", prompt: "keep going", - load_skills: [], run_in_background: false, session_id: "ses_cont", + load_skills: [], run_in_background: false, task_id: "ses_cont", } const deps = { diff --git a/src/tools/delegate-task/sync-continuation.test.ts b/src/tools/delegate-task/sync-continuation.test.ts index fa05e93ab..47205ce73 100644 --- a/src/tools/delegate-task/sync-continuation.test.ts +++ b/src/tools/delegate-task/sync-continuation.test.ts @@ -86,7 +86,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -148,7 +148,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -214,7 +214,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -278,7 +278,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -335,7 +335,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -395,7 +395,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue working", description: "resume oracle task", load_skills: [], @@ -449,7 +449,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue working", description: "resume task", load_skills: [], @@ -514,7 +514,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue working", description: "resume explore task", load_skills: [], @@ -584,7 +584,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue researching", description: "resume librarian task", load_skills: [], @@ -654,7 +654,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue planning", description: "resume prometheus task", load_skills: [], diff --git a/src/tools/delegate-task/task-id.ts b/src/tools/delegate-task/task-id.ts index 71ec223a6..c42697898 100644 --- a/src/tools/delegate-task/task-id.ts +++ b/src/tools/delegate-task/task-id.ts @@ -1,5 +1,5 @@ import type { DelegateTaskArgs } from "./types" -export function getTaskID(args: Pick): string | undefined { - return args.task_id ?? args.session_id +export function getTaskID(args: Pick): string | undefined { + return args.task_id } diff --git a/src/tools/delegate-task/tools.test.ts b/src/tools/delegate-task/tools.test.ts index 5353ed6d5..8fb3156a2 100644 --- a/src/tools/delegate-task/tools.test.ts +++ b/src/tools/delegate-task/tools.test.ts @@ -1359,7 +1359,7 @@ describe("sisyphus-task", () => { )).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED") }) - test("#given session_id without run_in_background #when executing #then throws required parameter error", async () => { + test("#given task_id without run_in_background #when executing #then throws required parameter error", async () => { // given const { createDelegateTask } = require("./tools") const mockManager = { resume: async () => ({ id: "task-1", sessionID: "ses_1", status: "running" }) } @@ -1381,14 +1381,14 @@ describe("sisyphus-task", () => { { description: "Continue without run flag", prompt: "Continue", - session_id: "ses_existing", + task_id: "ses_existing", load_skills: [], }, { sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal } )).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED") }) - test("#given no category no subagent_type no session_id and no run_in_background #when executing #then throws required parameter error", async () => { + test("#given no category no subagent_type no task_id and no run_in_background #when executing #then throws required parameter error", async () => { // given const { createDelegateTask } = require("./tools") const mockManager = { launch: async () => ({}) } @@ -1719,8 +1719,8 @@ describe("sisyphus-task", () => { }, { timeout: 10000 }) }) - describe("session_id with background parameter", () => { - test("session_id with background=false should wait for result and return content", async () => { + describe("task_id with background parameter", () => { + test("task_id with background=false should wait for result and return content", async () => { // Note: This test needs extended timeout because the implementation has MIN_STABILITY_TIME_MS = 5000 // given const { createDelegateTask } = require("./tools") @@ -1808,7 +1808,7 @@ describe("sisyphus-task", () => { { description: "Continue test", prompt: "Continue the task", - session_id: "ses_continue_test", + task_id: "ses_continue_test", run_in_background: false, load_skills: ["git-master"], }, @@ -1905,7 +1905,7 @@ describe("sisyphus-task", () => { { description: "Continue with variant", prompt: "Continue the task", - session_id: "ses_var_test", + task_id: "ses_var_test", run_in_background: false, load_skills: [], }, @@ -1920,7 +1920,7 @@ describe("sisyphus-task", () => { expect(callArgs.body.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) }, { timeout: 10000 }) - test("session_id with background=true should return immediately without waiting", async () => { + test("task_id with background=true should return immediately without waiting", async () => { // given const { createDelegateTask } = require("./tools") @@ -1964,7 +1964,7 @@ describe("sisyphus-task", () => { { description: "Continue bg test", prompt: "Continue in background", - session_id: "ses_bg_continue", + task_id: "ses_bg_continue", run_in_background: true, load_skills: ["git-master"], }, diff --git a/src/tools/delegate-task/tools.ts b/src/tools/delegate-task/tools.ts index 56e177a6d..f53d50fb2 100644 --- a/src/tools/delegate-task/tools.ts +++ b/src/tools/delegate-task/tools.ts @@ -85,7 +85,6 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini - subagent_type: Use specific agent directly (explore, librarian, oracle, metis, momus) - run_in_background: REQUIRED. true=async (returns task_id), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries. - task_id: Existing task to continue (from previous task output). Continues the same subagent session with FULL CONTEXT PRESERVED. - - session_id: Deprecated alias for task_id. Accepted for backward compatibility. - command: The command that triggered this task (optional, for slash command tracking). **WHEN TO USE task_id:** @@ -105,14 +104,10 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini category: tool.schema.string().optional().describe(`REQUIRED if subagent_type not provided. Do NOT provide both category and subagent_type.`), subagent_type: tool.schema.string().optional().describe("REQUIRED if category not provided. Do NOT provide both category and subagent_type."), task_id: tool.schema.string().optional().describe("Existing task to continue. Canonical resume identifier."), - session_id: tool.schema.string().optional().describe("Deprecated alias for task_id. Existing task to continue."), command: tool.schema.string().optional().describe("The command that triggered this task"), }, async execute(args: DelegateTaskArgs, toolContext) { const ctx = toolContext as ToolContextWithMetadata - if (!args.task_id && args.session_id) { - args.task_id = args.session_id - } if (args.category) { if (args.subagent_type && args.subagent_type !== SISYPHUS_JUNIOR_AGENT) { @@ -163,7 +158,7 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini const parentContext = await resolveParentContext(ctx, options.client) - if (args.task_id || args.session_id) { + if (args.task_id) { if (runInBackground) { return executeBackgroundContinuation(args, ctx, options, parentContext) } diff --git a/src/tools/delegate-task/types.ts b/src/tools/delegate-task/types.ts index bf853ef41..987e821a2 100644 --- a/src/tools/delegate-task/types.ts +++ b/src/tools/delegate-task/types.ts @@ -15,8 +15,6 @@ export interface DelegateTaskArgs { subagent_type?: string run_in_background: boolean task_id?: string - /** @deprecated Use task_id instead. */ - session_id?: string command?: string load_skills: string[] execute?: { From e97953e390ba83c2eb44fba65c7126a4490e1fbc Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 12:08:39 +0900 Subject: [PATCH 016/146] fix(build): externalize zod from plugin bundle to prevent dual-instance crash When oh-my-openagent is loaded by opencode 1.4.6+, both sides ship zod v4 but as two separate instances. zod v4 uses instance-identity checks (schema._zod.def) that fail across module boundaries, causing: TypeError: undefined is not an object (evaluating 'n._zod.def') Fix: - Add --external zod to the plugin bundle build command so the plugin resolves zod from opencode's runtime instead of embedding its own copy - Move zod from dependencies to peerDependencies (^4.0.0) so package managers know to deduplicate on a single shared instance - Keep zod in devDependencies so local build/test continues to work The plugin dist/index.js no longer contains node_modules/zod/v4 internals. Fixes #3479 --- bun.lock | 49 ++++++++++++++++++++++++++----------------------- package.json | 13 ++++++++----- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/bun.lock b/bun.lock index d3c61f010..77c29ca5b 100644 --- a/bun.lock +++ b/bun.lock @@ -21,26 +21,29 @@ "picomatch": "^4.0.2", "posthog-node": "^5.29.2", "vscode-jsonrpc": "^8.2.0", - "zod": "^4.3.0", }, "devDependencies": { "@types/js-yaml": "^4.0.9", "@types/picomatch": "^3.0.2", "bun-types": "1.3.11", "typescript": "^5.7.3", + "zod": "^4.3.0", }, "optionalDependencies": { - "oh-my-opencode-darwin-arm64": "3.17.2", - "oh-my-opencode-darwin-x64": "3.17.2", - "oh-my-opencode-darwin-x64-baseline": "3.17.2", - "oh-my-opencode-linux-arm64": "3.17.2", - "oh-my-opencode-linux-arm64-musl": "3.17.2", - "oh-my-opencode-linux-x64": "3.17.2", - "oh-my-opencode-linux-x64-baseline": "3.17.2", - "oh-my-opencode-linux-x64-musl": "3.17.2", - "oh-my-opencode-linux-x64-musl-baseline": "3.17.2", - "oh-my-opencode-windows-x64": "3.17.2", - "oh-my-opencode-windows-x64-baseline": "3.17.2", + "oh-my-opencode-darwin-arm64": "3.17.4", + "oh-my-opencode-darwin-x64": "3.17.4", + "oh-my-opencode-darwin-x64-baseline": "3.17.4", + "oh-my-opencode-linux-arm64": "3.17.4", + "oh-my-opencode-linux-arm64-musl": "3.17.4", + "oh-my-opencode-linux-x64": "3.17.4", + "oh-my-opencode-linux-x64-baseline": "3.17.4", + "oh-my-opencode-linux-x64-musl": "3.17.4", + "oh-my-opencode-linux-x64-musl-baseline": "3.17.4", + "oh-my-opencode-windows-x64": "3.17.4", + "oh-my-opencode-windows-x64-baseline": "3.17.4", + }, + "peerDependencies": { + "zod": "^4.0.0", }, }, }, @@ -238,27 +241,27 @@ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - "oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.2", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-GcEMpe2Q9ocbXtJgcdY1ZnINdpyp+FU6lHeuhqSMaFj9Eba3QTZ7p87PKpV0rwHvQ2q4nyb47Am+JheKVptRhg=="], + "oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.4", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-N135KhfHom/qiP3lgMHfY8DvRNVyOzZMuUs6p6uYTekLduSg3i72Pnc2WyNTZEKFX2yehaLjC5ireY8SnRCbdg=="], - "oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.2", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-KEHAOljGrKMWlUWXLfcUiw32nVM2HhcxTYmjtoLdveiLUBEIidokFyCrXHZPU45BKIs1jVVGx4Q3qQrboAx7nA=="], + "oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.4", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-LSh5o4oC7ItuIoqd7s1UCAVZ5I7JftEBgeLoatUeto/8by1O6MYvm12ljjP8HIXLsnfi3nJfipqLyXAiiHDHPQ=="], - "oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.2", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-BJhPlaQlAVDfGeCPY1fLe0UNVVSdYFq53ZYb61WVvhSgHnvakJGS6wSG+Al69RvAJx5qZ4i76Aw7CZWnLvDVLw=="], + "oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.4", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-caGra13pBdRoV/jCdRWZNeu8XUHUgIxBVn9guAJfT9bZ7AoBurqwO0wgJHUFghOydTdFxPBOGbSOYzJY3Hco5Q=="], - "oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-AYE6gCM9uMbzf83Sja0qBpxvN4JZzOHpY0MbZGEN/zfzgAVF+9Xh0bx2zKDVWA6GHhgtTJKO7xIUal8f9mUgtQ=="], + "oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.4", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-P9BAlcybNmJn7ZEq4pKI/qeeP6eUJd0/M/unP+FCjKJE/UwY0YJTYS/Jf9PPZbLCgwbJErPglZe2Ku6t/NXAxQ=="], - "oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-l4mRpCbx6ccFY1am6hD9qsrJxbwPVelHOplEdSdfvgPWiOIlDXoV5dsiGSOn5TbpjA7a3KNKXmctBK9utmkJwA=="], + "oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.4", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-F7HNYc/DygFsrraMbvXSQjb16NnC9EgtBsbWgHNkRm6UbxVHkWGIuVdHFEUJ1CqHPm2C/9xIuKJ5jiZrtEXqaA=="], - "oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-0mqEN73FFAsk+CmvHR/FiOV0AavaNp7CI5c5W/57remxxY4bEfhs2Q+idhv6hbmraEvM/vxoTYMBhExogpo75A=="], + "oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-WgDiowJBI7nXxqFZDo3FbR0lRkxURrFbBjDVfpqj7jxRQfUrVtwedNjkgxCF8eBOQwoBrijTmxG40GiF4z219g=="], - "oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-hNYG8laRQAS6akx3zKY8YXZ0kObseXjlU5gKe/7z0uAtSMgQhvyXn/uA68gwuU5eXNCDICwTJgxJOcI1vnYIFA=="], + "oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-BVJR1qiFe1WykrTBGYmd9XT387yR6VY8jupS/Pu0pqamRYBjeSlER4HQjOcrMY1XHJ/ygsspOcaWKJbSQ8Wcvw=="], - "oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-3tPJ9INHwhAI24Guqi3p7LKbY+zKalQ7vPj5AhTWrWCCt7Lcr7zsTg0Atz2nMVl0UJ8xbBa2jNjn/dmFg1cDng=="], + "oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-qbLyLSc6bMAys6AwQnD4a3PR9KJNSDaMvA9DA9ARz9+yZ1tb7aA2JdEA24xAoxwct7k2EzxnQI+gssJJM4VUoQ=="], - "oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-0TvudUyQvAcw6PM4wcZX7NY+xcyOIObJ9+kxYUU8e/saWYKVvkISBowzKDBjFuptbX4gVOvz6JVEfPaiCJxYNA=="], + "oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-ETqpbPN4HHc0wKfNSeAI2f0NE4nzUq+x85APomPRitVfTPxjdZbQd0TSc0O85vjT+kWj6cXjnHtviHB2BtxHog=="], - "oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.2", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-LKr8v+o9KByFUhIvzc6MGLr7/k9hZjHfYnFfcdbiAPCwsIvr8j2RLcl0LhUg1OQD6/U5JikjVYPYGqKanD44QA=="], + "oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.4", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-RC34rbTJGtJeOvp2WTY4ZgVmtkjrduVmXCVMcIdgvQ53yNmNqx79nDITm9FVBA8Id02AHJbYmXGxKvr+XpHbNA=="], - "oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.2", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-zVHptYD3Jzpah2301NAW7eNQ3WgW43cz4mGNrmj0jDpFQVeLy+UwXoGgFuYdZS8kuG9ARYtRA8e5M+0iAWnmbQ=="], + "oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.4", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-pi43bhDpt6l1fnxkqYYkWCsec1RNxsWL7FZDXoLOGJq/0y3bobWiTNDhbEWNr+uJvOrMs/Sv3qpF1TmYeTvdiA=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], diff --git a/package.json b/package.json index c6f4029a6..7846f3b9e 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "./schema.json": "./dist/oh-my-opencode.schema.json" }, "scripts": { - "build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema", + "build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi --external zod && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema", "build:all": "bun run build && bun run build:binaries", "build:binaries": "bun run script/build-binaries.ts", "build:schema": "bun run script/build-schema.ts", @@ -69,14 +69,14 @@ "picocolors": "^1.1.1", "picomatch": "^4.0.2", "posthog-node": "^5.29.2", - "vscode-jsonrpc": "^8.2.0", - "zod": "^4.3.0" + "vscode-jsonrpc": "^8.2.0" }, "devDependencies": { "@types/js-yaml": "^4.0.9", "@types/picomatch": "^3.0.2", "bun-types": "1.3.11", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "zod": "^4.3.0" }, "optionalDependencies": { "oh-my-opencode-darwin-arm64": "3.17.4", @@ -96,5 +96,8 @@ "@ast-grep/cli", "@ast-grep/napi", "@code-yeongyu/comment-checker" - ] + ], + "peerDependencies": { + "zod": "^4.0.0" + } } From 91ebffa9da32dd97340f4ef76e330fc63983c552 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 12:12:26 +0900 Subject: [PATCH 017/146] fix(test): update atlas test to expect task_id parameter instead of session_id verification-reminders.ts was updated to use task(task_id=...) but the 'should ignore extracted session ids' test still expected the old task(session_id=...) format, causing a consistent CI failure on dev. Fixes the pre-existing test failure unrelated to any code changes. --- src/hooks/atlas/index.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/atlas/index.test.ts b/src/hooks/atlas/index.test.ts index 0f9e7d605..20fb02fc1 100644 --- a/src/hooks/atlas/index.test.ts +++ b/src/hooks/atlas/index.test.ts @@ -957,7 +957,8 @@ session_id: ses_untrusted_999 const updatedState = readBoulderState(TEST_DIR) expect(updatedState?.task_sessions?.["todo:1"]).toBeUndefined() expect(output.output).not.toContain('task(session_id="ses_untrusted_999"') - expect(output.output).toContain('task(session_id=""') + expect(output.output).not.toContain('task(task_id="ses_untrusted_999"') + expect(output.output).toContain('task(task_id=""') cleanupMessageStorage(sessionID) }) From fec50c5d850bee956dc4a47d8ff6f89905516eca Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 12:42:21 +0900 Subject: [PATCH 018/146] fix: add oh-my-openagent bin alias for renamed package After the package was renamed from oh-my-opencode to oh-my-openagent, the bin entry only had 'oh-my-opencode'. Users running: npm install -g oh-my-openagent could not invoke 'oh-my-openagent' from the command line. Add 'oh-my-openagent' as a second bin entry pointing to the same bin/oh-my-opencode.js entry point. Both aliases now work. Fixes #3482 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c6f4029a6..f7e396d2f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "types": "dist/index.d.ts", "type": "module", "bin": { - "oh-my-opencode": "bin/oh-my-opencode.js" + "oh-my-opencode": "bin/oh-my-opencode.js", + "oh-my-openagent": "bin/oh-my-opencode.js" }, "files": [ "dist", From 28a896d09370b7550c4bb8ac537d3fe9bff9ba0c Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 12:16:27 +0900 Subject: [PATCH 019/146] fix(test): update dynamic-agent-prompt-builder test to expect task_id Same session_id->task_id migration as the atlas hook test. --- src/agents/dynamic-agent-prompt-builder.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agents/dynamic-agent-prompt-builder.test.ts b/src/agents/dynamic-agent-prompt-builder.test.ts index 7fab72a75..5bf5bcb4b 100644 --- a/src/agents/dynamic-agent-prompt-builder.test.ts +++ b/src/agents/dynamic-agent-prompt-builder.test.ts @@ -244,7 +244,7 @@ describe("buildNonClaudePlannerSection", () => { //#then expect(result).toContain("Plan Agent") - expect(result).toContain("session_id") + expect(result).toContain("task_id") expect(result).toContain("Multi-step") }) From 3a956b2103ce644da9556a186abda8956d03464a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 12:18:22 +0900 Subject: [PATCH 020/146] =?UTF-8?q?fix(test):=20align=20session=5Fid?= =?UTF-8?q?=E2=86=92task=5Fid=20across=20tests=20and=20source=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several places still emitted task(session_id=...) after the refactor: - src/hooks/atlas/verification-reminders.ts: 2 occurrences - src/agents/dynamic-agent-core-sections.ts: buildNonClaudePlannerSection prompt Tests updated to match: atlas index.test.ts and dynamic-agent-prompt-builder.test.ts --- src/agents/dynamic-agent-core-sections.ts | 2 +- src/hooks/atlas/verification-reminders.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/agents/dynamic-agent-core-sections.ts b/src/agents/dynamic-agent-core-sections.ts index dc91fd480..416750a54 100644 --- a/src/agents/dynamic-agent-core-sections.ts +++ b/src/agents/dynamic-agent-core-sections.ts @@ -182,7 +182,7 @@ Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementatio - Single-file fix or trivial change → proceed directly - Anything else (2+ steps, unclear scope, architecture) → \`task(subagent_type="plan", ...)\` FIRST -- Use \`session_id\` to resume the same Plan Agent - ask follow-up questions aggressively +- Use \`task_id\` to resume the same Plan Agent - ask follow-up questions aggressively - If ANY part of the task is ambiguous, ask Plan Agent before guessing Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it.` diff --git a/src/hooks/atlas/verification-reminders.ts b/src/hooks/atlas/verification-reminders.ts index b00618ecd..9bde55b9d 100644 --- a/src/hooks/atlas/verification-reminders.ts +++ b/src/hooks/atlas/verification-reminders.ts @@ -29,7 +29,7 @@ Your completion will NOT be recorded until you complete ALL of the following: If anything fails while closing this out, resume the same session immediately: \`\`\`typescript -task(session_id="${sessionId}", load_skills=[], prompt="fix: checkbox not recorded correctly") +task(task_id="${sessionId}", load_skills=[], prompt="fix: checkbox not recorded correctly") \`\`\` **Your completion is NOT tracked until the checkbox is marked in the plan file.** @@ -47,7 +47,7 @@ ${VERIFICATION_REMINDER} **If ANY verification fails, use this immediately:** \`\`\` -task(session_id="${sessionId}", load_skills=[], prompt="fix: [describe the specific failure]") +task(task_id="${sessionId}", load_skills=[], prompt="fix: [describe the specific failure]") \`\`\` ${buildReuseHint(sessionId)}` From 2fca3dced8aa495ca069b437ab2451fcc592754a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 12:47:49 +0900 Subject: [PATCH 021/146] =?UTF-8?q?fix(test):=20complete=20session=5Fid?= =?UTF-8?q?=E2=86=92task=5Fid=20migration=20in=20test=20assertions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous PR #3481 only added a not.toContain check but left the final toContain assertion still expecting task(session_id=...). Also updates dynamic-agent-core-sections.ts and verification-reminders.ts which still had session_id format after the refactor. --- src/hooks/atlas/index.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/atlas/index.test.ts b/src/hooks/atlas/index.test.ts index 0f9e7d605..20fb02fc1 100644 --- a/src/hooks/atlas/index.test.ts +++ b/src/hooks/atlas/index.test.ts @@ -957,7 +957,8 @@ session_id: ses_untrusted_999 const updatedState = readBoulderState(TEST_DIR) expect(updatedState?.task_sessions?.["todo:1"]).toBeUndefined() expect(output.output).not.toContain('task(session_id="ses_untrusted_999"') - expect(output.output).toContain('task(session_id=""') + expect(output.output).not.toContain('task(task_id="ses_untrusted_999"') + expect(output.output).toContain('task(task_id=""') cleanupMessageStorage(sessionID) }) From def44338ff57d68e07520a6be11b694b99b48197 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 14:51:52 +0900 Subject: [PATCH 022/146] refactor(models): bump claude-opus-4-6 to claude-opus-4-7 across fallback chains, categories, and hooks Updates the canonical Anthropic Opus model in every fallback chain (sisyphus, oracle, prometheus, metis, momus, visual-engineering, ultrabrain, deep, artistry, unspecified-high), the unspecified-high category default, the think-mode HIGH_VARIANT_MAP, the Claude Code alias map, the claude-thinking legacy alias, the context-limit GA regex, and event.ts fallback strings. Widens supportsCachedAnthropicLimit to accept both claude-*-4-6 and claude-*-4-7 so the 1M context cache still applies across the bump. Regenerates the bundled model-capabilities snapshot from models.dev and the model-fallback snapshot to match the new source output. --- src/agents/agent-identity.test.ts | 8 +- .../builtin-agents/sisyphus-agent.test.ts | 8 +- ...stom-agent-orchestrator-visibility.test.ts | 4 +- .../dynamic-agent-prompt-builder.test.ts | 2 +- src/agents/hephaestus/agent.test.ts | 16 +- src/agents/types.test.ts | 14 +- src/agents/utils.test.ts | 46 +- .../__snapshots__/model-fallback.test.ts.snap | 424 +- src/cli/cli-program.ts | 2 +- .../generate-omo-config.test.ts | 10 +- .../checks/model-resolution-cache.test.ts | 2 +- .../doctor/checks/model-resolution.test.ts | 12 +- src/cli/model-fallback.test.ts | 6 +- src/cli/provider-model-id-transform.test.ts | 46 +- src/cli/provider-model-id-transform.ts | 2 +- src/cli/refresh-model-capabilities.test.ts | 2 +- src/cli/run/message-part-delta.test.ts | 22 +- src/cli/tui-install-prompts.ts | 2 +- .../compaction-aware-message-resolver.test.ts | 12 +- .../background-agent/concurrency.test.ts | 2 +- src/features/background-agent/manager.test.ts | 56 +- .../background-agent/task-poller.test.ts | 4 +- .../claude-model-mapper.test.ts | 8 +- .../claude-model-mapper.ts | 2 +- .../opencode-config-agents-reader.test.ts | 2 +- .../task-toast-manager/manager.test.ts | 4 +- .../model-capabilities.generated.json | 76226 ++++++++-------- .../executor.test.ts | 8 +- src/hooks/anthropic-effort/index.test.ts | 14 +- .../atlas/compaction-agent-filter.test.ts | 2 +- ...inal-wave-approval-gate-regression.test.ts | 2 +- .../atlas/final-wave-approval-gate.test.ts | 2 +- src/hooks/atlas/index.test.ts | 2 +- src/hooks/model-fallback/hook.test.ts | 38 +- src/hooks/no-hephaestus-non-gpt/index.test.ts | 10 +- src/hooks/no-sisyphus-gpt/index.test.ts | 2 +- src/hooks/runtime-fallback/dispose.test.ts | 4 +- .../runtime-fallback/error-classifier.test.ts | 10 +- .../runtime-fallback/fallback-models.test.ts | 10 +- .../hook-dispose-cleanup.test.ts | 6 +- src/hooks/runtime-fallback/index.test.ts | 146 +- .../runtime-fallback/provider-matrix.test.ts | 2 +- .../session-status-handler.test.ts | 4 +- src/hooks/think-mode/index.test.ts | 2 +- src/hooks/think-mode/switcher.test.ts | 32 +- src/hooks/think-mode/switcher.ts | 2 +- ...x.compaction-model-agnostic.static.test.ts | 2 +- ...agent-config-handler-agents-skills.test.ts | 4 +- .../agent-config-handler.test.ts | 2 +- src/plugin-handlers/config-handler.test.ts | 96 +- .../plan-model-inheritance.test.ts | 12 +- .../prometheus-agent-config-builder.test.ts | 16 +- src/plugin/chat-message.test.ts | 6 +- src/plugin/chat-params.test.ts | 2 +- src/plugin/event-compaction-agent.test.ts | 2 +- src/plugin/event.model-fallback.test.ts | 42 +- src/plugin/event.test.ts | 6 +- src/plugin/event.ts | 6 +- .../fallback.cliproxyapi-matrix.test.ts | 4 +- .../ultrawork-db-model-override.test.ts | 16 +- src/plugin/ultrawork-model-override.test.ts | 58 +- .../ultrawork-variant-availability.test.ts | 14 +- src/shared/agent-config-integration.test.ts | 30 +- src/shared/agent-variant.test.ts | 10 +- src/shared/connected-providers-cache.test.ts | 4 +- src/shared/context-limit-resolver.test.ts | 12 +- src/shared/context-limit-resolver.ts | 2 +- src/shared/merge-categories.test.ts | 4 +- src/shared/model-availability.test.ts | 86 +- src/shared/model-availability.ts | 2 +- src/shared/model-capabilities.test.ts | 18 +- src/shared/model-capability-aliases.test.ts | 18 +- src/shared/model-capability-aliases.ts | 4 +- .../model-capability-guardrails.test.ts | 2 +- src/shared/model-error-classifier.test.ts | 2 +- src/shared/model-format-normalizer.test.ts | 4 +- src/shared/model-requirements.test.ts | 32 +- src/shared/model-requirements.ts | 20 +- src/shared/model-resolver.test.ts | 128 +- .../model-settings-compatibility.test.ts | 8 +- src/shared/provider-model-id-transform.ts | 6 +- .../delegate-task/anthropic-categories.ts | 2 +- .../delegate-task/category-resolver.test.ts | 2 +- src/tools/delegate-task/sync-task.test.ts | 12 +- src/tools/delegate-task/tools.test.ts | 82 +- 85 files changed, 39904 insertions(+), 38116 deletions(-) diff --git a/src/agents/agent-identity.test.ts b/src/agents/agent-identity.test.ts index 1247cda17..2c6a568a8 100644 --- a/src/agents/agent-identity.test.ts +++ b/src/agents/agent-identity.test.ts @@ -57,7 +57,7 @@ describe("Sisyphus prompt identity", () => { describe("#given a Sisyphus agent created with default model", () => { describe("#when checking the prompt", () => { it("#then contains the agent identity section with override directive", () => { - const config = createSisyphusAgent("anthropic/claude-opus-4-6") + const config = createSisyphusAgent("anthropic/claude-opus-4-7") expect(config.prompt).toContain("") expect(config.prompt).toContain("Sisyphus") @@ -65,7 +65,7 @@ describe("Sisyphus prompt identity", () => { }) it("#then identity section appears before the Role section", () => { - const config = createSisyphusAgent("anthropic/claude-opus-4-6") + const config = createSisyphusAgent("anthropic/claude-opus-4-7") const prompt = config.prompt ?? "" const identityIndex = prompt.indexOf("") const roleIndex = prompt.indexOf("") @@ -115,7 +115,7 @@ describe("Agent identity preservation through overrides", () => { describe("#given a Sisyphus agent with prompt_append override", () => { describe("#when merging the override", () => { it("#then identity section is preserved in the merged prompt", () => { - const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-6") + const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-7") const merged = mergeAgentConfig(baseConfig, { prompt_append: "Extra instructions here" }) expect(merged.prompt).toContain("") @@ -129,7 +129,7 @@ describe("Agent identity preservation through overrides", () => { describe("#given a Sisyphus agent with model override only", () => { describe("#when merging the override", () => { it("#then identity section is preserved unchanged", () => { - const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-6") + const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-7") const merged = mergeAgentConfig(baseConfig, { model: "openai/gpt-5.4" }) expect(merged.prompt).toContain("") diff --git a/src/agents/builtin-agents/sisyphus-agent.test.ts b/src/agents/builtin-agents/sisyphus-agent.test.ts index e55fea125..e7289f6c0 100644 --- a/src/agents/builtin-agents/sisyphus-agent.test.ts +++ b/src/agents/builtin-agents/sisyphus-agent.test.ts @@ -43,7 +43,7 @@ describe("maybeCreateSisyphusConfig", () => { // given const agentOverrides: AgentOverrides = { sisyphus: { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", permission: { apply_patch: "allow", }, @@ -55,8 +55,8 @@ describe("maybeCreateSisyphusConfig", () => { const config = maybeCreateSisyphusConfig({ disabledAgents: [], agentOverrides, - availableModels: new Set(["anthropic/claude-opus-4-6"]), - systemDefaultModel: "anthropic/claude-opus-4-6", + availableModels: new Set(["anthropic/claude-opus-4-7"]), + systemDefaultModel: "anthropic/claude-opus-4-7", isFirstRunNoCache: false, availableAgents: [], availableSkills: [], @@ -67,7 +67,7 @@ describe("maybeCreateSisyphusConfig", () => { // then expect(config).toBeDefined(); - expect(config?.model).toBe("anthropic/claude-opus-4-6"); + expect(config?.model).toBe("anthropic/claude-opus-4-7"); // Claude models should allow the user override expect(config?.permission).toHaveProperty("apply_patch", "allow"); }); diff --git a/src/agents/custom-agent-orchestrator-visibility.test.ts b/src/agents/custom-agent-orchestrator-visibility.test.ts index c0b709e4b..b526d3f9f 100644 --- a/src/agents/custom-agent-orchestrator-visibility.test.ts +++ b/src/agents/custom-agent-orchestrator-visibility.test.ts @@ -2,13 +2,13 @@ import { describe, expect, spyOn, test } from "bun:test" import { createBuiltinAgents } from "./builtin-agents" import * as shared from "../shared" -const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-6" +const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-7" describe("createBuiltinAgents custom agent visibility", () => { test("#given runtime custom agents #when orchestrator prompts are built #then custom agents are not advertised for automatic delegation", async () => { //#given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) try { diff --git a/src/agents/dynamic-agent-prompt-builder.test.ts b/src/agents/dynamic-agent-prompt-builder.test.ts index 5bf5bcb4b..7e4b57305 100644 --- a/src/agents/dynamic-agent-prompt-builder.test.ts +++ b/src/agents/dynamic-agent-prompt-builder.test.ts @@ -211,7 +211,7 @@ describe("buildParallelDelegationSection", () => { it("#given Claude model #when building #then returns empty", () => { //#given - const model = "anthropic/claude-opus-4-6" + const model = "anthropic/claude-opus-4-7" const categories = [deepCategory] //#when diff --git a/src/agents/hephaestus/agent.test.ts b/src/agents/hephaestus/agent.test.ts index 7818e0361..5721f006a 100644 --- a/src/agents/hephaestus/agent.test.ts +++ b/src/agents/hephaestus/agent.test.ts @@ -56,7 +56,7 @@ describe("getHephaestusPromptSource", () => { test("returns 'gpt' for non-GPT models and undefined", () => { // given - const model1 = "anthropic/claude-opus-4-6"; + const model1 = "anthropic/claude-opus-4-7"; const model2 = undefined; // when @@ -124,7 +124,7 @@ describe("getHephaestusPrompt", () => { test("Claude model returns generic GPT prompt (Hephaestus default)", () => { // given - const model = "anthropic/claude-opus-4-6"; + const model = "anthropic/claude-opus-4-7"; // when const prompt = getHephaestusPrompt(model); @@ -149,7 +149,7 @@ describe("getHephaestusPrompt", () => { test("useTaskSystem=false includes Todo Discipline for Claude models", () => { // given - const model = "anthropic/claude-opus-4-6"; + const model = "anthropic/claude-opus-4-7"; // when const prompt = getHephaestusPrompt(model, false); @@ -239,7 +239,7 @@ describe("createHephaestusAgent", () => { // given const gpt54Model = "openai/gpt-5.4"; const gptGenericModel = "openai/gpt-4o"; - const claudeModel = "anthropic/claude-opus-4-6"; + const claudeModel = "anthropic/claude-opus-4-7"; // when const gpt54Config = createHephaestusAgent(gpt54Model); @@ -322,7 +322,7 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => { // given const agentOverrides: AgentOverrides = { hephaestus: { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", permission: { apply_patch: "allow", }, @@ -334,8 +334,8 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => { const config = maybeCreateHephaestusConfig({ disabledAgents: [], agentOverrides, - availableModels: new Set(["anthropic/claude-opus-4-6"]), - systemDefaultModel: "anthropic/claude-opus-4-6", + availableModels: new Set(["anthropic/claude-opus-4-7"]), + systemDefaultModel: "anthropic/claude-opus-4-7", isFirstRunNoCache: false, availableAgents: [], availableSkills: [], @@ -346,7 +346,7 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => { // then expect(config).toBeDefined(); - expect(config?.model).toBe("anthropic/claude-opus-4-6"); + expect(config?.model).toBe("anthropic/claude-opus-4-7"); expect(config?.permission).toHaveProperty("apply_patch", "allow"); }); }); diff --git a/src/agents/types.test.ts b/src/agents/types.test.ts index a214d304a..4c94e2868 100644 --- a/src/agents/types.test.ts +++ b/src/agents/types.test.ts @@ -18,7 +18,7 @@ describe("isGpt5_4Model", () => { }); test("does not match non-GPT models", () => { - expect(isGpt5_4Model("anthropic/claude-opus-4-6")).toBe(false); + expect(isGpt5_4Model("anthropic/claude-opus-4-7")).toBe(false); expect(isGpt5_4Model("google/gemini-3.1-pro")).toBe(false); expect(isGpt5_4Model("openai/o1")).toBe(false); }); @@ -64,7 +64,7 @@ describe("isGptModel", () => { }); test("claude models are not gpt", () => { - expect(isGptModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isGptModel("anthropic/claude-opus-4-7")).toBe(false); expect(isGptModel("anthropic/claude-sonnet-4-6")).toBe(false); expect(isGptModel("litellm/anthropic.claude-opus-4-5")).toBe(false); }); @@ -75,7 +75,7 @@ describe("isGptModel", () => { }); test("opencode provider is not gpt", () => { - expect(isGptModel("opencode/claude-opus-4-6")).toBe(false); + expect(isGptModel("opencode/claude-opus-4-7")).toBe(false); }); }); @@ -95,7 +95,7 @@ describe("isMiniMaxModel", () => { test("does not match non-minimax models", () => { expect(isMiniMaxModel("openai/gpt-5.4")).toBe(false); - expect(isMiniMaxModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isMiniMaxModel("anthropic/claude-opus-4-7")).toBe(false); expect(isMiniMaxModel("google/gemini-3.1-pro")).toBe(false); expect(isMiniMaxModel("opencode-go/kimi-k2.5")).toBe(false); }); @@ -116,7 +116,7 @@ describe("isGlmModel", () => { test("#given non-GLM models #then returns false", () => { expect(isGlmModel("openai/gpt-5.4")).toBe(false); - expect(isGlmModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isGlmModel("anthropic/claude-opus-4-7")).toBe(false); expect(isGlmModel("google/gemini-3.1-pro")).toBe(false); }); }); @@ -156,11 +156,11 @@ describe("isGeminiModel", () => { }); test("#given claude models #then returns false", () => { - expect(isGeminiModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isGeminiModel("anthropic/claude-opus-4-7")).toBe(false); expect(isGeminiModel("anthropic/claude-sonnet-4-6")).toBe(false); }); test("#given opencode provider #then returns false", () => { - expect(isGeminiModel("opencode/claude-opus-4-6")).toBe(false); + expect(isGeminiModel("opencode/claude-opus-4-7")).toBe(false); }); }); diff --git a/src/agents/utils.test.ts b/src/agents/utils.test.ts index b63a34827..bd8bb5740 100644 --- a/src/agents/utils.test.ts +++ b/src/agents/utils.test.ts @@ -7,7 +7,7 @@ import * as connectedProvidersCache from "../shared/connected-providers-cache" import * as modelAvailability from "../shared/model-availability" import * as shared from "../shared" -const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-6" +const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-7" let createBuiltinAgents: (typeof import("./builtin-agents"))["createBuiltinAgents"] async function importFreshBuiltinAgentsModule(): Promise { @@ -32,7 +32,7 @@ describe("createBuiltinAgents with model overrides", () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "kimi-for-coding/k2p5", "opencode/kimi-k2.5-free", "zai-coding-plan/glm-5", @@ -45,7 +45,7 @@ describe("createBuiltinAgents with model overrides", () => { const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL, undefined, undefined, [], {}) // #then - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7") expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 }) expect(agents.sisyphus.reasoningEffort).toBeUndefined() } finally { @@ -170,7 +170,7 @@ describe("createBuiltinAgents with model overrides", () => { test("Sisyphus is created on first run when no availableModels or cache exist", async () => { // #given - const systemDefaultModel = "anthropic/claude-opus-4-6" + const systemDefaultModel = "anthropic/claude-opus-4-7" const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set()) @@ -180,7 +180,7 @@ describe("createBuiltinAgents with model overrides", () => { // #then expect(agents.sisyphus).toBeDefined() - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.7") } finally { cacheSpy.mockRestore() fetchSpy.mockRestore() @@ -299,7 +299,7 @@ describe("createBuiltinAgents with model overrides", () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "kimi-for-coding/k2p5", "opencode/kimi-k2.5-free", "zai-coding-plan/glm-5", @@ -341,7 +341,7 @@ describe("createBuiltinAgents with model overrides", () => { test("excludes hidden custom agents from orchestrator prompts", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -377,7 +377,7 @@ describe("createBuiltinAgents with model overrides", () => { test("excludes disabled custom agents from orchestrator prompts", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -413,7 +413,7 @@ describe("createBuiltinAgents with model overrides", () => { test("excludes custom agents when disabledAgents contains their name (case-insensitive)", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const disabledAgents = ["ReSeArChEr"] @@ -449,7 +449,7 @@ describe("createBuiltinAgents with model overrides", () => { test("does not advertise duplicate custom agents case-insensitively", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -481,7 +481,7 @@ describe("createBuiltinAgents with model overrides", () => { test("does not surface custom agent strings in orchestrator prompts", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -555,7 +555,7 @@ describe("createBuiltinAgents without systemDefaultModel", () => { ]) const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "kimi-for-coding/k2p5", "opencode/kimi-k2.5-free", "zai-coding-plan/glm-5", @@ -569,7 +569,7 @@ describe("createBuiltinAgents without systemDefaultModel", () => { // #then expect(agents.sisyphus).toBeDefined() - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7") } finally { cacheSpy.mockRestore() fetchSpy.mockRestore() @@ -590,7 +590,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () => const providers = options?.connectedProviders ?? [] return providers.includes("openai") ? new Set(["openai/gpt-5.3-codex"]) - : new Set(["anthropic/claude-opus-4-6"]) + : new Set(["anthropic/claude-opus-4-7"]) }) try { @@ -609,7 +609,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () => test("hephaestus is not created when no required provider is connected", async () => { // #given - only anthropic models available, not in hephaestus requiresProvider const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6"]) + new Set(["anthropic/claude-opus-4-7"]) ) const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"]) @@ -699,10 +699,10 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () => test("hephaestus is created when explicit config provided even if provider unavailable", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6"]) + new Set(["anthropic/claude-opus-4-7"]) ) const overrides = { - hephaestus: { model: "anthropic/claude-opus-4-6" }, + hephaestus: { model: "anthropic/claude-opus-4-7" }, } try { @@ -781,7 +781,7 @@ describe("Sisyphus and Librarian environment context toggle", () => { beforeEach(() => { fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "google/gemini-3-flash"]) + new Set(["anthropic/claude-opus-4-7", "google/gemini-3-flash"]) ) }) @@ -840,7 +840,7 @@ describe("Atlas is unaffected by environment context toggle", () => { beforeEach(() => { fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) }) @@ -893,7 +893,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { test("sisyphus is created when at least one fallback model is available", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6"]) + new Set(["anthropic/claude-opus-4-7"]) ) try { @@ -918,7 +918,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { // #then expect(agents.sisyphus).toBeDefined() - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.7") } finally { cacheSpy.mockRestore() fetchSpy.mockRestore() @@ -929,7 +929,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set()) const overrides = { - sisyphus: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, } try { @@ -1039,7 +1039,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { describe("buildAgent with category and skills", () => { const { buildAgent } = require("./agent-builder") - const TEST_MODEL = "anthropic/claude-opus-4-6" + const TEST_MODEL = "anthropic/claude-opus-4-7" beforeEach(() => { clearSkillCache() diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index 92769a5b8..dc2bac7a6 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -75,26 +75,26 @@ exports[`generateModelConfig single native provider uses Claude models when only "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { "model": "opencode/gpt-5-nano", }, "oracle": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -103,14 +103,14 @@ exports[`generateModelConfig single native provider uses Claude models when only }, "categories": { "deep": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-high": { @@ -120,7 +120,7 @@ exports[`generateModelConfig single native provider uses Claude models when only "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "writing": { @@ -141,26 +141,26 @@ exports[`generateModelConfig single native provider uses Claude models with isMa "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { "model": "opencode/gpt-5-nano", }, "oracle": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -169,25 +169,25 @@ exports[`generateModelConfig single native provider uses Claude models with isMa }, "categories": { "deep": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-high": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "writing": { @@ -532,13 +532,13 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -565,7 +565,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -582,7 +582,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -592,7 +592,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "medium", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -609,7 +609,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -622,7 +622,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -651,7 +651,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -685,7 +685,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -731,13 +731,13 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -764,7 +764,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -781,7 +781,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -791,7 +791,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "medium", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -808,7 +808,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -821,7 +821,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -850,7 +850,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -864,7 +864,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-low": { @@ -882,7 +882,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -936,13 +936,13 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "variant": "high", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -969,7 +969,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -986,7 +986,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "model": "opencode/gemini-3.1-pro", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -1005,7 +1005,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "model": "opencode/big-pickle", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -1025,7 +1025,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "artistry": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1038,7 +1038,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "deep": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1070,7 +1070,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1107,7 +1107,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "model": "opencode/glm-5", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1161,13 +1161,13 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "variant": "high", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1194,7 +1194,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1211,7 +1211,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/gemini-3.1-pro", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -1230,7 +1230,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/big-pickle", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -1250,7 +1250,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "artistry": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1263,7 +1263,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "deep": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1295,7 +1295,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1315,7 +1315,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/kimi-k2.5", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "unspecified-low": { @@ -1336,7 +1336,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/glm-5", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1387,13 +1387,13 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1414,7 +1414,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1431,7 +1431,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "model": "github-copilot/gemini-3.1-pro-preview", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -1441,7 +1441,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "variant": "medium", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -1458,7 +1458,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "artistry": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1471,7 +1471,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "deep": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1496,7 +1496,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "ultrabrain": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1522,7 +1522,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1573,13 +1573,13 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1600,7 +1600,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1617,7 +1617,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "model": "github-copilot/gemini-3.1-pro-preview", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -1627,7 +1627,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "medium", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -1644,7 +1644,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "artistry": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1657,7 +1657,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "deep": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1682,7 +1682,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "ultrabrain": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1696,7 +1696,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "unspecified-low": { @@ -1710,7 +1710,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1888,7 +1888,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "metis": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1896,17 +1896,17 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1933,11 +1933,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1947,7 +1947,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "prometheus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1958,13 +1958,13 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1981,7 +1981,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -2004,11 +2004,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2021,11 +2021,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2060,11 +2060,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2107,11 +2107,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2179,7 +2179,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { @@ -2189,7 +2189,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "xhigh", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -2223,7 +2223,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -2244,7 +2244,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "model": "github-copilot/gemini-3.1-pro-preview", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -2258,7 +2258,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "medium", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -2279,7 +2279,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "artistry": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -2299,7 +2299,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "medium", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -2331,7 +2331,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -2365,7 +2365,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -2403,22 +2403,22 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "model": "zai-coding-plan/glm-4.7", }, "metis": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { "model": "zai-coding-plan/glm-4.6v", }, "oracle": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -2427,7 +2427,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "model": "zai-coding-plan/glm-5", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -2436,14 +2436,14 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat }, "categories": { "deep": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-high": { @@ -2455,7 +2455,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2479,7 +2479,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { @@ -2489,7 +2489,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { @@ -2498,7 +2498,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "oracle": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2511,11 +2511,11 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -2526,7 +2526,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2540,7 +2540,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { @@ -2554,7 +2554,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "ultrabrain": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2580,7 +2580,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2660,7 +2660,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "metis": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2672,7 +2672,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { @@ -2682,11 +2682,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "xhigh", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2731,11 +2731,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2745,7 +2745,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "prometheus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2763,13 +2763,13 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/gemini-3.1-pro", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2793,7 +2793,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/big-pickle", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -2824,11 +2824,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2848,11 +2848,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "medium", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2901,11 +2901,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2961,11 +2961,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/glm-5", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3068,11 +3068,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "metis": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3088,7 +3088,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { @@ -3102,15 +3102,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "xhigh", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3174,15 +3174,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3192,11 +3192,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "prometheus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3221,17 +3221,17 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3259,7 +3259,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -3301,15 +3301,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3336,15 +3336,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "medium", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3414,15 +3414,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3502,15 +3502,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3619,11 +3619,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "metis": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3639,7 +3639,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { @@ -3653,15 +3653,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "xhigh", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3725,15 +3725,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3743,11 +3743,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "prometheus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3772,17 +3772,17 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3810,7 +3810,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -3852,15 +3852,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3887,15 +3887,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "medium", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3965,15 +3965,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3983,11 +3983,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "unspecified-high": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -4012,7 +4012,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/kimi-k2.5", }, ], - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-low": { @@ -4060,15 +4060,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -4163,13 +4163,13 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4205,7 +4205,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4228,7 +4228,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/google/gemini-3.1-pro-preview", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -4244,7 +4244,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -4267,7 +4267,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "artistry": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4280,7 +4280,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "deep": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4315,7 +4315,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4367,7 +4367,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, ], @@ -4456,13 +4456,13 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4498,7 +4498,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4521,7 +4521,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/google/gemini-3.1-pro-preview", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -4537,7 +4537,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -4560,7 +4560,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "artistry": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4573,7 +4573,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "deep": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4608,7 +4608,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4631,7 +4631,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/moonshotai/kimi-k2.5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "unspecified-low": { @@ -4658,7 +4658,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, ], diff --git a/src/cli/cli-program.ts b/src/cli/cli-program.ts index 6d982e57b..4835495a5 100644 --- a/src/cli/cli-program.ts +++ b/src/cli/cli-program.ts @@ -46,7 +46,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi > Verce OpenAI Native openai/ models (GPT-5.4 for Oracle) Gemini Native google/ models (Gemini 3.1 Pro, Flash) Copilot github-copilot/ models (fallback) - OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.) + OpenCode Zen opencode/ models (opencode/claude-opus-4-7, etc.) Z.ai zai-coding-plan/glm-5 (visual-engineering fallback) Kimi kimi-for-coding/k2p5 (Sisyphus/Prometheus fallback) Vercel vercel/ models (universal proxy, always last fallback) diff --git a/src/cli/config-manager/generate-omo-config.test.ts b/src/cli/config-manager/generate-omo-config.test.ts index 2d13046ec..8b4a1dde1 100644 --- a/src/cli/config-manager/generate-omo-config.test.ts +++ b/src/cli/config-manager/generate-omo-config.test.ts @@ -26,8 +26,8 @@ describe("generateOmoConfig - model fallback system", () => { //#then expect([ - "github-copilot/claude-opus-4.6", - "github-copilot/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "github-copilot/claude-opus-4-7", ]).toContain((result.agents as Record).sisyphus.model) }) @@ -74,7 +74,7 @@ describe("generateOmoConfig - model fallback system", () => { //#then expect((result.agents as Record).librarian.model).toBe("zai-coding-plan/glm-4.7") - expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4-7") }) test("uses native OpenAI models when only ChatGPT available", () => { @@ -131,7 +131,7 @@ describe("generateOmoConfig - model fallback system", () => { }> //#then - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7") expect(agents.sisyphus.fallback_models).toEqual([ { model: "openai/gpt-5.4", @@ -141,7 +141,7 @@ describe("generateOmoConfig - model fallback system", () => { expect(categories.deep.model).toBe("openai/gpt-5.4") expect(categories.deep.fallback_models).toEqual([ { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", }, ]) diff --git a/src/cli/doctor/checks/model-resolution-cache.test.ts b/src/cli/doctor/checks/model-resolution-cache.test.ts index df6d68f16..58b0ce3d4 100644 --- a/src/cli/doctor/checks/model-resolution-cache.test.ts +++ b/src/cli/doctor/checks/model-resolution-cache.test.ts @@ -34,7 +34,7 @@ describe("loadAvailableModelsFromCache", () => { join(tempDir, "cache", "opencode", "models.json"), JSON.stringify({ openai: { models: { "gpt-5.4": {} } }, - anthropic: { models: { "claude-opus-4-6": {}, "claude-sonnet-4-6": {} } }, + anthropic: { models: { "claude-opus-4-7": {}, "claude-sonnet-4-6": {} } }, }) ) diff --git a/src/cli/doctor/checks/model-resolution.test.ts b/src/cli/doctor/checks/model-resolution.test.ts index b64b1fa10..2d1c09919 100644 --- a/src/cli/doctor/checks/model-resolution.test.ts +++ b/src/cli/doctor/checks/model-resolution.test.ts @@ -14,7 +14,7 @@ describe("model-resolution check", () => { // then: Should have agent entries const sisyphus = info.agents.find((a) => a.name === "sisyphus") expect(sisyphus).toBeDefined() - expect(sisyphus!.requirement.fallbackChain[0]?.model).toBe("claude-opus-4-6") + expect(sisyphus!.requirement.fallbackChain[0]?.model).toBe("claude-opus-4-7") expect(sisyphus!.requirement.fallbackChain[0]?.providers).toContain("anthropic") }) @@ -42,7 +42,7 @@ describe("model-resolution check", () => { // given: User has override for oracle agent const mockConfig = { agents: { - oracle: { model: "anthropic/claude-opus-4-6" }, + oracle: { model: "anthropic/claude-opus-4-7" }, }, } @@ -51,8 +51,8 @@ describe("model-resolution check", () => { // then: Oracle should show the override const oracle = info.agents.find((a) => a.name === "oracle") expect(oracle).toBeDefined() - expect(oracle!.userOverride).toBe("anthropic/claude-opus-4-6") - expect(oracle!.effectiveResolution).toBe("User override: anthropic/claude-opus-4-6") + expect(oracle!.userOverride).toBe("anthropic/claude-opus-4-7") + expect(oracle!.effectiveResolution).toBe("User override: anthropic/claude-opus-4-7") }) it("shows user override for category when configured", async () => { @@ -169,13 +169,13 @@ describe("model-resolution check", () => { const info = getModelResolutionInfoWithOverrides({ agents: { - oracle: { model: "anthropic/claude-opus-4-6-thinking" }, + oracle: { model: "anthropic/claude-opus-4-7-thinking" }, }, }) const oracle = info.agents.find((agent) => agent.name === "oracle") expect(oracle).toBeDefined() - expect(oracle!.effectiveModel).toBe("anthropic/claude-opus-4-6-thinking") + expect(oracle!.effectiveModel).toBe("anthropic/claude-opus-4-7-thinking") expect(oracle!.capabilityDiagnostics).toMatchObject({ resolutionMode: "alias-backed", canonicalization: { diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index 7e7816100..67fa83fd7 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -381,7 +381,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7") }) test("Sisyphus is created when multiple fallback providers are available", () => { @@ -398,7 +398,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7") }) test("Sisyphus resolves to gpt-5.4 medium when only OpenAI is available", () => { @@ -668,7 +668,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then should prefer native anthropic over gateway - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7") }) }) diff --git a/src/cli/provider-model-id-transform.test.ts b/src/cli/provider-model-id-transform.test.ts index fd2f32f07..0a1b57030 100644 --- a/src/cli/provider-model-id-transform.test.ts +++ b/src/cli/provider-model-id-transform.test.ts @@ -5,16 +5,16 @@ import { transformModelForProvider as transformSharedModelForProvider } from ".. describe("transformModelForProvider", () => { describe("github-copilot provider", () => { - test("transforms claude-opus-4-6 to claude-opus-4.6", () => { - // #given github-copilot provider and claude-opus-4-6 model + test("transforms claude-opus-4-7 to claude-opus-4.7", () => { + // #given github-copilot provider and claude-opus-4-7 model const provider = "github-copilot" - const model = "claude-opus-4-6" + const model = "claude-opus-4-7" // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-opus-4.6 - expect(result).toBe("claude-opus-4.6") + // #then should transform to claude-opus-4.7 + expect(result).toBe("claude-opus-4.7") }) test("transforms claude-sonnet-4-5 to claude-sonnet-4.5", () => { @@ -152,29 +152,29 @@ describe("transformModelForProvider", () => { }) test("does not transform claude models for google provider", () => { - // #given google provider and claude-opus-4-6 model + // #given google provider and claude-opus-4-7 model const provider = "google" - const model = "claude-opus-4-6" + const model = "claude-opus-4-7" // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) // #then should pass through unchanged (google doesn't use claude) - expect(result).toBe("claude-opus-4-6") + expect(result).toBe("claude-opus-4-7") }) }) describe("anthropic provider", () => { - test("preserves hyphenated claude-opus-4-6 for config output (regression: installer must not write dotted IDs)", () => { - // #given anthropic provider and claude-opus-4-6 model + test("preserves hyphenated claude-opus-4-7 for config output (regression: installer must not write dotted IDs)", () => { + // #given anthropic provider and claude-opus-4-7 model const provider = "anthropic" - const model = "claude-opus-4-6" + const model = "claude-opus-4-7" // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) // #then should keep hyphenated form so Anthropic provider resolution succeeds on fresh installs - expect(result).toBe("claude-opus-4-6") + expect(result).toBe("claude-opus-4-7") }) test("preserves hyphenated claude-sonnet-4-6 for config output", () => { @@ -204,12 +204,12 @@ describe("transformModelForProvider", () => { describe("vercel provider", () => { test("prepends anthropic/ and applies anthropic transform for claude models", () => { - // #given vercel provider and claude-opus-4-6 model + // #given vercel provider and claude-opus-4-7 model // #when transformModelForProvider is called - const result = transformModelForProvider("vercel", "claude-opus-4-6") + const result = transformModelForProvider("vercel", "claude-opus-4-7") - // #then should produce anthropic/claude-opus-4.6 - expect(result).toBe("anthropic/claude-opus-4.6") + // #then should produce anthropic/claude-opus-4.7 + expect(result).toBe("anthropic/claude-opus-4.7") }) test("prepends anthropic/ and applies anthropic transform for claude-sonnet", () => { @@ -267,12 +267,12 @@ describe("transformModelForProvider", () => { }) test("delegates to sub-provider when model already has sub-provider prefix", () => { - // #given vercel provider and anthropic/claude-opus-4-6 (already prefixed) + // #given vercel provider and anthropic/claude-opus-4-7 (already prefixed) // #when transformModelForProvider is called - const result = transformModelForProvider("vercel", "anthropic/claude-opus-4-6") + const result = transformModelForProvider("vercel", "anthropic/claude-opus-4-7") // #then should apply anthropic transform within the prefix - expect(result).toBe("anthropic/claude-opus-4.6") + expect(result).toBe("anthropic/claude-opus-4.7") }) test("prepends minimax/ for minimax models", () => { @@ -340,14 +340,14 @@ describe("transformModelForProvider", () => { test("uses a CLI-local transform implementation distinct from the shared runtime transform", () => { // #given the CLI transform (used by the installer) and the shared runtime transform - const cliResult = transformModelForProvider("anthropic", "claude-opus-4-6") - const sharedResult = transformSharedModelForProvider("anthropic", "claude-opus-4-6") + const cliResult = transformModelForProvider("anthropic", "claude-opus-4-7") + const sharedResult = transformSharedModelForProvider("anthropic", "claude-opus-4-7") // #when both are called with the same anthropic claude input // #then the CLI preserves hyphenated form for config output, // the shared runtime transform converts dash→dot for API calls expect(transformModelForProvider).not.toBe(transformSharedModelForProvider) - expect(cliResult).toBe("claude-opus-4-6") - expect(sharedResult).toBe("claude-opus-4.6") + expect(cliResult).toBe("claude-opus-4-7") + expect(sharedResult).toBe("claude-opus-4.7") }) }) diff --git a/src/cli/provider-model-id-transform.ts b/src/cli/provider-model-id-transform.ts index 0eab2d0e2..fda947c8c 100644 --- a/src/cli/provider-model-id-transform.ts +++ b/src/cli/provider-model-id-transform.ts @@ -54,7 +54,7 @@ export function transformModelForProvider(provider: string, model: string): stri } if (provider === "anthropic") { - // Installer writes hyphenated IDs (claude-opus-4-6) to the config. The + // Installer writes hyphenated IDs (claude-opus-4-7) to the config. The // runtime provider-model-id-transform converts dash→dot when calling the // Anthropic API. Keeping the dotted form in the config breaks fresh // installs with ProviderModelNotFoundError because Anthropic's provider diff --git a/src/cli/refresh-model-capabilities.test.ts b/src/cli/refresh-model-capabilities.test.ts index 800cf7e54..bfed41969 100644 --- a/src/cli/refresh-model-capabilities.test.ts +++ b/src/cli/refresh-model-capabilities.test.ts @@ -49,7 +49,7 @@ describe("refreshModelCapabilities", () => { sourceUrl: "https://override.example/api.json", models: { "gpt-5.4": { id: "gpt-5.4" }, - "claude-opus-4-6": { id: "claude-opus-4-6" }, + "claude-opus-4-7": { id: "claude-opus-4-7" }, }, })) let stdout = "" diff --git a/src/cli/run/message-part-delta.test.ts b/src/cli/run/message-part-delta.test.ts index 6d7fefa6e..09f0c2d84 100644 --- a/src/cli/run/message-part-delta.test.ts +++ b/src/cli/run/message-part-delta.test.ts @@ -98,7 +98,7 @@ describe("message.part.delta handling", () => { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", }, }, @@ -113,7 +113,7 @@ describe("message.part.delta handling", () => { //#then const rendered = stdoutSpy.mock.calls.map((call) => String(call[0] ?? "")).join("") expect(rendered).toContain("\u001b[38;2;0;206;209m") - expect(rendered).toContain("claude-opus-4-6 (max)") + expect(rendered).toContain("claude-opus-4-7 (max)") expect(rendered).toContain("└─") expect(rendered).toContain("Sisyphus - Ultraworker") stdoutSpy.mockRestore() @@ -128,7 +128,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -187,7 +187,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -242,7 +242,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -309,7 +309,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -353,7 +353,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6", variant: "max" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7", variant: "max" }, }, }, { @@ -388,7 +388,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -410,7 +410,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -619,7 +619,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-6" }, + info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-7" }, }, }, { @@ -634,7 +634,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-6" }, + info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-7" }, }, }, { diff --git a/src/cli/tui-install-prompts.ts b/src/cli/tui-install-prompts.ts index 3d5fb4584..9638dfd4d 100644 --- a/src/cli/tui-install-prompts.ts +++ b/src/cli/tui-install-prompts.ts @@ -74,7 +74,7 @@ export async function promptInstallConfig(detected: DetectedConfig): Promise { // given const message = { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } writeFileSync(join(tempDir, "001.json"), JSON.stringify(message)) @@ -94,18 +94,18 @@ describe("findNearestMessageExcludingCompaction", () => { expect(result).not.toBeNull() expect(result?.agent).toBe("sisyphus") expect(result?.model?.providerID).toBe("anthropic") - expect(result?.model?.modelID).toBe("claude-opus-4-6") + expect(result?.model?.modelID).toBe("claude-opus-4-7") }) test("skips compaction agent messages", () => { // given const compactionMessage = { agent: "compaction", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } const validMessage = { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } writeFileSync(join(tempDir, "002.json"), JSON.stringify(compactionMessage)) writeFileSync(join(tempDir, "001.json"), JSON.stringify(validMessage)) @@ -125,12 +125,12 @@ describe("findNearestMessageExcludingCompaction", () => { writeFileSync(join(tempDir, "002.json"), JSON.stringify({ id: compactionMessageID, agent: "atlas", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, })) writeFileSync(join(tempDir, "001.json"), JSON.stringify({ id: "msg_001", agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, })) mkdirSync(partDir, { recursive: true }) writeFileSync(join(partDir, "prt_0001.json"), JSON.stringify({ type: "compaction" })) diff --git a/src/features/background-agent/concurrency.test.ts b/src/features/background-agent/concurrency.test.ts index 682d6029a..45150f79b 100644 --- a/src/features/background-agent/concurrency.test.ts +++ b/src/features/background-agent/concurrency.test.ts @@ -94,7 +94,7 @@ describe("ConcurrencyManager.getConcurrencyLimit", () => { // when const modelLimit = manager.getConcurrencyLimit("anthropic/claude-sonnet-4-6") - const providerLimit = manager.getConcurrencyLimit("anthropic/claude-opus-4-6") + const providerLimit = manager.getConcurrencyLimit("anthropic/claude-opus-4-7") const defaultLimit = manager.getConcurrencyLimit("google/gemini-3.1-pro") // then diff --git a/src/features/background-agent/manager.test.ts b/src/features/background-agent/manager.test.ts index d76ab8aa2..8c855ebcf 100644 --- a/src/features/background-agent/manager.test.ts +++ b/src/features/background-agent/manager.test.ts @@ -855,7 +855,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => { info: { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, }, }, { @@ -890,7 +890,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => //#then expect(capturedBody?.agent).toBe("sisyphus") - expect(capturedBody?.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.6" }) + expect(capturedBody?.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.7" }) manager.shutdown() }) @@ -913,7 +913,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => } const currentMessage: CurrentMessage = { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } // when @@ -921,7 +921,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => // then - uses currentMessage values, not task.parentModel/parentAgent expect(promptBody.agent).toBe("sisyphus") - expect(promptBody.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.6" }) + expect(promptBody.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.7" }) }) test("should fallback to parentAgent when currentMessage.agent is undefined", async () => { @@ -1155,7 +1155,7 @@ describe("BackgroundManager.notifyParentSession - notifications toggle", () => { agent: "explore", model: { providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "high", }, }, @@ -1211,7 +1211,7 @@ describe("BackgroundManager.notifyParentSession - variant propagation", () => { agent: "explore", model: { providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }, }, @@ -1231,7 +1231,7 @@ describe("BackgroundManager.notifyParentSession - variant propagation", () => { status: "completed", startedAt: new Date(), completedAt: new Date(), - model: { providerID: "anthropic", modelID: "claude-opus-4.6", variant: "high" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7", variant: "high" }, } getPendingByParent(manager).set("session-parent", new Set([task.id])) @@ -1272,7 +1272,7 @@ describe("BackgroundManager.notifyParentSession - variant propagation", () => { status: "completed", startedAt: new Date(), completedAt: new Date(), - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getPendingByParent(manager).set("session-parent", new Set([task.id])) @@ -1349,7 +1349,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should release concurrency and clear key on completion", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) await concurrencyManager.acquire(concurrencyKey) @@ -1378,7 +1378,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should prevent double completion and double release", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) await concurrencyManager.acquire(concurrencyKey) @@ -1508,7 +1508,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should release task concurrencyKey when startTask throws after assigning it", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) const task = createMockTask({ @@ -1524,7 +1524,7 @@ describe("BackgroundManager.tryCompleteTask", () => { agent: task.agent, parentSessionID: task.parentSessionID, parentMessageID: task.parentMessageID, - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getTaskMap(manager).set(task.id, task) getQueuesByKey(manager).set(concurrencyKey, [{ task, input }]) @@ -1544,7 +1544,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should mark task as error when startTask throws after session creation", async () => { //#given - startTask creates session but fails before sending prompt - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const task = createMockTask({ id: "task-zombie-session", @@ -1561,7 +1561,7 @@ describe("BackgroundManager.tryCompleteTask", () => { agent: task.agent, parentSessionID: task.parentSessionID, parentMessageID: task.parentMessageID, - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getTaskMap(manager).set(task.id, task) getQueuesByKey(manager).set(concurrencyKey, [{ task, input }]) @@ -1585,7 +1585,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should release queue slot when queued task is already interrupt", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) const task = createMockTask({ @@ -1601,7 +1601,7 @@ describe("BackgroundManager.tryCompleteTask", () => { agent: task.agent, parentSessionID: task.parentSessionID, parentMessageID: task.parentMessageID, - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getTaskMap(manager).set(task.id, task) getQueuesByKey(manager).set(concurrencyKey, [{ task, input }]) @@ -2104,7 +2104,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { agent: "test-agent", parentSessionID: "parent-session", parentMessageID: "parent-message", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } const launchInputWithoutModel = { description: "Test task without model", @@ -2124,7 +2124,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { expect(taskWithModel.status).toBe("pending") expect(taskWithoutModel.status).toBe("pending") expect(promptBodies).toHaveLength(2) - expect(promptBodies[0].model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.6" }) + expect(promptBodies[0].model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.7" }) expect(promptBodies[0].agent).toBe("test-agent") expect(promptBodies[1].agent).toBe("test-agent") expect("model" in promptBodies[1]).toBe(false) @@ -3245,7 +3245,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { description: "Task 1", prompt: "Do something", agent: "test-agent", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, parentSessionID: "parent-session", parentMessageID: "parent-message", } @@ -4225,7 +4225,7 @@ describe("BackgroundManager.handleEvent - session.deleted cascade", () => { describe("BackgroundManager.handleEvent - session.error", () => { const defaultRetryFallbackChain = [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["anthropic"], model: "gpt-5.3-codex", variant: "high" }, ] @@ -4249,7 +4249,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { agent: "sisyphus", status: "running", concurrencyKey: input.concurrencyKey, - model: { providerID: "anthropic", modelID: "claude-opus-4.6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7-thinking" }, fallbackChain: input.fallbackChain ?? defaultRetryFallbackChain, attemptCount: 0, }) @@ -4394,7 +4394,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { //#given const manager = createBackgroundManager() const concurrencyManager = getConcurrencyManager(manager) - const concurrencyKey = "anthropic/claude-opus-4.6-thinking" + const concurrencyKey = "anthropic/claude-opus-4.7-thinking" await concurrencyManager.acquire(concurrencyKey) stubProcessKey(manager) @@ -4406,7 +4406,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { description: "task that should retry", concurrencyKey, fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["anthropic"], model: "claude-opus-4-5", variant: "max" }, ], }) @@ -4420,7 +4420,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { name: "UnknownError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.7-thinking\"}}", }, }, }, @@ -4431,7 +4431,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { expect(task.attemptCount).toBe(1) expect(task.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }) expect(task.concurrencyKey).toBeUndefined() @@ -4469,7 +4469,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { expect(task.attemptCount).toBe(1) expect(task.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }) @@ -4497,7 +4497,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { name: "UnknownError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.7-thinking\"}}", }, }, } @@ -4514,7 +4514,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { expect(task.attemptCount).toBe(1) expect(task.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }) diff --git a/src/features/background-agent/task-poller.test.ts b/src/features/background-agent/task-poller.test.ts index 1811051c5..532fd6e57 100644 --- a/src/features/background-agent/task-poller.test.ts +++ b/src/features/background-agent/task-poller.test.ts @@ -648,7 +648,7 @@ describe("checkAndInterruptStaleTasks", () => { const task = createRunningTask({ startedAt: new Date(Date.now() - 15 * 60 * 1000), progress: undefined, - concurrencyKey: "anthropic/claude-opus-4-6", + concurrencyKey: "anthropic/claude-opus-4-7", }) //#when @@ -661,7 +661,7 @@ describe("checkAndInterruptStaleTasks", () => { }) //#then - expect(releaseMock).toHaveBeenCalledWith("anthropic/claude-opus-4-6") + expect(releaseMock).toHaveBeenCalledWith("anthropic/claude-opus-4-7") expect(task.concurrencyKey).toBeUndefined() }) diff --git a/src/features/claude-code-agent-loader/claude-model-mapper.test.ts b/src/features/claude-code-agent-loader/claude-model-mapper.test.ts index b5f1983a9..97693761f 100644 --- a/src/features/claude-code-agent-loader/claude-model-mapper.test.ts +++ b/src/features/claude-code-agent-loader/claude-model-mapper.test.ts @@ -23,8 +23,8 @@ describe("mapClaudeModelToOpenCode", () => { expect(mapClaudeModelToOpenCode("sonnet")).toEqual({ providerID: "anthropic", modelID: "claude-sonnet-4-6" }) }) - it("#when called with opus #then maps to anthropic claude-opus-4-6 object", () => { - expect(mapClaudeModelToOpenCode("opus")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + it("#when called with opus #then maps to anthropic claude-opus-4-7 object", () => { + expect(mapClaudeModelToOpenCode("opus")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }) it("#when called with haiku #then maps to anthropic claude-haiku-4-5 object", () => { @@ -47,8 +47,8 @@ describe("mapClaudeModelToOpenCode", () => { expect(mapClaudeModelToOpenCode("claude-sonnet-4-5-20250514")).toEqual({ providerID: "anthropic", modelID: "claude-sonnet-4-5-20250514" }) }) - it("#when called with claude-opus-4-6 #then adds anthropic object format", () => { - expect(mapClaudeModelToOpenCode("claude-opus-4-6")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + it("#when called with claude-opus-4-7 #then adds anthropic object format", () => { + expect(mapClaudeModelToOpenCode("claude-opus-4-7")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }) it("#when called with claude-haiku-4-5-20251001 #then adds anthropic object format", () => { diff --git a/src/features/claude-code-agent-loader/claude-model-mapper.ts b/src/features/claude-code-agent-loader/claude-model-mapper.ts index 736a5f303..7737de5f7 100644 --- a/src/features/claude-code-agent-loader/claude-model-mapper.ts +++ b/src/features/claude-code-agent-loader/claude-model-mapper.ts @@ -5,7 +5,7 @@ const ANTHROPIC_PREFIX = "anthropic/" const CLAUDE_CODE_ALIAS_MAP = new Map([ ["sonnet", `${ANTHROPIC_PREFIX}claude-sonnet-4-6`], - ["opus", `${ANTHROPIC_PREFIX}claude-opus-4-6`], + ["opus", `${ANTHROPIC_PREFIX}claude-opus-4-7`], ["haiku", `${ANTHROPIC_PREFIX}claude-haiku-4-5`], ]) diff --git a/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts b/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts index e90bc2519..1e1fce79a 100644 --- a/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts +++ b/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts @@ -38,7 +38,7 @@ describe("readOpencodeConfigAgents", () => { agents: { "my-agent": { description: "Custom agent", - model: "claude-opus-4-6", + model: "claude-opus-4-7", mode: "subagent", prompt: "You are a helpful assistant", }, diff --git a/src/features/task-toast-manager/manager.test.ts b/src/features/task-toast-manager/manager.test.ts index d99698347..92ab524a0 100644 --- a/src/features/task-toast-manager/manager.test.ts +++ b/src/features/task-toast-manager/manager.test.ts @@ -203,7 +203,7 @@ describe("TaskToastManager", () => { description: "Task with inherited model", agent: "sisyphus-junior", isBackground: false, - modelInfo: { model: "cliproxy/claude-opus-4-6", type: "inherited" as const }, + modelInfo: { model: "cliproxy/claude-opus-4-7", type: "inherited" as const }, } // when - addTask is called @@ -213,7 +213,7 @@ describe("TaskToastManager", () => { expect(mockClient.tui.showToast).toHaveBeenCalled() const call = mockClient.tui.showToast.mock.calls[0][0] expect(call.body.message).toContain("[FALLBACK]") - expect(call.body.message).toContain("cliproxy/claude-opus-4-6") + expect(call.body.message).toContain("cliproxy/claude-opus-4-7") expect(call.body.message).toContain("(inherited from parent)") }) diff --git a/src/generated/model-capabilities.generated.json b/src/generated/model-capabilities.generated.json index 4d51ec888..b307aeadd 100644 --- a/src/generated/model-capabilities.generated.json +++ b/src/generated/model-capabilities.generated.json @@ -1,223 +1,12 @@ { - "generatedAt": "2026-03-25T13:44:08.677Z", + "generatedAt": "2026-04-17T05:38:15.814Z", "sourceUrl": "https://models.dev/api.json", "models": { - "nvidia/llama-3.3-70b-instruct-fp8": { - "id": "nvidia/Llama-3.3-70B-Instruct-FP8", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "microsoft/phi-4-multimodal-instruct": { - "id": "microsoft/phi-4-multimodal-instruct", - "family": "phi", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - }, - "temperature": true - }, - "intfloat/multilingual-e5-large-instruct": { - "id": "intfloat/multilingual-e5-large-instruct", - "family": "text-embedding", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 512, - "output": 1024 - }, - "temperature": false - }, - "moonshotai/kimi-k2.5": { - "id": "moonshotai/kimi-k2.5", - "family": "kimi", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536, - "input": 256000 - }, - "temperature": true - }, - "kblab/kb-whisper-large": { - "id": "KBLab/kb-whisper-large", - "family": "whisper", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 480000, - "output": 4800 - }, - "temperature": false - }, - "qwen/qwen3-30b-a3b-instruct-2507-fp8": { - "id": "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8", + "qwen3-235b-a22b": { + "id": "qwen3-235b-a22b", "family": "qwen", "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 64000 - } - }, - "qwen/qwen3-embedding-8b": { - "id": "Qwen/Qwen3-Embedding-8B", - "family": "qwen", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 4096, - "input": 32768 - }, - "temperature": false - }, - "qwen/qwen3-vl-30b-a3b-instruct": { - "id": "qwen/qwen3-vl-30b-a3b-instruct", - "family": "qwen", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - }, - "temperature": true - }, - "mistralai/voxtral-small-24b-2507": { - "id": "mistralai/voxtral-small-24b-2507", - "family": "voxtral", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 6400 - }, - "temperature": true - }, - "mistralai/devstral-small-2-24b-instruct-2512": { - "id": "mistralai/devstral-small-2-24b-instruct-2512", - "family": "devstral", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "mistralai/magistral-small-2509": { - "id": "mistralai/Magistral-Small-2509", - "family": "magistral-small", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "openai/gpt-oss-120b": { - "id": "openai/gpt-oss-120b", - "family": "gpt-oss", - "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ @@ -229,172 +18,18 @@ }, "limit": { "context": 128000, - "output": 16384, - "input": 128000 - }, - "temperature": true + "output": 32000 + } }, - "openai/whisper-large-v3": { - "id": "openai/whisper-large-v3", - "family": "whisper", + "grok-4.1": { + "id": "grok-4.1", "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 4096 - }, - "temperature": false - }, - "glm-5": { - "id": "glm-5", - "family": "glm", - "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 16384 - } - }, - "glm-4.5-air": { - "id": "glm-4.5-air", - "family": "glm-air", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "glm-4.5": { - "id": "glm-4.5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "glm-4.5-flash": { - "id": "glm-4.5-flash", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 98304 - } - }, - "glm-4.7-flash": { - "id": "glm-4.7-flash", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 203000, - "output": 203000 - } - }, - "glm-4.6": { - "id": "glm-4.6", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "glm-4.7": { - "id": "glm-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 198000 - } - }, - "glm-5-turbo": { - "id": "glm-5-turbo", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" + "text", + "image" ], "output": [ "text" @@ -402,234 +37,11 @@ }, "limit": { "context": 200000, - "output": 131072 - } - }, - "glm-4.5v": { - "id": "glm-4.5v", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 16384 - } - }, - "glm-4.6v": { - "id": "glm-4.6v", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "minimax-m2.5": { - "id": "MiniMax-M2.5", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "input": 196601, - "output": 131072 - } - }, - "qwen3-coder-next": { - "id": "qwen3-coder-next", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536, - "input": 262144 - } - }, - "kimi-k2.5": { - "id": "kimi-k2.5", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "qwen3-max-2026-01-23": { - "id": "qwen3-max-2026-01-23", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32768, - "input": 256000 - } - }, - "qwen3.5-plus": { - "id": "qwen3.5-plus", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65536 - } - }, - "qwen3-coder-plus": { - "id": "qwen3-coder-plus", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "xiaomi/mimo-v2-omni": { - "id": "xiaomi/mimo-v2-omni", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - }, - "family": "mimo" - }, - "xiaomi/mimo-v2-flash-free": { - "id": "xiaomi/mimo-v2-flash-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, "output": 64000 } }, - "xiaomi/mimo-v2-flash": { - "id": "xiaomi/mimo-v2-flash", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32768, - "input": 256000 - }, - "family": "mimo" - }, - "xiaomi/mimo-v2-pro": { - "id": "xiaomi/mimo-v2-pro", + "minimax-m2": { + "id": "MiniMax-M2", "reasoning": true, "temperature": true, "toolCall": true, @@ -642,201 +54,14 @@ ] }, "limit": { - "context": 1000000, - "output": 128000 + "context": 196608, + "output": 128000, + "input": 200000 }, - "family": "mimo" + "family": "minimax" }, - "kuaishou/kat-coder-pro-v1-free": { - "id": "kuaishou/kat-coder-pro-v1-free", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "kuaishou/kat-coder-pro-v1": { - "id": "kuaishou/kat-coder-pro-v1", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "stepfun/step-3.5-flash-free": { - "id": "stepfun/step-3.5-flash-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "stepfun/step-3.5-flash": { - "id": "stepfun/step-3.5-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - }, - "family": "step" - }, - "stepfun/step-3": { - "id": "stepfun/step-3", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 64000 - } - }, - "inclusionai/ling-1t": { - "id": "inclusionai/ling-1t", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 64000 - } - }, - "inclusionai/ring-1t": { - "id": "inclusionai/ring-1t", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 64000 - } - }, - "volcengine/doubao-seed-1.8": { - "id": "volcengine/doubao-seed-1.8", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "volcengine/doubao-seed-2.0-pro": { - "id": "volcengine/doubao-seed-2.0-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "volcengine/doubao-seed-2.0-mini": { - "id": "volcengine/doubao-seed-2.0-mini", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "volcengine/doubao-seed-code": { - "id": "volcengine/doubao-seed-code", + "grok-4-1-fast-reasoning": { + "id": "grok-4-1-fast-reasoning", "reasoning": true, "temperature": true, "toolCall": true, @@ -850,108 +75,34 @@ ] }, "limit": { - "context": 256000, - "output": 64000 - } - }, - "volcengine/doubao-seed-2.0-lite": { - "id": "volcengine/doubao-seed-2.0-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] + "context": 128000, + "output": 8192, + "input": 128000 }, - "limit": { - "context": 256000, - "output": 64000 - } + "family": "grok" }, - "volcengine/doubao-seed-2.0-code": { - "id": "volcengine/doubao-seed-2.0-code", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "deepseek/deepseek-v3.2": { - "id": "deepseek/deepseek-v3.2", + "gemini-2.5-flash-nothink": { + "id": "gemini-2.5-flash-nothink", + "family": "gemini-flash", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "pdf" + "image" ], "output": [ "text" ] }, "limit": { - "context": 163000, - "output": 65536, - "input": 163000 - }, - "family": "deepseek" - }, - "deepseek/deepseek-chat": { - "id": "deepseek/deepseek-chat", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "deepseek/deepseek-v3.2-exp": { - "id": "deepseek/deepseek-v3.2-exp", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, + "context": 1000000, "output": 65536 - }, - "family": "deepseek" + } }, - "moonshotai/kimi-k2-0905": { - "id": "moonshotai/kimi-k2-0905", + "kimi-k2-0905-preview": { + "id": "kimi-k2-0905-preview", "reasoning": false, "temperature": true, "toolCall": true, @@ -964,52 +115,13 @@ ] }, "limit": { - "context": 131072, - "output": 26215 + "context": 262144, + "output": 262144 }, "family": "kimi" }, - "moonshotai/kimi-k2-thinking": { - "id": "moonshotai/kimi-k2-thinking", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 262144, - "input": 256000 - }, - "family": "kimi-thinking" - }, - "moonshotai/kimi-k2-thinking-turbo": { - "id": "moonshotai/kimi-k2-thinking-turbo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262114, - "output": 262114 - }, - "family": "kimi-thinking" - }, - "baidu/ernie-5.0-thinking-preview": { - "id": "baidu/ernie-5.0-thinking-preview", + "claude-opus-4-5-20251101": { + "id": "claude-opus-4-5-20251101", "reasoning": true, "temperature": true, "toolCall": true, @@ -1017,223 +129,7 @@ "input": [ "text", "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 64000 - } - }, - "google/gemini-2.5-flash": { - "id": "google/gemini-2.5-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65535 - }, - "family": "gemini-flash" - }, - "google/gemini-3.1-flash-lite-preview": { - "id": "google/gemini-3.1-flash-lite-preview", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - }, - "family": "gemini" - }, - "google/gemini-3-flash-preview": { - "id": "google/gemini-3-flash-preview", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - }, - "family": "gemini-flash" - }, - "google/gemini-2.5-flash-lite": { - "id": "google/gemini-2.5-flash-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65535 - }, - "family": "gemini-flash-lite" - }, - "google/gemini-3.1-pro-preview": { - "id": "google/gemini-3.1-pro-preview", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - }, - "family": "gemini" - }, - "google/gemini-3-pro-image-preview": { - "id": "google/gemini-3-pro-image-preview", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image", - "text" - ] - }, - "limit": { - "context": 65536, - "output": 32768 - } - }, - "google/gemini-3-pro-preview": { - "id": "google/gemini-3-pro-preview", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - }, - "family": "gemini-pro" - }, - "google/gemini-2.5-pro": { - "id": "google/gemini-2.5-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - }, - "family": "gemini-pro" - }, - "z-ai/glm-5": { - "id": "z-ai/glm-5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 131072 - }, - "family": "glm" - }, - "z-ai/glm-4.7-flashx": { - "id": "z-ai/glm-4.7-flashx", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" + "pdf" ], "output": [ "text" @@ -1241,3830 +137,13 @@ }, "limit": { "context": 200000, - "output": 64000 - } - }, - "z-ai/glm-4.5-air": { - "id": "z-ai/glm-4.5-air", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 98304 - }, - "family": "glm-air" - }, - "z-ai/glm-4.5": { - "id": "z-ai/glm-4.5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 98304 - }, - "family": "glm" - }, - "z-ai/glm-4.6v-flash-free": { - "id": "z-ai/glm-4.6v-flash-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "z-ai/glm-4.6": { - "id": "z-ai/glm-4.6", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 65535, + "output": 64000, "input": 200000 }, - "family": "glm" - }, - "z-ai/glm-4.7": { - "id": "z-ai/glm-4.7", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 65535 - }, - "family": "glm" - }, - "z-ai/glm-4.7-flash-free": { - "id": "z-ai/glm-4.7-flash-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "z-ai/glm-4.6v-flash": { - "id": "z-ai/glm-4.6v-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "z-ai/glm-5-turbo": { - "id": "z-ai/glm-5-turbo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000 - } - }, - "z-ai/glm-4.6v": { - "id": "z-ai/glm-4.6v", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "qwen/qwen3.5-flash": { - "id": "qwen/qwen3.5-flash", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1020000, - "output": 1020000 - } - }, - "qwen/qwen3.5-plus": { - "id": "Qwen/Qwen3.5-Plus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65536 - }, - "family": "qwen" - }, - "qwen/qwen3-max": { - "id": "qwen/qwen3-max", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - }, - "family": "qwen" - }, - "qwen/qwen3-coder-plus": { - "id": "qwen/qwen3-coder-plus", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65536 - } - }, - "x-ai/grok-code-fast-1": { - "id": "x-ai/grok-code-fast-1", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 131072, - "input": 256000 - }, - "family": "grok" - }, - "x-ai/grok-4-fast": { - "id": "x-ai/grok-4-fast", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 131072, - "input": 2000000 - }, - "family": "grok" - }, - "x-ai/grok-4": { - "id": "x-ai/grok-4", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 51200 - }, - "family": "grok" - }, - "x-ai/grok-4.1-fast-non-reasoning": { - "id": "x-ai/grok-4.1-fast-non-reasoning", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "x-ai/grok-4.1-fast": { - "id": "x-ai/grok-4.1-fast", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 131072, - "input": 2000000 - }, - "family": "grok" - }, - "x-ai/grok-4.2-fast": { - "id": "x-ai/grok-4.2-fast", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 30000 - } - }, - "x-ai/grok-4.2-fast-non-reasoning": { - "id": "x-ai/grok-4.2-fast-non-reasoning", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 30000 - } - }, - "openai/gpt-5.3-codex": { - "id": "openai/gpt-5.3-codex", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 272000 - }, - "family": "gpt" - }, - "openai/gpt-5-codex": { - "id": "openai/gpt-5-codex", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32768, - "input": 256000 - }, - "family": "gpt-codex" - }, - "openai/gpt-5.2-codex": { - "id": "openai/gpt-5.2-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt-codex" - }, - "openai/gpt-5.1": { - "id": "openai/gpt-5.1", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt" - }, - "openai/gpt-5.1-chat": { - "id": "openai/gpt-5.1-chat", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt" - }, - "openai/gpt-5.1-codex-mini": { - "id": "openai/gpt-5.1-codex-mini", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt-codex-mini" - }, - "openai/gpt-5.2": { - "id": "openai/gpt-5.2", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt" - }, - "openai/gpt-5": { - "id": "openai/gpt-5", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt" - }, - "openai/gpt-5.4": { - "id": "openai/gpt-5.4", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1050000, - "output": 128000, - "input": 922000 - }, - "family": "gpt" - }, - "openai/gpt-5.4-pro": { - "id": "openai/gpt-5.4-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1050000, - "output": 128000, - "input": 922000 - }, - "family": "gpt" - }, - "openai/gpt-5.3-chat": { - "id": "openai/gpt-5.3-chat", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 111616 - }, - "family": "gpt" - }, - "openai/gpt-5.1-codex": { - "id": "openai/gpt-5.1-codex", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt-codex" - }, - "openai/gpt-5.2-pro": { - "id": "openai/gpt-5.2-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt-pro" - }, - "openai/gpt-5.4-nano": { - "id": "openai/gpt-5.4-nano", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 272000 - }, - "family": "gpt" - }, - "openai/gpt-5.4-mini": { - "id": "openai/gpt-5.4-mini", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 272000 - }, - "family": "gpt" - }, - "minimax/minimax-m2.5-lightning": { - "id": "minimax/minimax-m2.5-lightning", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "minimax/minimax-m2.1": { - "id": "minimax/minimax-m2.1", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 131072, - "input": 200000 - }, - "family": "minimax" - }, - "minimax/minimax-m2.7": { - "id": "minimax/minimax-m2.7", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072, - "input": 204800 - }, - "family": "minimax" - }, - "minimax/minimax-m2.7-highspeed": { - "id": "minimax/minimax-m2.7-highspeed", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131100 - }, - "family": "minimax" - }, - "minimax/minimax-m2": { - "id": "minimax/minimax-m2", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 196608 - }, - "family": "minimax" - }, - "minimax/minimax-m2.5": { - "id": "MiniMax/MiniMax-M2.5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072, - "input": 204800 - }, - "family": "minimax" - }, - "anthropic/claude-3.5-sonnet": { - "id": "anthropic/claude-3.5-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - }, - "family": "claude-sonnet" - }, - "anthropic/claude-3.7-sonnet": { - "id": "anthropic/claude-3.7-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - }, - "family": "claude-sonnet" - }, - "anthropic/claude-opus-4.1": { - "id": "anthropic/claude-opus-4.1", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - }, "family": "claude-opus" }, - "anthropic/claude-sonnet-4.6": { - "id": "anthropic/claude-sonnet-4.6", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000, - "input": 1000000 - }, - "family": "claude-sonnet" - }, - "anthropic/claude-haiku-4.5": { - "id": "anthropic/claude-haiku-4.5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - }, - "family": "claude-haiku" - }, - "anthropic/claude-3.5-haiku": { - "id": "anthropic/claude-3.5-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - }, - "family": "claude-haiku" - }, - "anthropic/claude-opus-4.5": { - "id": "anthropic/claude-opus-4.5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - }, - "family": "claude-opus" - }, - "anthropic/claude-opus-4": { - "id": "anthropic/claude-opus-4", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - }, - "family": "claude-opus" - }, - "anthropic/claude-sonnet-4": { - "id": "anthropic/claude-sonnet-4", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - }, - "family": "claude-sonnet" - }, - "anthropic/claude-sonnet-4.5": { - "id": "anthropic/claude-sonnet-4.5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - }, - "family": "claude-sonnet" - }, - "anthropic/claude-opus-4.6": { - "id": "anthropic/claude-opus-4.6", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000, - "input": 1000000 - }, - "family": "claude-opus" - }, - "zai-org/glm-4.6": { - "id": "zai-org/GLM-4.6", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 131072 - } - }, - "deepseek-ai/deepseek-r1-0528": { - "id": "deepseek-ai/DeepSeek-R1-0528", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 163840, - "input": 128000 - } - }, - "intel/qwen3-coder-480b-a35b-instruct-int4-mixed-ar": { - "id": "Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 106000, - "output": 4096 - } - }, - "moonshotai/kimi-k2-instruct-0905": { - "id": "moonshotai/Kimi-K2-Instruct-0905", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144, - "input": 256000 - } - }, - "meta-llama/llama-3.2-90b-vision-instruct": { - "id": "meta-llama/llama-3.2-90b-vision-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384, - "input": 131072 - } - }, - "meta-llama/llama-3.3-70b-instruct": { - "id": "meta-llama/llama-3.3-70b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384, - "input": 131072 - } - }, - "meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { - "id": "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 32768 - } - }, - "qwen/qwen3-next-80b-a3b-instruct": { - "id": "Qwen/Qwen3-Next-80B-A3B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen/qwen3-235b-a22b-thinking-2507": { - "id": "Qwen/Qwen3-235B-A22B-Thinking-2507", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen/qwen2.5-vl-32b-instruct": { - "id": "Qwen/Qwen2.5-VL-32B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "mistralai/mistral-nemo-instruct-2407": { - "id": "mistralai/Mistral-Nemo-Instruct-2407", - "family": "mistral-nemo", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 8192, - "input": 16384 - } - }, - "mistralai/magistral-small-2506": { - "id": "mistralai/Magistral-Small-2506", - "family": "magistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistralai/mistral-large-instruct-2411": { - "id": "mistralai/Mistral-Large-Instruct-2411", - "family": "mistral-large", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistralai/devstral-small-2505": { - "id": "mistralai/Devstral-Small-2505", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 8192, - "input": 32768 - } - }, - "openai/gpt-oss-20b": { - "id": "openai/gpt-oss-20b", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072, - "input": 128000 - } - }, - "nvidia/nemotron-3-super-120b-a12b": { - "id": "nvidia/nemotron-3-super-120b-a12b", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144, - "input": 256000 - } - }, - "nvidia/llama-3.1-nemotron-70b-instruct": { - "id": "nvidia/llama-3.1-nemotron-70b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "nvidia/llama-3.1-nemotron-ultra-253b-v1": { - "id": "nvidia/Llama-3.1-Nemotron-Ultra-253B-v1", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - } - }, - "nvidia/llama-3.1-nemotron-51b-instruct": { - "id": "nvidia/llama-3.1-nemotron-51b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "nvidia/parakeet-tdt-0.6b-v2": { - "id": "nvidia/parakeet-tdt-0.6b-v2", - "family": "parakeet", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 4096 - } - }, - "nvidia/nvidia-nemotron-nano-9b-v2": { - "id": "nvidia/nvidia-nemotron-nano-9b-v2", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - } - }, - "nvidia/llama-embed-nemotron-8b": { - "id": "nvidia/llama-embed-nemotron-8b", - "family": "llama", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 2048 - } - }, - "nvidia/llama-3.3-nemotron-super-49b-v1.5": { - "id": "nvidia/llama-3.3-nemotron-super-49b-v1.5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "nvidia/llama-3.3-nemotron-super-49b-v1": { - "id": "nvidia/Llama-3.3-Nemotron-Super-49B-v1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - }, - "family": "nemotron" - }, - "nvidia/llama3-chatqa-1.5-70b": { - "id": "nvidia/llama3-chatqa-1.5-70b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "nvidia/cosmos-nemotron-34b": { - "id": "nvidia/cosmos-nemotron-34b", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "nvidia/nemoretriever-ocr-v1": { - "id": "nvidia/nemoretriever-ocr-v1", - "family": "nemoretriever", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 4096 - } - }, - "nvidia/nemotron-4-340b-instruct": { - "id": "nvidia/nemotron-4-340b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "nvidia/nemotron-3-nano-30b-a3b": { - "id": "nvidia/nemotron-3-nano-30b-a3b", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 262144, - "input": 256000 - } - }, - "microsoft/phi-3-small-128k-instruct": { - "id": "microsoft/phi-3-small-128k-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - }, - "family": "phi" - }, - "microsoft/phi-3-medium-128k-instruct": { - "id": "microsoft/phi-3-medium-128k-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - }, - "family": "phi" - }, - "microsoft/phi-3.5-moe-instruct": { - "id": "microsoft/phi-3.5-moe-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - }, - "family": "phi" - }, - "microsoft/phi-3-vision-128k-instruct": { - "id": "microsoft/phi-3-vision-128k-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "microsoft/phi-4-mini-instruct": { - "id": "microsoft/phi-4-mini-instruct", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "microsoft/phi-3.5-vision-instruct": { - "id": "microsoft/phi-3.5-vision-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - }, - "family": "phi" - }, - "microsoft/phi-3-medium-4k-instruct": { - "id": "microsoft/phi-3-medium-4k-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 1024 - }, - "family": "phi" - }, - "microsoft/phi-3-small-8k-instruct": { - "id": "microsoft/phi-3-small-8k-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - }, - "family": "phi" - }, - "minimaxai/minimax-m2.1": { - "id": "MiniMaxAI/MiniMax-M2.1", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 196608, - "input": 120000 - } - }, - "minimaxai/minimax-m2.5": { - "id": "MiniMaxAI/MiniMax-M2.5", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 196608 - } - }, - "deepseek-ai/deepseek-v3.1": { - "id": "deepseek-ai/DeepSeek-V3.1", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 65536, - "input": 128000 - } - }, - "deepseek-ai/deepseek-r1": { - "id": "deepseek-ai/DeepSeek-R1", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 164000, - "output": 164000 - }, - "family": "deepseek-thinking" - }, - "deepseek-ai/deepseek-v3.1-terminus": { - "id": "deepseek-ai/DeepSeek-V3.1-Terminus", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 65536, - "input": 128000 - } - }, - "deepseek-ai/deepseek-coder-6.7b-instruct": { - "id": "deepseek-ai/deepseek-coder-6.7b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "deepseek-ai/deepseek-v3.2": { - "id": "deepseek-ai/DeepSeek-V3.2", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536, - "input": 160000 - } - }, - "moonshotai/kimi-k2-instruct": { - "id": "moonshotai/kimi-k2-instruct", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8192, - "input": 256000 - } - }, - "google/codegemma-7b": { - "id": "google/codegemma-7b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "google/gemma-2-2b-it": { - "id": "google/gemma-2-2b-it", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096, - "input": 8000 - } - }, - "google/gemma-3-1b-it": { - "id": "google/gemma-3-1b-it", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "google/gemma-2-27b-it": { - "id": "google/gemma-2-27b-it", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - } - }, - "google/gemma-3n-e2b-it": { - "id": "google/gemma-3n-e2b-it", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "google/codegemma-1.1-7b": { - "id": "google/codegemma-1.1-7b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "google/gemma-3n-e4b-it": { - "id": "google/gemma-3n-e4b-it", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 6554 - }, - "family": "gemma" - }, - "google/gemma-3-12b-it": { - "id": "google/gemma-3-12b-it", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - }, - "family": "gemma" - }, - "google/gemma-3-27b-it": { - "id": "google/gemma-3-27b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 65536, - "input": 100000 - } - }, - "z-ai/glm4.7": { - "id": "z-ai/glm4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "z-ai/glm5": { - "id": "z-ai/glm5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 131000 - } - }, - "stepfun-ai/step-3.5-flash": { - "id": "stepfun-ai/step-3.5-flash", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000, - "input": 256000 - }, - "family": "step" - }, - "qwen/qwen3-next-80b-a3b-thinking": { - "id": "qwen/qwen3-next-80b-a3b-thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768, - "input": 120000 - } - }, - "qwen/qwen3-coder-480b-a35b-instruct": { - "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 66536 - } - }, - "qwen/qwq-32b": { - "id": "qwen/qwq-32b", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - }, - "family": "qwen" - }, - "qwen/qwen2.5-coder-7b-instruct": { - "id": "qwen/qwen2.5-coder-7b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 6554 - } - }, - "qwen/qwen3.5-397b-a17b": { - "id": "qwen/qwen3.5-397b-a17b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 258048, - "output": 65536, - "input": 258048 - } - }, - "qwen/qwen2.5-coder-32b-instruct": { - "id": "Qwen/Qwen2.5-Coder-32B-Instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - }, - "family": "qwen" - }, - "qwen/qwen3-235b-a22b": { - "id": "Qwen/Qwen3-235B-A22B", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 40960 - } - }, - "meta/llama-3.1-70b-instruct": { - "id": "meta/llama-3.1-70b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "meta/llama-3.3-70b-instruct": { - "id": "meta/llama-3.3-70b-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - }, - "family": "llama" - }, - "meta/llama-4-scout-17b-16e-instruct": { - "id": "meta/llama-4-scout-17b-16e-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - }, - "family": "llama" - }, - "meta/llama-3.2-11b-vision-instruct": { - "id": "meta/llama-3.2-11b-vision-instruct", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - }, - "family": "llama" - }, - "meta/llama3-8b-instruct": { - "id": "meta/llama3-8b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "meta/codellama-70b": { - "id": "meta/codellama-70b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "meta/llama-3.2-1b-instruct": { - "id": "meta/llama-3.2-1b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "output": 4096 - }, - "family": "llama" - }, - "meta/llama-3.1-405b-instruct": { - "id": "meta/llama-3.1-405b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "meta/llama3-70b-instruct": { - "id": "meta/llama3-70b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "meta/llama-4-maverick-17b-128e-instruct": { - "id": "meta/llama-4-maverick-17b-128e-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistralai/mistral-large-3-675b-instruct-2512": { - "id": "mistralai/mistral-large-3-675b-instruct-2512", - "family": "mistral-large", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 256000, - "input": 262144 - } - }, - "mistralai/mamba-codestral-7b-v0.1": { - "id": "mistralai/mamba-codestral-7b-v0.1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistralai/codestral-22b-instruct-v0.1": { - "id": "mistralai/codestral-22b-instruct-v0.1", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistralai/mistral-large-2-instruct": { - "id": "mistralai/mistral-large-2-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistralai/ministral-14b-instruct-2512": { - "id": "mistralai/ministral-14b-instruct-2512", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768, - "input": 262144 - } - }, - "mistralai/mistral-small-3.1-24b-instruct-2503": { - "id": "mistralai/mistral-small-3.1-24b-instruct-2503", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistralai/devstral-2-123b-instruct-2512": { - "id": "mistralai/devstral-2-123b-instruct-2512", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536, - "input": 262144 - } - }, - "black-forest-labs/flux.1-dev": { - "id": "black-forest-labs/flux.1-dev", - "family": "flux", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 4096, - "output": 0 - } - }, - "deepseek-ai/deepseek-r1-distill-llama-70b": { - "id": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "moonshotai/kimi-k2": { - "id": "moonshotai/kimi-k2", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 26215 - } - }, - "qwen/qwen3-coder": { - "id": "qwen/qwen3-coder", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 52429 - } - }, - "openai/gpt-4.1": { - "id": "openai/gpt-4.1", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1047576, - "output": 32768, - "input": 1047576 - } - }, - "openai/gpt-5-mini": { - "id": "openai/gpt-5-mini", - "family": "gpt-mini", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - } - }, - "openai/gpt-5-nano": { - "id": "openai/gpt-5-nano", - "family": "gpt-nano", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - } - }, - "kimi-k2": { - "id": "kimi-k2", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen3-max-preview": { - "id": "qwen3-max-preview", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "deepseek-v3": { - "id": "deepseek-v3", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 8192 - } - }, - "kimi-k2-0905": { - "id": "kimi-k2-0905", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 16384 - } - }, - "qwen3-235b-a22b-instruct": { - "id": "qwen3-235b-a22b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "deepseek-r1": { - "id": "deepseek-r1", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384, - "input": 128000 - } - }, - "qwen3-32b": { - "id": "qwen3-32b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "deepseek-v3.2": { - "id": "deepseek-v3.2", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "qwen3-235b": { - "id": "qwen3-235b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "qwen3-vl-plus": { - "id": "qwen3-vl-plus", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "qwen3-235b-a22b-thinking-2507": { - "id": "qwen3-235b-a22b-thinking-2507", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "qwen3-max": { - "id": "qwen3-max", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "qwen/qwen3-30b-a3b-instruct-2507": { - "id": "Qwen/Qwen3-30B-A3B-Instruct-2507", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144, - "input": 120000 - } - }, - "qwen/qwen3-30b-a3b-thinking-2507": { - "id": "qwen/qwen3-30b-a3b-thinking-2507", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 6554, - "input": 120000 - } - }, - "qwen/qwen3-coder-30b-a3b-instruct": { - "id": "qwen/qwen3-coder-30b-a3b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 160000, - "output": 32768, - "input": 120000 - } - }, - "qwen/qwen3-235b-a22b-instruct-2507": { - "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "zhipuai/glm-4.6": { - "id": "ZhipuAI/GLM-4.6", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 98304 - } - }, - "zhipuai/glm-4.5": { - "id": "ZhipuAI/GLM-4.5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 98304 - } - }, - "cerebras-llama-4-maverick-17b-128e-instruct": { - "id": "cerebras-llama-4-maverick-17b-128e-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "llama-4-scout-17b-16e-instruct-fp8": { - "id": "llama-4-scout-17b-16e-instruct-fp8", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "llama-3.3-8b-instruct": { - "id": "llama-3.3-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "groq-llama-4-maverick-17b-128e-instruct": { - "id": "groq-llama-4-maverick-17b-128e-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "llama-3.3-70b-instruct": { - "id": "llama-3.3-70b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "cerebras-llama-4-scout-17b-16e-instruct": { - "id": "cerebras-llama-4-scout-17b-16e-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "llama-4-maverick-17b-128e-instruct-fp8": { - "id": "llama-4-maverick-17b-128e-instruct-fp8", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "mistral/mistral-nemo-12b-instruct": { - "id": "mistral/mistral-nemo-12b-instruct", - "family": "mistral-nemo", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "output": 4096 - } - }, - "google/gemma-3": { - "id": "google/gemma-3", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 125000, - "output": 4096 - } - }, - "qwen/qwen3-embedding-4b": { - "id": "Qwen/Qwen3-Embedding-4B", - "family": "qwen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 2048 - } - }, - "qwen/qwen-2.5-7b-vision-instruct": { - "id": "qwen/qwen-2.5-7b-vision-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 125000, - "output": 4096 - } - }, - "meta/llama-3.2-3b-instruct": { - "id": "meta/llama-3.2-3b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "output": 4096 - } - }, - "meta/llama-3.1-8b-instruct": { - "id": "meta/llama-3.1-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "output": 4096 - } - }, - "osmosis/osmosis-structure-0.6b": { - "id": "osmosis/osmosis-structure-0.6b", - "family": "osmosis", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4000, - "output": 2048 - } - }, - "zai-org/glm-4.7-flash": { - "id": "zai-org/GLM-4.7-Flash", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 65535, - "input": 200000 - } - }, - "zai-org/glm-4.7": { - "id": "zai-org/glm-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000, - "input": 200000 - } - }, - "zai-org/glm-4.6v": { - "id": "zai-org/GLM-4.6V", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "zai-org/glm-4.5": { - "id": "zai-org/glm-4.5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 98304, - "input": 124000 - } - }, - "zai-org/glm-5": { - "id": "zai-org/glm-5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000, - "input": 200000 - } - }, - "minimaxai/minimax-m2": { - "id": "MiniMaxAI/MiniMax-M2", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "meta-llama/llama-3.1-8b-instruct-turbo": { - "id": "meta-llama/Llama-3.1-8B-Instruct-Turbo", - "family": "llama", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "meta-llama/llama-3.1-70b-instruct-turbo": { - "id": "meta-llama/Llama-3.1-70B-Instruct-Turbo", - "family": "llama", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "meta-llama/llama-4-scout-17b-16e-instruct": { - "id": "meta-llama/Llama-4-Scout-17B-16E-Instruct", - "family": "llama", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 64000 - }, - "temperature": true - }, - "meta-llama/llama-3.1-70b-instruct": { - "id": "meta-llama/llama-3.1-70b-instruct", - "family": "llama", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - }, - "temperature": true - }, - "meta-llama/llama-3.1-8b-instruct": { - "id": "meta-llama/llama-3.1-8b-instruct", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384, - "input": 131072 - }, - "temperature": true - }, - "meta-llama/llama-3.3-70b-instruct-turbo": { - "id": "meta-llama/Llama-3.3-70B-Instruct-Turbo", - "family": "llama", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - }, - "temperature": true - }, - "qwen/qwen3-coder-480b-a35b-instruct-turbo": { - "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 66536 - } - }, - "anthropic/claude-3-7-sonnet-latest": { - "id": "anthropic/claude-3-7-sonnet-latest", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic/claude-4-opus": { - "id": "anthropic/claude-4-opus", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "perplexity/sonar": { - "id": "perplexity/sonar", - "family": "sonar", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 127072, - "output": 25415 - } - }, - "anthropic/claude-opus-4-6": { - "id": "anthropic/claude-opus-4-6", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "anthropic/claude-sonnet-4-6": { - "id": "anthropic/claude-sonnet-4-6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "anthropic/claude-haiku-4-5": { - "id": "anthropic/claude-haiku-4-5", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 62000 - } - }, - "anthropic/claude-opus-4-5": { - "id": "anthropic/claude-opus-4-5", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic/claude-sonnet-4-5": { - "id": "anthropic/claude-sonnet-4-5", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "xai/grok-4-1-fast-non-reasoning": { - "id": "xai/grok-4-1-fast-non-reasoning", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 30000 - } - }, - "mimo-v2-omni": { - "id": "mimo-v2-omni", - "family": "mimo", + "gemini-2.5-flash-lite-preview-09-2025": { + "id": "gemini-2.5-flash-lite-preview-09-2025", "reasoning": true, "temperature": true, "toolCall": true, @@ -5081,1150 +160,11 @@ ] }, "limit": { - "context": 256000, - "output": 128000 - } - }, - "mimo-v2-flash": { - "id": "mimo-v2-flash", - "family": "mimo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] + "context": 1048576, + "output": 65536, + "input": 1048756 }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "mimo-v2-pro": { - "id": "mimo-v2-pro", - "family": "mimo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "hf:minimaxai/minimax-m2.5": { - "id": "hf:MiniMaxAI/MiniMax-M2.5", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 191488, - "output": 65536 - } - }, - "hf:minimaxai/minimax-m2": { - "id": "hf:MiniMaxAI/MiniMax-M2", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 131000 - } - }, - "hf:minimaxai/minimax-m2.1": { - "id": "hf:MiniMaxAI/MiniMax-M2.1", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "hf:deepseek-ai/deepseek-r1": { - "id": "hf:deepseek-ai/DeepSeek-R1", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "hf:deepseek-ai/deepseek-r1-0528": { - "id": "hf:deepseek-ai/DeepSeek-R1-0528", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "hf:deepseek-ai/deepseek-v3.1": { - "id": "hf:deepseek-ai/DeepSeek-V3.1", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "hf:deepseek-ai/deepseek-v3.2": { - "id": "hf:deepseek-ai/DeepSeek-V3.2", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 162816, - "input": 162816, - "output": 8000 - } - }, - "hf:deepseek-ai/deepseek-v3-0324": { - "id": "hf:deepseek-ai/DeepSeek-V3-0324", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "hf:deepseek-ai/deepseek-v3": { - "id": "hf:deepseek-ai/DeepSeek-V3", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "hf:deepseek-ai/deepseek-v3.1-terminus": { - "id": "hf:deepseek-ai/DeepSeek-V3.1-Terminus", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "hf:moonshotai/kimi-k2-instruct-0905": { - "id": "hf:moonshotai/Kimi-K2-Instruct-0905", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "hf:moonshotai/kimi-k2.5": { - "id": "hf:moonshotai/Kimi-K2.5", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "hf:moonshotai/kimi-k2-thinking": { - "id": "hf:moonshotai/Kimi-K2-Thinking", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "hf:openai/gpt-oss-120b": { - "id": "hf:openai/gpt-oss-120b", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "hf:nvidia/kimi-k2.5-nvfp4": { - "id": "hf:nvidia/Kimi-K2.5-NVFP4", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "hf:meta-llama/llama-4-scout-17b-16e-instruct": { - "id": "hf:meta-llama/Llama-4-Scout-17B-16E-Instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 328000, - "output": 4096 - } - }, - "hf:meta-llama/llama-3.1-405b-instruct": { - "id": "hf:meta-llama/Llama-3.1-405B-Instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "hf:meta-llama/llama-3.1-70b-instruct": { - "id": "hf:meta-llama/Llama-3.1-70B-Instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "hf:meta-llama/llama-3.1-8b-instruct": { - "id": "hf:meta-llama/Llama-3.1-8B-Instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "hf:meta-llama/llama-3.3-70b-instruct": { - "id": "hf:meta-llama/Llama-3.3-70B-Instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "hf:meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { - "id": "hf:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 524000, - "output": 4096 - } - }, - "hf:zai-org/glm-4.7-flash": { - "id": "hf:zai-org/GLM-4.7-Flash", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 65536 - } - }, - "hf:zai-org/glm-4.6": { - "id": "hf:zai-org/GLM-4.6", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "hf:zai-org/glm-4.7": { - "id": "hf:zai-org/GLM-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "hf:qwen/qwen3-235b-a22b-thinking-2507": { - "id": "hf:Qwen/Qwen3-235B-A22B-Thinking-2507", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "hf:qwen/qwen2.5-coder-32b-instruct": { - "id": "hf:Qwen/Qwen2.5-Coder-32B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "hf:qwen/qwen3-coder-480b-a35b-instruct": { - "id": "hf:Qwen/Qwen3-Coder-480B-A35B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "hf:qwen/qwen3-235b-a22b-instruct-2507": { - "id": "hf:Qwen/Qwen3-235B-A22B-Instruct-2507", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "zai-org/glm-4.7-fp8": { - "id": "zai-org/GLM-4.7-FP8", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "input": 124000, - "output": 65535 - } - }, - "zai-org/glm-4.5-air": { - "id": "zai-org/GLM-4.5-Air", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 124000, - "output": 131072 - }, - "family": "glm" - }, - "nvidia/llama-3_1-nemotron-ultra-253b-v1": { - "id": "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 120000, - "output": 4096 - } - }, - "nvidia/nemotron-nano-v2-12b": { - "id": "nvidia/Nemotron-Nano-V2-12b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 30000, - "output": 4096 - } - }, - "nvidia/nvidia-nemotron-3-nano-30b-a3b": { - "id": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 30000, - "output": 4096 - } - }, - "nousresearch/hermes-4-405b": { - "id": "nousresearch/hermes-4-405b", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 120000, - "output": 26215 - }, - "family": "hermes" - }, - "nousresearch/hermes-4-70b": { - "id": "NousResearch/Hermes-4-70B", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 120000, - "output": 131072 - }, - "family": "nousresearch" - }, - "baai/bge-en-icl": { - "id": "BAAI/bge-en-icl", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 0 - } - }, - "baai/bge-multilingual-gemma2": { - "id": "BAAI/bge-multilingual-gemma2", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 8192, - "output": 0 - } - }, - "primeintellect/intellect-3": { - "id": "PrimeIntellect/INTELLECT-3", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 120000, - "output": 8192 - } - }, - "deepseek-ai/deepseek-v3-0324-fast": { - "id": "deepseek-ai/DeepSeek-V3-0324-fast", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 120000, - "output": 8192 - } - }, - "deepseek-ai/deepseek-v3-0324": { - "id": "deepseek-ai/DeepSeek-V3-0324", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "input": 120000, - "output": 163840 - }, - "family": "deepseek" - }, - "deepseek-ai/deepseek-r1-0528-fast": { - "id": "deepseek-ai/DeepSeek-R1-0528-fast", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "intfloat/e5-mistral-7b-instruct": { - "id": "intfloat/e5-mistral-7b-instruct", - "family": "mistral", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "input": 32768, - "output": 4096 - } - }, - "moonshotai/kimi-k2.5-fast": { - "id": "moonshotai/Kimi-K2.5-fast", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 8192 - } - }, - "google/gemma-3-27b-it-fast": { - "id": "google/gemma-3-27b-it-fast", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 110000, - "input": 100000, - "output": 8192 - } - }, - "google/gemma-2-9b-it-fast": { - "id": "google/gemma-2-9b-it-fast", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 8000, - "output": 4096 - } - }, - "meta-llama/meta-llama-3.1-8b-instruct": { - "id": "meta-llama/Meta-Llama-3.1-8B-Instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 33000, - "input": 120000, - "output": 4000 - }, - "family": "llama" - }, - "meta-llama/llama-guard-3-8b": { - "id": "meta-llama/llama-guard-3-8b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 8000, - "output": 26215 - } - }, - "meta-llama/llama-3.3-70b-instruct-fast": { - "id": "meta-llama/Llama-3.3-70B-Instruct-fast", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 120000, - "output": 8192 - } - }, - "meta-llama/meta-llama-3.1-8b-instruct-fast": { - "id": "meta-llama/Meta-Llama-3.1-8B-Instruct-fast", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 120000, - "output": 4096 - } - }, - "qwen/qwen3-32b": { - "id": "Qwen/Qwen3-32B", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "input": 120000, - "output": 40960 - }, - "family": "qwen" - }, - "qwen/qwen2.5-vl-72b-instruct": { - "id": "qwen/qwen2.5-vl-72b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 120000, - "output": 32768 - }, - "family": "qwen" - }, - "qwen/qwen3-32b-fast": { - "id": "Qwen/Qwen3-32B-fast", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 120000, - "output": 8192 - } - }, - "qwen/qwen2.5-coder-7b-fast": { - "id": "Qwen/Qwen2.5-Coder-7B-fast", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 120000, - "output": 8192 - } - }, - "black-forest-labs/flux-dev": { - "id": "black-forest-labs/flux-dev", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 77, - "input": 77, - "output": 0 - } - }, - "black-forest-labs/flux-schnell": { - "id": "black-forest-labs/flux-schnell", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 77, - "input": 77, - "output": 0 - } - }, - "claude-4.5-haiku": { - "id": "claude-4.5-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - }, - "family": "claude-haiku" - }, - "claude-3.5-sonnet": { - "id": "claude-3.5-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8200 - } + "family": "gemini-flash-lite" }, "qwen3-235b-a22b-instruct-2507": { "id": "qwen3-235b-a22b-instruct-2507", @@ -6240,193 +180,14 @@ ] }, "limit": { - "context": 128000, - "output": 16384 - }, - "family": "qwen" - }, - "claude-3.7-sonnet": { - "id": "claude-3.7-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - }, - "family": "claude-sonnet" - }, - "qwen3-next-80b-a3b-thinking": { - "id": "qwen3-next-80b-a3b-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - }, - "family": "qwen" - }, - "claude-4.0-sonnet": { - "id": "claude-4.0-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "qwen-vl-max-2025-01-25": { - "id": "qwen-vl-max-2025-01-25", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "doubao-seed-1.6-thinking": { - "id": "doubao-seed-1.6-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "qwen3-coder-480b-a35b-instruct": { - "id": "qwen3-coder-480b-a35b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - }, - "family": "qwen" - }, - "claude-4.5-sonnet": { - "id": "claude-4.5-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - }, - "family": "claude-sonnet" - }, - "qwen2.5-vl-7b-instruct": { - "id": "qwen2.5-vl-7b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, + "context": 262000, "output": 8192 - } - }, - "doubao-seed-2.0-pro": { - "id": "doubao-seed-2.0-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 256000, - "output": 128000 - } + "family": "qwen" }, - "gemini-2.5-flash": { - "id": "gemini-2.5-flash", - "reasoning": true, + "mistral-large-2512": { + "id": "mistral-large-2512", + "reasoning": false, "temperature": true, "toolCall": false, "modalities": { @@ -6439,14 +200,13 @@ ] }, "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 + "context": 262144, + "output": 16384 }, - "family": "gemini-flash" + "family": "mistral" }, - "deepseek-v3.1": { - "id": "deepseek-v3.1", + "glm-4.7": { + "id": "glm-4.7", "reasoning": true, "temperature": true, "toolCall": true, @@ -6458,54 +218,91 @@ "text" ] }, + "limit": { + "context": 204800, + "output": 131072 + }, + "family": "glm" + }, + "doubao-seed-1-8-251215": { + "id": "doubao-seed-1-8-251215", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + } + }, + "chatgpt-4o-latest": { + "id": "chatgpt-4o-latest", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "deepseek-chat": { + "id": "deepseek-chat", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, "limit": { "context": 131072, - "output": 131072 - }, - "family": "deepseek" + "output": 8192, + "input": 128000 + } }, - "doubao-seed-1.6": { - "id": "doubao-seed-1.6", + "deepseek-v3.2-thinking": { + "id": "deepseek-v3.2-thinking", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image", - "video" + "text" ], "output": [ "text" ] }, "limit": { - "context": 256000, - "output": 32000 + "context": 128000, + "output": 128000 } }, - "doubao-seed-2.0-mini": { - "id": "doubao-seed-2.0-mini", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "claude-4.0-opus": { - "id": "claude-4.0-opus", + "gpt-5-thinking": { + "id": "gpt-5-thinking", "reasoning": true, "temperature": true, "toolCall": true, @@ -6519,32 +316,12 @@ ] }, "limit": { - "context": 200000, - "output": 32000 + "context": 400000, + "output": 128000 } }, - "qwen-turbo": { - "id": "qwen-turbo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 16384, - "input": 1000000 - }, - "family": "qwen" - }, - "gemini-3.0-pro-preview": { - "id": "gemini-3.0-pro-preview", + "gemini-3-flash-preview": { + "id": "gemini-3-flash-preview", "reasoning": true, "temperature": true, "toolCall": true, @@ -6553,8 +330,72 @@ "text", "image", "video", - "pdf", - "audio" + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 128000 + }, + "family": "gemini-flash" + }, + "qwen-plus": { + "id": "qwen-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000, + "input": 995904 + } + }, + "gpt-5-mini": { + "id": "gpt-5-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 272000 + }, + "family": "gpt-mini" + }, + "gemini-3-pro-preview": { + "id": "gemini-3-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" ], "output": [ "text" @@ -6562,50 +403,157 @@ }, "limit": { "context": 1000000, + "output": 65000, + "input": 128000 + }, + "family": "gemini-pro" + }, + "qwen3-max-2025-09-23": { + "id": "qwen3-max-2025-09-23", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 258048, + "output": 65536 + } + }, + "claude-sonnet-4-5-20250929": { + "id": "claude-sonnet-4-5-20250929", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 1000000 + }, + "family": "claude-sonnet" + }, + "qwen-flash": { + "id": "qwen-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32000 + }, + "family": "qwen" + }, + "gemini-2.5-pro": { + "id": "gemini-2.5-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 128000 + } + }, + "grok-4-1-fast-non-reasoning": { + "id": "grok-4-1-fast-non-reasoning", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + }, + "family": "grok" + }, + "claude-opus-4-5-20251101-thinking": { + "id": "claude-opus-4-5-20251101-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, "output": 64000 } }, - "deepseek-r1-0528": { - "id": "deepseek-r1-0528", + "gpt-5.2": { + "id": "gpt-5.2", "reasoning": true, "temperature": true, "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - }, - "family": "deepseek-thinking" - }, - "doubao-1.5-vision-pro": { - "id": "doubao-1.5-vision-pro", - "reasoning": false, - "temperature": true, - "toolCall": false, "modalities": { "input": [ "text", - "image", - "video" + "image" ], "output": [ "text" ] }, "limit": { - "context": 128000, - "output": 16000 - } + "context": 400000, + "output": 128000, + "input": 272000 + }, + "family": "gpt" }, - "gemini-3.0-pro-image-preview": { - "id": "gemini-3.0-pro-image-preview", + "gemini-3-pro-image-preview": { + "id": "gemini-3-pro-image-preview", "reasoning": false, "temperature": true, "toolCall": false, @@ -6620,54 +568,15 @@ ] }, "limit": { - "context": 32768, - "output": 8192 - } - }, - "qwen3.5-397b-a17b": { - "id": "qwen3.5-397b-a17b", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - }, - "family": "qwen" - }, - "gemini-2.5-flash-lite": { - "id": "gemini-2.5-flash-lite", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, + "context": 65536, + "output": 32768, "input": 1048756 }, - "family": "gemini-flash-lite" + "family": "gemini" }, - "claude-3.5-haiku": { - "id": "claude-3.5-haiku", + "qwen-max-latest": { + "id": "qwen-max-latest", + "family": "qwen", "reasoning": false, "temperature": true, "toolCall": true, @@ -6680,184 +589,11 @@ "text" ] }, - "limit": { - "context": 200000, - "output": 8192 - }, - "family": "claude-haiku" - }, - "gpt-oss-120b": { - "id": "gpt-oss-120b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - }, - "family": "gpt-oss" - }, - "deepseek-v3-0324": { - "id": "deepseek-v3-0324", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000, - "input": 128000 - }, - "family": "deepseek" - }, - "doubao-1.5-pro-32k": { - "id": "doubao-1.5-pro-32k", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 8192, - "input": 32000 - } - }, - "qwen3-30b-a3b-instruct-2507": { - "id": "qwen3-30b-a3b-instruct-2507", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32768, - "input": 256000 - } - }, - "qwen2.5-vl-72b-instruct": { - "id": "qwen2.5-vl-72b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "qwen3-235b-a22b": { - "id": "qwen3-235b-a22b", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, "limit": { "context": 131072, - "output": 16384 - }, - "family": "qwen" - }, - "doubao-seed-2.0-lite": { - "id": "doubao-seed-2.0-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, "output": 32000 } }, - "claude-4.1-opus": { - "id": "claude-4.1-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "doubao-1.5-thinking-pro": { - "id": "doubao-1.5-thinking-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16000 - } - }, "gemini-2.5-flash-image": { "id": "gemini-2.5-flash-image", "reasoning": true, @@ -6879,8 +615,153 @@ }, "family": "gemini-flash" }, - "minimax-m1": { - "id": "MiniMax-M1", + "glm-4.5": { + "id": "glm-4.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + }, + "family": "glm" + }, + "gemini-2.5-flash": { + "id": "gemini-2.5-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 1048756 + } + }, + "gpt-5.2-chat-latest": { + "id": "gpt-5.2-chat-latest", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16400 + }, + "family": "gpt" + }, + "doubao-seed-1-6-vision-250815": { + "id": "doubao-seed-1-6-vision-250815", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "minimax-m2.1": { + "id": "MiniMax-M2.1", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + }, + "family": "minimax" + }, + "gpt-5.1": { + "id": "gpt-5.1", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "image", + "audio" + ] + }, + "limit": { + "context": 272000, + "output": 128000, + "input": 272000 + }, + "family": "gpt" + }, + "kimi-k2-thinking-turbo": { + "id": "kimi-k2-thinking-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + }, + "family": "kimi-thinking" + }, + "deepseek-reasoner": { + "id": "deepseek-reasoner", + "family": "deepseek-thinking", "reasoning": false, "temperature": true, "toolCall": false, @@ -6892,93 +773,34 @@ "text" ] }, - "limit": { - "context": 1000000, - "output": 131072, - "input": 1000000 - }, - "family": "minimax" - }, - "doubao-seed-1.6-flash": { - "id": "doubao-seed-1.6-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "qwen3-vl-30b-a3b-thinking": { - "id": "qwen3-vl-30b-a3b-thinking", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, "limit": { "context": 128000, - "output": 32000 + "output": 64000, + "input": 64000 } }, - "doubao-seed-2.0-code": { - "id": "doubao-seed-2.0-code", + "grok-4-fast-reasoning": { + "id": "grok-4-fast-reasoning", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image", - "video" + "image" ], "output": [ "text" ] }, "limit": { - "context": 256000, - "output": 128000 - } - }, - "qwen3-30b-a3b-thinking-2507": { - "id": "qwen3-30b-a3b-thinking-2507", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] + "context": 2000000, + "output": 30000 }, - "limit": { - "context": 126000, - "output": 32000 - } + "family": "grok" }, - "claude-4.5-opus": { - "id": "claude-4.5-opus", + "claude-opus-4-1-20250805-thinking": { + "id": "claude-opus-4-1-20250805-thinking", "reasoning": true, "temperature": true, "toolCall": true, @@ -6993,74 +815,12 @@ }, "limit": { "context": 200000, - "output": 64000 - }, - "family": "claude-opus" - }, - "gemini-2.0-flash-lite": { - "id": "gemini-2.0-flash-lite", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 8192, - "input": 1000000 - }, - "family": "gemini-flash-lite" - }, - "qwen3-next-80b-a3b-instruct": { - "id": "qwen3-next-80b-a3b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - }, - "family": "qwen" - }, - "gemini-3.0-flash-preview": { - "id": "gemini-3.0-flash-preview", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 + "output": 32000 } }, "qwen3-30b-a3b": { "id": "qwen3-30b-a3b", + "family": "qwen", "reasoning": false, "temperature": true, "toolCall": true, @@ -7076,11 +836,31 @@ "limit": { "context": 41000, "output": 41000 - }, - "family": "qwen" + } }, - "gpt-oss-20b": { - "id": "gpt-oss-20b", + "glm-4.5v": { + "id": "glm-4.5v", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16384 + }, + "family": "glm" + }, + "glm-4.6": { + "id": "glm-4.6", "reasoning": true, "temperature": true, "toolCall": true, @@ -7093,55 +873,14 @@ ] }, "limit": { - "context": 131072, + "context": 204800, "output": 131072 }, - "family": "gpt-oss" + "family": "glm" }, - "kling-v2-6": { - "id": "kling-v2-6", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 99999999, - "output": 99999999 - } - }, - "gemini-2.5-pro": { - "id": "gemini-2.5-pro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65535, - "input": 1048756 - }, - "family": "gemini-pro" - }, - "gemini-2.0-flash": { - "id": "gemini-2.0-flash", - "reasoning": false, + "gemini-2.5-flash-preview-09-2025": { + "id": "gemini-2.5-flash-preview-09-2025", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -7158,196 +897,13 @@ }, "limit": { "context": 1048576, - "output": 8192 + "output": 65536, + "input": 1048756 }, "family": "gemini-flash" }, - "qwen-max-2025-01-25": { - "id": "qwen-max-2025-01-25", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "deepseek/deepseek-v3.2-exp-thinking": { - "id": "deepseek/deepseek-v3.2-exp-thinking", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "deepseek/deepseek-v3.1-terminus": { - "id": "deepseek/deepseek-v3.1-terminus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 32768 - }, - "family": "deepseek" - }, - "deepseek/deepseek-v3.2-251201": { - "id": "deepseek/deepseek-v3.2-251201", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "deepseek/deepseek-math-v2": { - "id": "deepseek/deepseek-math-v2", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 160000, - "output": 160000 - } - }, - "deepseek/deepseek-v3.1-terminus-thinking": { - "id": "deepseek/deepseek-v3.1-terminus-thinking", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "z-ai/autoglm-phone-9b": { - "id": "z-ai/autoglm-phone-9b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 12800, - "output": 4096 - } - }, - "stepfun-ai/gelab-zero-4b-preview": { - "id": "stepfun-ai/gelab-zero-4b-preview", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096 - } - }, - "meituan/longcat-flash-lite": { - "id": "meituan/longcat-flash-lite", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 320000 - } - }, - "meituan/longcat-flash-chat": { - "id": "meituan/longcat-flash-chat", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - }, - "family": "longcat" - }, - "x-ai/grok-4-fast-reasoning": { - "id": "x-ai/grok-4-fast-reasoning", + "glm-4.6v": { + "id": "glm-4.6v", "reasoning": true, "temperature": true, "toolCall": true, @@ -7355,7 +911,6 @@ "input": [ "text", "image", - "audio", "video" ], "output": [ @@ -7363,33 +918,13 @@ ] }, "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "x-ai/grok-4.1-fast-reasoning": { - "id": "x-ai/grok-4.1-fast-reasoning", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] + "context": 128000, + "output": 32768 }, - "limit": { - "context": 2000000, - "output": 131072, - "input": 2000000 - }, - "family": "grok" + "family": "glm" }, - "x-ai/grok-4-fast-non-reasoning": { - "id": "x-ai/grok-4-fast-non-reasoning", + "claude-opus-4-1-20250805": { + "id": "claude-opus-4-1-20250805", "reasoning": true, "temperature": true, "toolCall": true, @@ -7397,3051 +932,21 @@ "input": [ "text", "image", - "audio", - "video" + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "minimax/minimax-m2.5-highspeed": { - "id": "minimax/minimax-m2.5-highspeed", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - }, - "family": "minimax" - }, - "qwen3-coder:480b": { - "id": "qwen3-coder:480b", - "family": "qwen", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "nemotron-3-nano:30b": { - "id": "nemotron-3-nano:30b", - "family": "nemotron", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 131072 - } - }, - "ministral-3:8b": { - "id": "ministral-3:8b", - "family": "ministral", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 128000 - } - }, - "gpt-oss:120b": { - "id": "gpt-oss:120b", - "family": "gpt-oss", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "devstral-2:123b": { - "id": "devstral-2:123b", - "family": "devstral", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen3-vl:235b-instruct": { - "id": "qwen3-vl:235b-instruct", - "family": "qwen", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "gemini-3-flash-preview": { - "id": "gemini-3-flash-preview", - "family": "gemini-flash", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536, - "input": 128000 - }, - "temperature": true - }, - "minimax-m2.1": { - "id": "minimax-m2.1", - "family": "minimax", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196000, - "output": 196000 - }, - "temperature": true - }, - "ministral-3:14b": { - "id": "ministral-3:14b", - "family": "ministral", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 128000 - } - }, - "qwen3-next:80b": { - "id": "qwen3-next:80b", - "family": "qwen", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "kimi-k2:1t": { - "id": "kimi-k2:1t", - "family": "kimi", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "gemma3:12b": { - "id": "gemma3:12b", - "family": "gemma", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "minimax-m2.7": { - "id": "MiniMax-M2.7", - "family": "minimax", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - }, - "temperature": true - }, - "gpt-oss:20b": { - "id": "gpt-oss:20b", - "family": "gpt-oss", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "kimi-k2-thinking": { - "id": "kimi-k2-thinking", - "family": "kimi", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 16384 - }, - "temperature": true - }, - "ministral-3:3b": { - "id": "ministral-3:3b", - "family": "ministral", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 128000 - } - }, - "qwen3.5:397b": { - "id": "qwen3.5:397b", - "family": "qwen", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 81920 - } - }, - "gemma3:27b": { - "id": "gemma3:27b", - "family": "gemma", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "minimax-m2": { - "id": "minimax-m2", - "family": "minimax", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 400000, + "context": 200000, + "output": 32000, "input": 200000 }, - "temperature": true + "family": "claude-opus" }, - "devstral-small-2:24b": { - "id": "devstral-small-2:24b", - "family": "devstral", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "nemotron-3-super": { - "id": "nemotron-3-super", - "family": "nemotron", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "cogito-2.1:671b": { - "id": "cogito-2.1:671b", - "family": "cogito", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 32000 - } - }, - "gemma3:4b": { - "id": "gemma3:4b", - "family": "gemma", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "deepseek-v3.1:671b": { - "id": "deepseek-v3.1:671b", - "family": "deepseek", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "mistral-large-3:675b": { - "id": "mistral-large-3:675b", - "family": "mistral-large", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "rnj-1:8b": { - "id": "rnj-1:8b", - "family": "rnj", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 4096 - } - }, - "qwen3-vl:235b": { - "id": "qwen3-vl:235b", - "family": "qwen", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "voxtral-small-24b-2507": { - "id": "voxtral-small-24b-2507", - "family": "voxtral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 16384 - } - }, - "mistral-small-3.2-24b-instruct-2506": { - "id": "mistral-small-3.2-24b-instruct-2506", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "qwen3-embedding-8b": { - "id": "qwen3-embedding-8b", - "family": "qwen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 4096 - } - }, - "bge-multilingual-gemma2": { - "id": "bge-multilingual-gemma2", - "family": "gemma", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8191, - "output": 3072 - } - }, - "deepseek-r1-distill-llama-70b": { - "id": "deepseek-r1-distill-llama-70b", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384 - } - }, - "qwen3-coder-30b-a3b-instruct": { - "id": "qwen3-coder-30b-a3b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536, - "input": 128000 - } - }, - "whisper-large-v3": { - "id": "whisper-large-v3", - "family": "whisper", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 4096 - } - }, - "llama-3.1-8b-instruct": { - "id": "llama-3.1-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "devstral-2-123b-instruct-2512": { - "id": "devstral-2-123b-instruct-2512", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 16384 - } - }, - "pixtral-12b-2409": { - "id": "pixtral-12b-2409", - "family": "pixtral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistral-nemo-instruct-2407": { - "id": "mistral-nemo-instruct-2407", - "family": "mistral-nemo", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 65536 - } - }, - "gemma-3-27b-it": { - "id": "Gemma-3-27B-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384, - "input": 32768 - } - }, - "workers-ai/@cf/zai-org/glm-4.7-flash": { - "id": "workers-ai/@cf/zai-org/glm-4.7-flash", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "workers-ai/@cf/nvidia/nemotron-3-120b-a12b": { - "id": "workers-ai/@cf/nvidia/nemotron-3-120b-a12b", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "workers-ai/@cf/ibm-granite/granite-4.0-h-micro": { - "id": "workers-ai/@cf/ibm-granite/granite-4.0-h-micro", - "family": "granite", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/baai/bge-small-en-v1.5": { - "id": "workers-ai/@cf/baai/bge-small-en-v1.5", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/baai/bge-large-en-v1.5": { - "id": "workers-ai/@cf/baai/bge-large-en-v1.5", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/baai/bge-reranker-base": { - "id": "workers-ai/@cf/baai/bge-reranker-base", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/baai/bge-m3": { - "id": "workers-ai/@cf/baai/bge-m3", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/baai/bge-base-en-v1.5": { - "id": "workers-ai/@cf/baai/bge-base-en-v1.5", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/pfnet/plamo-embedding-1b": { - "id": "workers-ai/@cf/pfnet/plamo-embedding-1b", - "family": "plamo", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b": { - "id": "workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", - "family": "deepseek-thinking", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/facebook/bart-large-cnn": { - "id": "workers-ai/@cf/facebook/bart-large-cnn", - "family": "bart", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1": { - "id": "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/myshell-ai/melotts": { - "id": "workers-ai/@cf/myshell-ai/melotts", - "family": "melotts", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/pipecat-ai/smart-turn-v2": { - "id": "workers-ai/@cf/pipecat-ai/smart-turn-v2", - "family": "smart-turn", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/moonshotai/kimi-k2.5": { - "id": "workers-ai/@cf/moonshotai/kimi-k2.5", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "workers-ai/@cf/google/gemma-3-12b-it": { - "id": "workers-ai/@cf/google/gemma-3-12b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/qwen/qwq-32b": { - "id": "workers-ai/@cf/qwen/qwq-32b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8": { - "id": "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct": { - "id": "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/qwen/qwen3-embedding-0.6b": { - "id": "workers-ai/@cf/qwen/qwen3-embedding-0.6b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8": { - "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3-8b-instruct-awq": { - "id": "workers-ai/@cf/meta/llama-3-8b-instruct-awq", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3.1-8b-instruct-awq": { - "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct-awq", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct": { - "id": "workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3.2-11b-vision-instruct": { - "id": "workers-ai/@cf/meta/llama-3.2-11b-vision-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3.2-3b-instruct": { - "id": "workers-ai/@cf/meta/llama-3.2-3b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-guard-3-8b": { - "id": "workers-ai/@cf/meta/llama-guard-3-8b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3.2-1b-instruct": { - "id": "workers-ai/@cf/meta/llama-3.2-1b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast": { - "id": "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3.1-8b-instruct": { - "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/m2m100-1.2b": { - "id": "workers-ai/@cf/meta/m2m100-1.2b", - "family": "m2m", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-2-7b-chat-fp16": { - "id": "workers-ai/@cf/meta/llama-2-7b-chat-fp16", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/meta/llama-3-8b-instruct": { - "id": "workers-ai/@cf/meta/llama-3-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct": { - "id": "workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/deepgram/aura-2-es": { - "id": "workers-ai/@cf/deepgram/aura-2-es", - "family": "aura", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/deepgram/nova-3": { - "id": "workers-ai/@cf/deepgram/nova-3", - "family": "nova", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/deepgram/aura-2-en": { - "id": "workers-ai/@cf/deepgram/aura-2-en", - "family": "aura", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/openai/gpt-oss-120b": { - "id": "workers-ai/@cf/openai/gpt-oss-120b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/openai/gpt-oss-20b": { - "id": "workers-ai/@cf/openai/gpt-oss-20b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1b": { - "id": "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1B", - "family": "indictrans", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/huggingface/distilbert-sst-2-int8": { - "id": "workers-ai/@cf/huggingface/distilbert-sst-2-int8", - "family": "distilbert", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it": { - "id": "workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "openai/gpt-4o-mini": { - "id": "openai/gpt-4o-mini", - "family": "gpt-mini", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - } - }, - "openai/o1": { - "id": "openai/o1", - "family": "o", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/o3": { - "id": "openai/o3", - "family": "o", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/gpt-3.5-turbo": { - "id": "openai/gpt-3.5-turbo", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16385, - "output": 4096, - "input": 16385 - } - }, - "openai/o3-pro": { - "id": "openai/o3-pro", - "family": "o-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 100000 - } - }, - "openai/gpt-4-turbo": { - "id": "openai/gpt-4-turbo", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096, - "input": 128000 - } - }, - "openai/o4-mini": { - "id": "openai/o4-mini", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/o3-mini": { - "id": "openai/o3-mini", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/gpt-4": { - "id": "openai/gpt-4", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8191, - "output": 4096 - } - }, - "openai/gpt-4o": { - "id": "openai/gpt-4o", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - } - }, - "anthropic/claude-opus-4-1": { - "id": "anthropic/claude-opus-4-1", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "anthropic/claude-3-sonnet": { - "id": "anthropic/claude-3-sonnet", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "anthropic/claude-3-5-haiku": { - "id": "anthropic/claude-3-5-haiku", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "anthropic/claude-3-haiku": { - "id": "anthropic/claude-3-haiku", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "anthropic/claude-3-opus": { - "id": "anthropic/claude-3-opus", - "family": "claude-opus", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "solar-pro2": { - "id": "solar-pro2", - "family": "solar-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 8192 - } - }, - "solar-mini": { - "id": "solar-mini", - "family": "solar-mini", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 4096 - } - }, - "solar-pro3": { - "id": "solar-pro3", - "family": "solar-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "mercury-2": { - "id": "mercury-2", - "family": "mercury", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 50000 - } - }, - "mercury": { - "id": "mercury", - "family": "mercury", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "mercury-edit": { - "id": "mercury-edit", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "mercury-coder": { - "id": "mercury-coder", - "family": "mercury", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "zai-org/glm-4.5-fp8": { - "id": "zai-org/GLM-4.5-FP8", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "qwen/qwen3-coder-480b-a35b-instruct-fp8": { - "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "minimax-m2.7-highspeed": { - "id": "MiniMax-M2.7-highspeed", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "minimax-m2.5-highspeed": { - "id": "MiniMax-M2.5-highspeed", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "zai-org/autoglm-phone-9b-multilingual": { - "id": "zai-org/autoglm-phone-9b-multilingual", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 65536 - } - }, - "zai-org/glm-4.5v": { - "id": "zai-org/glm-4.5v", - "family": "glmv", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 16384 - } - }, - "microsoft/wizardlm-2-8x22b": { - "id": "microsoft/wizardlm-2-8x22b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 8192, - "input": 65536 - }, - "family": "gpt" - }, - "minimaxai/minimax-m1-80k": { - "id": "MiniMaxAI/MiniMax-M1-80k", - "family": "minimax", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 131072, - "input": 1000000 - } - }, - "skywork/r1v4-lite": { - "id": "skywork/r1v4-lite", - "family": "skywork", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "gryphe/mythomax-l2-13b": { - "id": "Gryphe/MythoMax-L2-13b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4000, - "output": 4096, - "input": 4000 - }, - "family": "llama" - }, - "paddlepaddle/paddleocr-vl": { - "id": "PaddlePaddle/PaddleOCR-VL", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "baichuan/baichuan-m2-32b": { - "id": "baichuan/baichuan-m2-32b", - "family": "baichuan", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "kwaipilot/kat-coder-pro": { - "id": "kwaipilot/kat-coder-pro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 128000 - } - }, - "kwaipilot/kat-coder": { - "id": "kwaipilot/kat-coder", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "deepseek/deepseek-v3-turbo": { - "id": "deepseek/deepseek-v3-turbo", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 16000 - } - }, - "deepseek/deepseek-prover-v2-671b": { - "id": "deepseek/deepseek-prover-v2-671b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 160000, - "output": 16384, - "input": 160000 - }, - "family": "deepseek" - }, - "deepseek/deepseek-r1-turbo": { - "id": "deepseek/deepseek-r1-turbo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 16000 - } - }, - "deepseek/deepseek-ocr-2": { - "id": "deepseek/deepseek-ocr-2", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "deepseek/deepseek-v3.1": { - "id": "deepseek/deepseek-v3.1", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 32768 - } - }, - "deepseek/deepseek-r1-0528": { - "id": "deepseek/deepseek-r1-0528", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "deepseek/deepseek-r1-0528-qwen3-8b": { - "id": "deepseek/deepseek-r1-0528-qwen3-8b", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "deepseek/deepseek-r1-distill-llama-70b": { - "id": "deepseek/deepseek-r1-distill-llama-70b", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "deepseek/deepseek-v3-0324": { - "id": "deepseek/deepseek-v3-0324", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "deepseek/deepseek-ocr": { - "id": "deepseek/deepseek-ocr", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "baidu/ernie-4.5-vl-28b-a3b-thinking": { - "id": "baidu/ernie-4.5-vl-28b-a3b-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "baidu/ernie-4.5-vl-424b-a47b": { - "id": "baidu/ernie-4.5-vl-424b-a47b", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 123000, - "output": 16000 - }, - "family": "ernie" - }, - "baidu/ernie-4.5-vl-28b-a3b": { - "id": "baidu/ernie-4.5-vl-28b-a3b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384, - "input": 32768 - }, - "family": "ernie" - }, - "baidu/ernie-4.5-300b-a47b-paddle": { - "id": "baidu/ernie-4.5-300b-a47b-paddle", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 123000, - "output": 12000 - }, - "family": "ernie" - }, - "baidu/ernie-4.5-21b-a3b": { - "id": "baidu/ernie-4.5-21b-a3b", - "family": "ernie", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 120000, - "output": 8000 - } - }, - "baidu/ernie-4.5-21b-a3b-thinking": { - "id": "baidu/ernie-4.5-21b-a3b-thinking", - "family": "ernie", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "qwen/qwen3-4b-fp8": { - "id": "qwen/qwen3-4b-fp8", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 20000 - } - }, - "qwen/qwen3-32b-fp8": { - "id": "qwen/qwen3-32b-fp8", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 20000 - }, - "family": "qwen" - }, - "qwen/qwen3-30b-a3b-fp8": { - "id": "qwen/qwen3-30b-a3b-fp8", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 20000 - }, - "family": "qwen" - }, - "qwen/qwen3-coder-next": { - "id": "Qwen/Qwen3-Coder-Next", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "qwen/qwen3-vl-235b-a22b-instruct": { - "id": "Qwen/Qwen3-VL-235B-A22B-Instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - }, - "family": "qwen" - }, - "qwen/qwen-mt-plus": { - "id": "qwen/qwen-mt-plus", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 8192 - } - }, - "qwen/qwen3-omni-30b-a3b-instruct": { - "id": "Qwen/Qwen3-Omni-30B-A3B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 66000, - "output": 66000 - } - }, - "qwen/qwen-2.5-72b-instruct": { - "id": "qwen/qwen-2.5-72b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384 - } - }, - "qwen/qwen3-vl-30b-a3b-thinking": { - "id": "qwen/qwen3-vl-30b-a3b-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - }, - "family": "qwen" - }, - "qwen/qwen3-vl-235b-a22b-thinking": { - "id": "qwen/qwen3-vl-235b-a22b-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - }, - "family": "qwen" - }, - "qwen/qwen2.5-7b-instruct": { - "id": "Qwen/Qwen2.5-7B-Instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 33000, - "output": 4000 - }, - "family": "qwen" - }, - "qwen/qwen3-235b-a22b-fp8": { - "id": "qwen/qwen3-235b-a22b-fp8", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 20000 - }, - "family": "qwen" - }, - "qwen/qwen3-vl-8b-instruct": { - "id": "qwen/qwen3-vl-8b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - }, - "family": "qwen" - }, - "qwen/qwen3-8b-fp8": { - "id": "qwen/qwen3-8b-fp8", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 20000 - } - }, - "qwen/qwen3-omni-30b-a3b-thinking": { - "id": "Qwen/Qwen3-Omni-30B-A3B-Thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 66000, - "output": 66000 - }, - "family": "qwen" - }, - "meta-llama/llama-3-70b-instruct": { - "id": "meta-llama/llama-3-70b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8000 - } - }, - "meta-llama/llama-3-8b-instruct": { - "id": "meta-llama/llama-3-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 16384 - } - }, - "mistralai/mistral-nemo": { - "id": "mistralai/mistral-nemo", - "family": "mistral-nemo", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "sao10k/l3-70b-euryale-v2.1": { - "id": "sao10k/l3-70b-euryale-v2.1", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "sao10k/l31-70b-euryale-v2.2": { - "id": "sao10k/l31-70b-euryale-v2.2", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "sao10k/l3-8b-lunaris": { - "id": "sao10k/l3-8b-lunaris", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "sao10k/l3-8b-stheno-v3.2": { - "id": "Sao10K/L3-8B-Stheno-v3.2", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 8192, - "input": 16384 - }, - "family": "llama" - }, - "xiaomimimo/mimo-v2-flash": { - "id": "XiaomiMiMo/MiMo-V2-Flash", - "family": "mimo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32000 - } - }, - "nousresearch/hermes-2-pro-llama-3-8b": { - "id": "nousresearch/hermes-2-pro-llama-3-8b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "gpt-5.3-codex": { - "id": "gpt-5.3-codex", - "family": "gpt-codex", + "gpt-5.1-chat-latest": { + "id": "gpt-5.1-chat-latest", "reasoning": true, "temperature": false, "toolCall": true, @@ -10454,663 +959,15 @@ "text" ] }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "gpt-5-codex": { - "id": "gpt-5-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "gemini-3.1-pro": { - "id": "gemini-3.1-pro", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "trinity-large-preview-free": { - "id": "trinity-large-preview-free", - "family": "trinity", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "gpt-5.1-codex-max": { - "id": "gpt-5.1-codex-max", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "kimi-k2.5-free": { - "id": "kimi-k2.5-free", - "family": "kimi-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "claude-opus-4-1": { - "id": "claude-opus-4-1", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "grok-code": { - "id": "grok-code", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "nemotron-3-super-free": { - "id": "nemotron-3-super-free", - "family": "nemotron-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "claude-3-5-haiku": { - "id": "claude-3-5-haiku", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "gpt-5.2-codex": { - "id": "gpt-5.2-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "claude-opus-4-6": { - "id": "claude-opus-4-6", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000 - } - }, - "mimo-v2-flash-free": { - "id": "mimo-v2-flash-free", - "family": "mimo-flash-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "gemini-3-flash": { - "id": "gemini-3-flash", - "family": "gemini-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "claude-sonnet-4-6": { - "id": "claude-sonnet-4-6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "gpt-5.1": { - "id": "gpt-5.1", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text", - "image", - "audio" - ] - }, - "limit": { - "context": 272000, - "input": 272000, - "output": 128000 - } - }, - "gpt-5.3-codex-spark": { - "id": "gpt-5.3-codex-spark", - "family": "gpt-codex-spark", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, "limit": { "context": 128000, - "input": 100000, - "output": 32000 - } - }, - "qwen3-coder": { - "id": "qwen3-coder", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, "output": 16384 - } - }, - "gpt-5.1-codex-mini": { - "id": "gpt-5.1-codex-mini", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } + "family": "gpt-codex" }, - "gpt-5.2": { - "id": "gpt-5.2", - "family": "gpt", + "claude-haiku-4-5-20251001": { + "id": "claude-haiku-4-5-20251001", "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "mimo-v2-omni-free": { - "id": "mimo-v2-omni-free", - "family": "mimo-omni-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 64000 - } - }, - "minimax-m2.1-free": { - "id": "minimax-m2.1-free", - "family": "minimax-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "mimo-v2-pro-free": { - "id": "mimo-v2-pro-free", - "family": "mimo-pro-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 64000 - } - }, - "gpt-5": { - "id": "gpt-5", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 272000, - "input": 272000, - "output": 128000 - } - }, - "glm-5-free": { - "id": "glm-5-free", - "family": "glm-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "gpt-5.4": { - "id": "gpt-5.4", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "gpt-5.4-pro": { - "id": "gpt-5.4-pro", - "family": "gpt-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "claude-haiku-4-5": { - "id": "claude-haiku-4-5", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 200000 - } - }, - "gpt-5.1-codex": { - "id": "gpt-5.1-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text", - "image", - "audio" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "big-pickle": { - "id": "big-pickle", - "family": "big-pickle", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000 - } - }, - "minimax-m2.5-free": { - "id": "minimax-m2.5-free", - "family": "minimax-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "claude-opus-4-5": { - "id": "claude-opus-4-5", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-sonnet-4": { - "id": "claude-sonnet-4", - "family": "claude-sonnet", - "reasoning": false, "temperature": true, "toolCall": true, "modalities": { @@ -11126,12 +983,13 @@ "limit": { "context": 200000, "output": 64000, - "input": 128000 - } + "input": 200000 + }, + "family": "claude-haiku" }, - "glm-4.7-free": { - "id": "glm-4.7-free", - "family": "glm-free", + "minimax-m1": { + "id": "MiniMax-M1", + "family": "minimax", "reasoning": true, "temperature": true, "toolCall": true, @@ -11143,813 +1001,36 @@ "text" ] }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "gemini-3-pro": { - "id": "gemini-3-pro", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "claude-sonnet-4-5": { - "id": "claude-sonnet-4-5", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "gpt-5.4-nano": { - "id": "gpt-5.4-nano", - "family": "gpt-nano", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "gpt-5-nano": { - "id": "gpt-5-nano", - "family": "gpt-nano", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 272000, - "input": 272000, - "output": 128000 - } - }, - "gpt-5.4-mini": { - "id": "gpt-5.4-mini", - "family": "gpt-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "stabilityai/stablediffusionxl": { - "id": "stabilityai/stablediffusionxl", - "family": "stable-diffusion", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 200, - "output": 0 - } - }, - "ideogramai/ideogram-v2": { - "id": "ideogramai/ideogram-v2", - "family": "ideogram", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 150, - "output": 0 - } - }, - "ideogramai/ideogram": { - "id": "ideogramai/ideogram", - "family": "ideogram", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 150, - "output": 0 - } - }, - "ideogramai/ideogram-v2a-turbo": { - "id": "ideogramai/ideogram-v2a-turbo", - "family": "ideogram", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 150, - "output": 0 - } - }, - "ideogramai/ideogram-v2a": { - "id": "ideogramai/ideogram-v2a", - "family": "ideogram", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 150, - "output": 0 - } - }, - "novita/glm-4.7-flash": { - "id": "novita/glm-4.7-flash", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 65500 - } - }, - "novita/glm-4.7-n": { - "id": "novita/glm-4.7-n", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 205000, - "output": 131072 - } - }, - "novita/glm-4.6": { - "id": "novita/glm-4.6", - "family": "glm", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "novita/minimax-m2.1": { - "id": "novita/minimax-m2.1", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 205000, - "output": 131072 - } - }, - "novita/kimi-k2.5": { - "id": "novita/kimi-k2.5", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 262144 - } - }, - "novita/glm-4.7": { - "id": "novita/glm-4.7", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 205000, - "output": 131072 - } - }, - "novita/kimi-k2-thinking": { - "id": "novita/kimi-k2-thinking", - "family": "kimi", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 0 - } - }, - "novita/glm-4.6v": { - "id": "novita/glm-4.6v", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 32768 - } - }, - "google/gemini-3.1-pro": { - "id": "google/gemini-3.1-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "google/lyria": { - "id": "google/lyria", - "family": "lyria", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "audio" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "google/gemini-3-flash": { - "id": "google/gemini-3-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, "limit": { "context": 1000000, - "output": 64000 - }, - "family": "gemini-flash" - }, - "google/imagen-3": { - "id": "google/imagen-3", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 + "output": 80000, + "input": 1000000 } }, - "google/veo-3.1": { - "id": "google/veo-3.1", - "family": "veo", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/imagen-3-fast": { - "id": "google/imagen-3-fast", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/nano-banana-pro": { - "id": "google/nano-banana-pro", - "family": "nano-banana", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 65536, - "output": 0 - } - }, - "google/veo-2": { - "id": "google/veo-2", - "family": "veo", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/imagen-4-ultra": { - "id": "google/imagen-4-ultra", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/nano-banana": { - "id": "google/nano-banana", - "family": "nano-banana", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 65536, - "output": 0 - } - }, - "google/veo-3.1-fast": { - "id": "google/veo-3.1-fast", - "family": "veo", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/gemini-deep-research": { - "id": "google/gemini-deep-research", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 0 - } - }, - "google/veo-3": { - "id": "google/veo-3", - "family": "veo", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/imagen-4": { - "id": "google/imagen-4", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/gemini-2.0-flash-lite": { - "id": "google/gemini-2.0-flash-lite", - "family": "gemini-flash-lite", + "qwen3-coder-480b-a35b-instruct": { + "id": "qwen3-coder-480b-a35b-instruct", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image", - "audio", - "video", - "pdf" + "text" ], "output": [ "text" ] }, "limit": { - "context": 1048576, + "context": 262000, "output": 8192 - } - }, - "google/gemini-3.1-flash-lite": { - "id": "google/gemini-3.1-flash-lite", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 1048576, - "output": 65536 - } + "family": "qwen" }, - "google/gemini-3-pro": { - "id": "google/gemini-3-pro", - "family": "gemini-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "google/gemini-2.0-flash": { - "id": "google/gemini-2.0-flash", - "family": "gemini-flash", + "doubao-seed-code-preview-251028": { + "id": "doubao-seed-code-preview-251028", "reasoning": false, "temperature": true, "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 8192 - } - }, - "google/veo-3-fast": { - "id": "google/veo-3-fast", - "family": "veo", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/imagen-4-fast": { - "id": "google/imagen-4-fast", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "lumalabs/ray2": { - "id": "lumalabs/ray2", - "family": "ray", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 5000, - "output": 0 - } - }, - "poetools/claude-code": { - "id": "poetools/claude-code", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "openai/gpt-5-pro": { - "id": "openai/gpt-5-pro", - "family": "gpt-pro", - "reasoning": true, - "temperature": false, - "toolCall": false, "modalities": { "input": [ "text", @@ -11960,321 +1041,16 @@ ] }, "limit": { - "context": 400000, - "output": 128000, - "input": 400000 + "context": 256000, + "output": 32000 } }, - "openai/gpt-5.1-codex-max": { - "id": "openai/gpt-5.1-codex-max", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 400000 - }, - "family": "gpt-codex" - }, - "openai/o3-deep-research": { - "id": "openai/o3-deep-research", - "family": "o", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/o4-mini-deep-research": { - "id": "openai/o4-mini-deep-research", - "family": "o-mini", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/gpt-5-chat": { - "id": "openai/gpt-5-chat", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 111616 - } - }, - "openai/gpt-4-classic": { - "id": "openai/gpt-4-classic", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096 - } - }, - "openai/gpt-5.3-instant": { - "id": "openai/gpt-5.3-instant", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 111616, - "output": 16384 - } - }, - "openai/gpt-image-1.5": { - "id": "openai/gpt-image-1.5", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 128000, - "output": 0 - } - }, - "openai/gpt-4.1-nano": { - "id": "openai/gpt-4.1-nano", + "gpt-4.1-nano": { + "id": "gpt-4.1-nano", "family": "gpt-nano", "reasoning": false, "temperature": true, "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1047576, - "output": 32768, - "input": 1047576 - } - }, - "openai/gpt-image-1-mini": { - "id": "openai/gpt-image-1-mini", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "openai/sora-2-pro": { - "id": "openai/sora-2-pro", - "family": "sora", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "openai/gpt-4o-aug": { - "id": "openai/gpt-4o-aug", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "openai/gpt-image-1": { - "id": "openai/gpt-image-1", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 128000, - "output": 0 - } - }, - "openai/sora-2": { - "id": "openai/sora-2", - "family": "sora", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "openai/gpt-3.5-turbo-raw": { - "id": "openai/gpt-3.5-turbo-raw", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4524, - "output": 2048 - } - }, - "openai/gpt-4o-mini-search": { - "id": "openai/gpt-4o-mini-search", - "family": "gpt-mini", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "openai/gpt-4.1-mini": { - "id": "openai/gpt-4.1-mini", - "family": "gpt-mini", - "reasoning": false, - "temperature": true, - "toolCall": true, "modalities": { "input": [ "text", @@ -12286,699 +1062,12 @@ }, "limit": { "context": 1047576, - "output": 32768, - "input": 1047576 - } - }, - "openai/o1-pro": { - "id": "openai/o1-pro", - "family": "o-pro", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/chatgpt-4o-latest": { - "id": "openai/chatgpt-4o-latest", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - } - }, - "openai/dall-e-3": { - "id": "openai/dall-e-3", - "family": "dall-e", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 800, - "output": 0 - } - }, - "openai/gpt-4o-search": { - "id": "openai/gpt-4o-search", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "openai/gpt-4-classic-0314": { - "id": "openai/gpt-4-classic-0314", - "family": "gpt", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096 - } - }, - "openai/gpt-3.5-turbo-instruct": { - "id": "openai/gpt-3.5-turbo-instruct", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4095, - "output": 4096, - "input": 4096 - } - }, - "openai/gpt-5.2-instant": { - "id": "openai/gpt-5.2-instant", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "openai/o3-mini-high": { - "id": "openai/o3-mini-high", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - } - }, - "openai/gpt-5.1-instant": { - "id": "openai/gpt-5.1-instant", - "family": "gpt", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 111616 - } - }, - "topazlabs-co/topazlabs": { - "id": "topazlabs-co/topazlabs", - "family": "topazlabs", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 204, - "output": 0 - } - }, - "runwayml/runway": { - "id": "runwayml/runway", - "family": "runway", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 256, - "output": 0 - } - }, - "runwayml/runway-gen-4-turbo": { - "id": "runwayml/runway-gen-4-turbo", - "family": "runway", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "video" - ] - }, - "limit": { - "context": 256, - "output": 0 - } - }, - "anthropic/claude-sonnet-3.5-june": { - "id": "anthropic/claude-sonnet-3.5-june", - "family": "claude-sonnet", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 189096, - "output": 8192 - } - }, - "anthropic/claude-sonnet-3.5": { - "id": "anthropic/claude-sonnet-3.5", - "family": "claude-sonnet", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 189096, - "output": 8192 - } - }, - "anthropic/claude-haiku-3": { - "id": "anthropic/claude-haiku-3", - "family": "claude-haiku", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 189096, - "output": 8192 - } - }, - "anthropic/claude-haiku-3.5": { - "id": "anthropic/claude-haiku-3.5", - "family": "claude-haiku", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 189096, - "output": 8192 - } - }, - "anthropic/claude-sonnet-3.7": { - "id": "anthropic/claude-sonnet-3.7", - "family": "claude-sonnet", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 128000 - } - }, - "trytako/tako": { - "id": "trytako/tako", - "family": "tako", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2048, - "output": 0 - } - }, - "elevenlabs/elevenlabs-music": { - "id": "elevenlabs/elevenlabs-music", - "family": "elevenlabs", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "audio" - ] - }, - "limit": { - "context": 2000, - "output": 0 - } - }, - "elevenlabs/elevenlabs-v3": { - "id": "elevenlabs/elevenlabs-v3", - "family": "elevenlabs", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "audio" - ] - }, - "limit": { - "context": 128000, - "output": 0 - } - }, - "elevenlabs/elevenlabs-v2.5-turbo": { - "id": "elevenlabs/elevenlabs-v2.5-turbo", - "family": "elevenlabs", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "audio" - ] - }, - "limit": { - "context": 128000, - "output": 0 - } - }, - "cerebras/llama-3.1-8b-cs": { - "id": "cerebras/llama-3.1-8b-cs", - "reasoning": false, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "cerebras/gpt-oss-120b-cs": { - "id": "cerebras/gpt-oss-120b-cs", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "cerebras/qwen3-235b-2507-cs": { - "id": "cerebras/qwen3-235b-2507-cs", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "cerebras/llama-3.3-70b-cs": { - "id": "cerebras/llama-3.3-70b-cs", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "cerebras/qwen3-32b-cs": { - "id": "cerebras/qwen3-32b-cs", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "xai/grok-4-fast-reasoning": { - "id": "xai/grok-4-fast-reasoning", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 256000 - } - }, - "xai/grok-3": { - "id": "xai/grok-3", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "xai/grok-code-fast-1": { - "id": "xai/grok-code-fast-1", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 10000 - } - }, - "xai/grok-4.1-fast-reasoning": { - "id": "xai/grok-4.1-fast-reasoning", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 30000 - } - }, - "xai/grok-4": { - "id": "xai/grok-4", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "xai/grok-4.1-fast-non-reasoning": { - "id": "xai/grok-4.1-fast-non-reasoning", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 30000 - } - }, - "xai/grok-3-mini": { - "id": "xai/grok-3-mini", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "xai/grok-4-fast-non-reasoning": { - "id": "xai/grok-4-fast-non-reasoning", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 30000 - } - }, - "deepseek.r1-v1:0": { - "id": "deepseek.r1-v1:0", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, "output": 32768 } }, - "meta.llama3-1-70b-instruct-v1:0": { - "id": "meta.llama3-1-70b-instruct-v1:0", - "family": "llama", - "reasoning": false, + "deepseek-v3.2": { + "id": "deepseek-v3.2", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -12991,554 +1080,14 @@ }, "limit": { "context": 128000, - "output": 4096 - } - }, - "qwen.qwen3-coder-480b-a35b-v1:0": { - "id": "qwen.qwen3-coder-480b-a35b-v1:0", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "eu.anthropic.claude-sonnet-4-6": { - "id": "eu.anthropic.claude-sonnet-4-6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "eu.anthropic.claude-haiku-4-5-20251001-v1:0": { - "id": "eu.anthropic.claude-haiku-4-5-20251001-v1:0", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "mistral.mistral-large-3-675b-instruct": { - "id": "mistral.mistral-large-3-675b-instruct", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8192 - } - }, - "openai.gpt-oss-120b-1:0": { - "id": "openai.gpt-oss-120b-1:0", - "family": "gpt-oss", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "us.anthropic.claude-opus-4-20250514-v1:0": { - "id": "us.anthropic.claude-opus-4-20250514-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "nvidia.nemotron-nano-12b-v2": { - "id": "nvidia.nemotron-nano-12b-v2", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "anthropic.claude-3-7-sonnet-20250219-v1:0": { - "id": "anthropic.claude-3-7-sonnet-20250219-v1:0", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "anthropic.claude-sonnet-4-6": { - "id": "anthropic.claude-sonnet-4-6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "minimax.minimax-m2.1": { - "id": "minimax.minimax-m2.1", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "global.anthropic.claude-opus-4-5-20251101-v1:0": { - "id": "global.anthropic.claude-opus-4-5-20251101-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "mistral.ministral-3-8b-instruct": { - "id": "mistral.ministral-3-8b-instruct", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "openai.gpt-oss-safeguard-20b": { - "id": "openai.gpt-oss-safeguard-20b", - "family": "gpt-oss", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "amazon.nova-lite-v1:0": { - "id": "amazon.nova-lite-v1:0", - "family": "nova-lite", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 300000, - "output": 8192 - } - }, - "eu.anthropic.claude-sonnet-4-5-20250929-v1:0": { - "id": "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "mistral.pixtral-large-2502-v1:0": { - "id": "mistral.pixtral-large-2502-v1:0", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "google.gemma-3-12b-it": { - "id": "google.gemma-3-12b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "meta.llama3-1-8b-instruct-v1:0": { - "id": "meta.llama3-1-8b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistral.devstral-2-123b": { - "id": "mistral.devstral-2-123b", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8192 - } - }, - "anthropic.claude-sonnet-4-5-20250929-v1:0": { - "id": "anthropic.claude-sonnet-4-5-20250929-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "meta.llama4-maverick-17b-instruct-v1:0": { - "id": "meta.llama4-maverick-17b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 16384 - } - }, - "mistral.ministral-3-14b-instruct": { - "id": "mistral.ministral-3-14b-instruct", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "minimax.minimax-m2": { - "id": "minimax.minimax-m2", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204608, "output": 128000 - } - }, - "amazon.nova-micro-v1:0": { - "id": "amazon.nova-micro-v1:0", - "family": "nova-micro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 128000, - "output": 8192 - } + "family": "deepseek" }, - "anthropic.claude-3-5-sonnet-20241022-v2:0": { - "id": "anthropic.claude-3-5-sonnet-20241022-v2:0", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "nvidia.nemotron-nano-3-30b": { - "id": "nvidia.nemotron-nano-3-30b", - "family": "nemotron", + "gpt-5-pro": { + "id": "gpt-5-pro", "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "anthropic.claude-sonnet-4-20250514-v1:0": { - "id": "anthropic.claude-sonnet-4-20250514-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "qwen.qwen3-vl-235b-a22b": { - "id": "qwen.qwen3-vl-235b-a22b", - "family": "qwen", - "reasoning": false, - "temperature": true, + "temperature": false, "toolCall": true, "modalities": { "input": [ @@ -13550,1192 +1099,11 @@ ] }, "limit": { - "context": 262000, - "output": 262000 - } - }, - "global.anthropic.claude-opus-4-6-v1": { - "id": "global.anthropic.claude-opus-4-6-v1", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] + "context": 400000, + "output": 272000, + "input": 272000 }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "writer.palmyra-x4-v1:0": { - "id": "writer.palmyra-x4-v1:0", - "family": "palmyra", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 122880, - "output": 8192 - } - }, - "minimax.minimax-m2.5": { - "id": "minimax.minimax-m2.5", - "family": "minimax-m2.5", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 131072 - } - }, - "amazon.nova-pro-v1:0": { - "id": "amazon.nova-pro-v1:0", - "family": "nova-pro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 300000, - "output": 8192 - } - }, - "us.anthropic.claude-opus-4-5-20251101-v1:0": { - "id": "us.anthropic.claude-opus-4-5-20251101-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "meta.llama3-2-90b-instruct-v1:0": { - "id": "meta.llama3-2-90b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "us.anthropic.claude-opus-4-6-v1": { - "id": "us.anthropic.claude-opus-4-6-v1", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "google.gemma-3-4b-it": { - "id": "google.gemma-3-4b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "anthropic.claude-opus-4-6-v1": { - "id": "anthropic.claude-opus-4-6-v1", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "zai.glm-4.7-flash": { - "id": "zai.glm-4.7-flash", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 131072 - } - }, - "anthropic.claude-opus-4-20250514-v1:0": { - "id": "anthropic.claude-opus-4-20250514-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "global.anthropic.claude-sonnet-4-6": { - "id": "global.anthropic.claude-sonnet-4-6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "meta.llama3-2-1b-instruct-v1:0": { - "id": "meta.llama3-2-1b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 4096 - } - }, - "anthropic.claude-opus-4-1-20250805-v1:0": { - "id": "anthropic.claude-opus-4-1-20250805-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "meta.llama4-scout-17b-instruct-v1:0": { - "id": "meta.llama4-scout-17b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 3500000, - "output": 16384 - } - }, - "deepseek.v3.2": { - "id": "deepseek.v3.2", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 81920 - } - }, - "deepseek.v3-v1:0": { - "id": "deepseek.v3-v1:0", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 81920 - } - }, - "mistral.ministral-3-3b-instruct": { - "id": "mistral.ministral-3-3b-instruct", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8192 - } - }, - "global.anthropic.claude-haiku-4-5-20251001-v1:0": { - "id": "global.anthropic.claude-haiku-4-5-20251001-v1:0", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "nvidia.nemotron-nano-9b-v2": { - "id": "nvidia.nemotron-nano-9b-v2", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "writer.palmyra-x5-v1:0": { - "id": "writer.palmyra-x5-v1:0", - "family": "palmyra", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1040000, - "output": 8192 - } - }, - "meta.llama3-3-70b-instruct-v1:0": { - "id": "meta.llama3-3-70b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "zai.glm-4.7": { - "id": "zai.glm-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "moonshot.kimi-k2-thinking": { - "id": "moonshot.kimi-k2-thinking", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "anthropic.claude-3-haiku-20240307-v1:0": { - "id": "anthropic.claude-3-haiku-20240307-v1:0", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "us.anthropic.claude-sonnet-4-5-20250929-v1:0": { - "id": "us.anthropic.claude-sonnet-4-5-20250929-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "openai.gpt-oss-20b-1:0": { - "id": "openai.gpt-oss-20b-1:0", - "family": "gpt-oss", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "us.anthropic.claude-sonnet-4-6": { - "id": "us.anthropic.claude-sonnet-4-6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "meta.llama3-2-11b-instruct-v1:0": { - "id": "meta.llama3-2-11b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "eu.anthropic.claude-opus-4-5-20251101-v1:0": { - "id": "eu.anthropic.claude-opus-4-5-20251101-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "meta.llama3-1-405b-instruct-v1:0": { - "id": "meta.llama3-1-405b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "qwen.qwen3-next-80b-a3b": { - "id": "qwen.qwen3-next-80b-a3b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, - "output": 262000 - } - }, - "us.anthropic.claude-sonnet-4-20250514-v1:0": { - "id": "us.anthropic.claude-sonnet-4-20250514-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "qwen.qwen3-coder-30b-a3b-v1:0": { - "id": "qwen.qwen3-coder-30b-a3b-v1:0", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "us.anthropic.claude-haiku-4-5-20251001-v1:0": { - "id": "us.anthropic.claude-haiku-4-5-20251001-v1:0", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "qwen.qwen3-235b-a22b-2507-v1:0": { - "id": "qwen.qwen3-235b-a22b-2507-v1:0", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "openai.gpt-oss-safeguard-120b": { - "id": "openai.gpt-oss-safeguard-120b", - "family": "gpt-oss", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "anthropic.claude-3-5-sonnet-20240620-v1:0": { - "id": "anthropic.claude-3-5-sonnet-20240620-v1:0", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "mistral.voxtral-small-24b-2507": { - "id": "mistral.voxtral-small-24b-2507", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 8192 - } - }, - "anthropic.claude-haiku-4-5-20251001-v1:0": { - "id": "anthropic.claude-haiku-4-5-20251001-v1:0", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "meta.llama3-2-3b-instruct-v1:0": { - "id": "meta.llama3-2-3b-instruct-v1:0", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 4096 - } - }, - "google.gemma-3-27b-it": { - "id": "google.gemma-3-27b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 8192 - } - }, - "us.anthropic.claude-opus-4-1-20250805-v1:0": { - "id": "us.anthropic.claude-opus-4-1-20250805-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "global.anthropic.claude-sonnet-4-20250514-v1:0": { - "id": "global.anthropic.claude-sonnet-4-20250514-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic.claude-3-5-haiku-20241022-v1:0": { - "id": "anthropic.claude-3-5-haiku-20241022-v1:0", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "zai.glm-5": { - "id": "zai.glm-5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 131072 - } - }, - "eu.anthropic.claude-sonnet-4-20250514-v1:0": { - "id": "eu.anthropic.claude-sonnet-4-20250514-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic.claude-opus-4-5-20251101-v1:0": { - "id": "anthropic.claude-opus-4-5-20251101-v1:0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "eu.anthropic.claude-opus-4-6-v1": { - "id": "eu.anthropic.claude-opus-4-6-v1", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "amazon.nova-premier-v1:0": { - "id": "amazon.nova-premier-v1:0", - "family": "nova", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 16384 - } - }, - "amazon.nova-2-lite-v1:0": { - "id": "amazon.nova-2-lite-v1:0", - "family": "nova", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "qwen.qwen3-32b-v1:0": { - "id": "qwen.qwen3-32b-v1:0", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "mistral.magistral-small-2509": { - "id": "mistral.magistral-small-2509", - "family": "magistral", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 40000 - } - }, - "moonshotai.kimi-k2.5": { - "id": "moonshotai.kimi-k2.5", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "mistral.voxtral-mini-3b-2507": { - "id": "mistral.voxtral-mini-3b-2507", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "global.anthropic.claude-sonnet-4-5-20250929-v1:0": { - "id": "global.anthropic.claude-sonnet-4-5-20250929-v1:0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "ring-1t": { - "id": "Ring-1T", - "family": "ring", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "ling-1t": { - "id": "Ling-1T", - "family": "ling", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "phi-3-small-8k-instruct": { - "id": "phi-3-small-8k-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - } + "family": "gpt-pro" }, "gpt-4o": { "id": "gpt-4o", @@ -14758,162 +1126,8 @@ "input": 64000 } }, - "codestral-2501": { - "id": "codestral-2501", - "family": "codestral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "mistral-small-2503": { - "id": "mistral-small-2503", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "o1-mini": { - "id": "o1-mini", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 65536 - } - }, - "gpt-3.5-turbo-instruct": { - "id": "gpt-3.5-turbo-instruct", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 4096 - } - }, - "gpt-4": { - "id": "gpt-4", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "gpt-3.5-turbo-1106": { - "id": "gpt-3.5-turbo-1106", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "phi-4-reasoning": { - "id": "phi-4-reasoning", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 4096 - } - }, - "phi-3-mini-128k-instruct": { - "id": "phi-3-mini-128k-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "gpt-5-mini": { - "id": "gpt-5-mini", - "family": "gpt-mini", + "gpt-5": { + "id": "gpt-5", "reasoning": true, "temperature": false, "toolCall": true, @@ -14930,429 +1144,28 @@ "context": 272000, "output": 128000, "input": 272000 - } + }, + "family": "gpt" }, - "grok-4-fast-non-reasoning": { - "id": "grok-4-fast-non-reasoning", - "family": "grok", - "reasoning": false, + "claude-sonnet-4-5-20250929-thinking": { + "id": "claude-sonnet-4-5-20250929-thinking", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 2000000, - "output": 30000 - } - }, - "o3-mini": { - "id": "o3-mini", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "cohere-embed-v3-english": { - "id": "cohere-embed-v3-english", - "family": "cohere-embed", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 512, - "output": 1024 - } - }, - "phi-3-medium-4k-instruct": { - "id": "phi-3-medium-4k-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 1024 - } - }, - "cohere-embed-v3-multilingual": { - "id": "cohere-embed-v3-multilingual", - "family": "cohere-embed", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 512, - "output": 1024 - } - }, - "gpt-3.5-turbo-0125": { - "id": "gpt-3.5-turbo-0125", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "phi-4-mini-reasoning": { - "id": "phi-4-mini-reasoning", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mistral-large-2411": { - "id": "mistral-large-2411", - "family": "mistral-large", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "meta-llama-3.1-8b-instruct": { - "id": "meta-llama-3.1-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "o1-preview": { - "id": "o1-preview", - "family": "o", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "meta-llama-3.1-70b-instruct": { - "id": "meta-llama-3.1-70b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "phi-3-mini-4k-instruct": { - "id": "phi-3-mini-4k-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 1024 - } - }, - "codex-mini": { - "id": "codex-mini", - "family": "gpt-codex-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "phi-4-reasoning-plus": { - "id": "phi-4-reasoning-plus", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 4096 - } - }, - "gpt-4.1-mini": { - "id": "gpt-4.1-mini", - "family": "gpt-mini", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1047576, - "output": 32768 - } - }, - "phi-4": { - "id": "phi-4", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "o4-mini": { - "id": "o4-mini", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "gpt-4-32k": { - "id": "gpt-4-32k", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "grok-3-mini": { - "id": "grok-3-mini", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "cohere-embed-v-4-0": { - "id": "cohere-embed-v-4-0", - "family": "cohere-embed", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 1536 - } - }, - "mistral-nemo": { - "id": "mistral-nemo", - "family": "mistral-nemo", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "gpt-4-turbo": { - "id": "gpt-4-turbo", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 + "context": 1000000, + "output": 64000, + "input": 1000000 } }, "gpt-4.1": { @@ -15376,85 +1189,52 @@ "input": 64000 } }, - "model-router": { - "id": "model-router", - "family": "model-router", + "kimi-k2-thinking": { + "id": "kimi-k2-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + }, + "family": "kimi-thinking" + }, + "gemini-2.0-flash-lite": { + "id": "gemini-2.0-flash-lite", + "family": "gemini-flash-lite", "reasoning": false, + "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "audio", + "video", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 128000, - "output": 16384 + "context": 1048576, + "output": 8192, + "input": 1000000 } }, - "text-embedding-3-large": { - "id": "text-embedding-3-large", - "family": "text-embedding", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8191, - "output": 3072 - }, - "temperature": false - }, - "gpt-3.5-turbo-0613": { - "id": "gpt-3.5-turbo-0613", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "cohere-command-r-08-2024": { - "id": "cohere-command-r-08-2024", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "gpt-4.1-nano": { - "id": "gpt-4.1-nano", - "family": "gpt-nano", + "gpt-4.1-mini": { + "id": "gpt-4.1-mini", + "family": "gpt-mini", "reasoning": false, "temperature": true, "toolCall": true, @@ -15472,560 +1252,11 @@ "output": 32768 } }, - "deepseek-v3.2-speciale": { - "id": "deepseek-v3.2-speciale", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "phi-4-mini": { - "id": "phi-4-mini", - "family": "phi", + "grok-4-fast-non-reasoning": { + "id": "grok-4-fast-non-reasoning", "reasoning": false, "temperature": true, "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "text-embedding-3-small": { - "id": "text-embedding-3-small", - "family": "text-embedding", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8191, - "output": 1536 - }, - "temperature": false - }, - "gpt-3.5-turbo-0301": { - "id": "gpt-3.5-turbo-0301", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 4096 - } - }, - "meta-llama-3-70b-instruct": { - "id": "meta-llama-3-70b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - } - }, - "llama-3.2-11b-vision-instruct": { - "id": "llama-3.2-11b-vision-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "o3": { - "id": "o3", - "family": "o", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "meta-llama-3-8b-instruct": { - "id": "meta-llama-3-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - } - }, - "gpt-5.1-chat": { - "id": "gpt-5.1-chat", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text", - "image", - "audio" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "grok-4": { - "id": "grok-4", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "gpt-5-chat": { - "id": "gpt-5-chat", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "gpt-5.2-chat": { - "id": "gpt-5.2-chat", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "cohere-command-r-plus-08-2024": { - "id": "cohere-command-r-plus-08-2024", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "meta-llama-3.1-405b-instruct": { - "id": "meta-llama-3.1-405b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "llama-4-scout-17b-16e-instruct": { - "id": "llama-4-scout-17b-16e-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "o1": { - "id": "o1", - "family": "o", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "mistral-medium-2505": { - "id": "mistral-medium-2505", - "family": "mistral-medium", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "cohere-command-a": { - "id": "cohere-command-a", - "family": "command-a", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8000 - } - }, - "phi-3.5-mini-instruct": { - "id": "phi-3.5-mini-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "grok-code-fast-1": { - "id": "grok-code-fast-1", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 10000, - "input": 128000 - } - }, - "llama-3.2-90b-vision-instruct": { - "id": "llama-3.2-90b-vision-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "grok-3": { - "id": "grok-3", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "ministral-3b": { - "id": "ministral-3b", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "gpt-4-turbo-vision": { - "id": "gpt-4-turbo-vision", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "phi-3.5-moe-instruct": { - "id": "phi-3.5-moe-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "mai-ds-r1": { - "id": "mai-ds-r1", - "family": "mai", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "phi-4-multimodal": { - "id": "phi-4-multimodal", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "phi-3-medium-128k-instruct": { - "id": "phi-3-medium-128k-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "grok-4-fast-reasoning": { - "id": "grok-4-fast-reasoning", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, "modalities": { "input": [ "text", @@ -16038,31 +1269,12 @@ "limit": { "context": 2000000, "output": 30000 - } - }, - "text-embedding-ada-002": { - "id": "text-embedding-ada-002", - "family": "text-embedding", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 8192, - "output": 1536 - }, - "temperature": false + "family": "grok" }, - "gpt-4o-mini": { - "id": "gpt-4o-mini", - "family": "gpt-mini", - "reasoning": false, + "doubao-seed-1-6-thinking-250715": { + "id": "doubao-seed-1-6-thinking-250715", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -16075,111 +1287,32 @@ ] }, "limit": { - "context": 128000, + "context": 256000, + "output": 16000 + } + }, + "ministral-14b-2512": { + "id": "ministral-14b-2512", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, "output": 16384 - } - }, - "phi-3-small-128k-instruct": { - "id": "phi-3-small-128k-instruct", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 128000, - "output": 4096 - } + "family": "mistral" }, - "gpt-5-pro": { - "id": "gpt-5-pro", - "family": "gpt-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 272000, - "input": 272000 - } - }, - "qwen-vl-plus": { - "id": "qwen-vl-plus", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen-vl-max": { - "id": "qwen-vl-max", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen3-14b": { - "id": "qwen3-14b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen3-coder-flash": { - "id": "qwen3-coder-flash", + "qwen3-coder-plus": { + "id": "qwen3-coder-plus", "family": "qwen", "reasoning": false, "temperature": true, @@ -16194,11 +1327,72 @@ }, "limit": { "context": 1000000, - "output": 65536 + "output": 66000 } }, - "qwen3-vl-30b-a3b": { - "id": "qwen3-vl-30b-a3b", + "qwen-vl-ocr": { + "id": "qwen-vl-ocr", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 34096, + "output": 4096 + } + }, + "qwen-omni-turbo-realtime": { + "id": "qwen-omni-turbo-realtime", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "qwen3-8b": { + "id": "qwen3-8b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3.5-397b-a17b": { + "id": "qwen3.5-397b-a17b", "family": "qwen", "reasoning": true, "temperature": true, @@ -16212,9 +1406,254 @@ "text" ] }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "qwq-plus": { + "id": "qwq-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, "limit": { "context": 131072, - "output": 32768 + "output": 8192 + } + }, + "qwen-vl-plus": { + "id": "qwen-vl-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "qwen3-livetranslate-flash-realtime": { + "id": "qwen3-livetranslate-flash-realtime", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 53248, + "output": 4096 + } + }, + "qwen3-32b": { + "id": "qwen3-32b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen-max": { + "id": "qwen-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000, + "input": 32000 + } + }, + "qwen-omni-turbo": { + "id": "qwen-omni-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen2-5-vl-7b-instruct": { + "id": "qwen2-5-vl-7b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3.6-plus": { + "id": "qwen3.6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen3-max": { + "id": "qwen3-max", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32800 + } + }, + "qwen3-omni-flash": { + "id": "qwen3-omni-flash", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 65536, + "output": 16384 + } + }, + "qwen2-5-72b-instruct": { + "id": "qwen2-5-72b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-vl-235b-a22b": { + "id": "qwen3-vl-235b-a22b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 } }, "qwen3-asr-flash": { @@ -16236,8 +1675,66 @@ "output": 4096 } }, - "qwen-max": { - "id": "qwen-max", + "qwen3-next-80b-a3b-thinking": { + "id": "qwen3-next-80b-a3b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen-mt-plus": { + "id": "qwen-mt-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192 + } + }, + "qwen-vl-max": { + "id": "qwen-vl-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "qwen3-coder-flash": { + "id": "qwen3-coder-flash", "family": "qwen", "reasoning": false, "temperature": true, @@ -16251,9 +1748,8 @@ ] }, "limit": { - "context": 131072, - "output": 8192, - "input": 32000 + "context": 1000000, + "output": 65536 } }, "qwen2-5-7b-instruct": { @@ -16275,26 +1771,6 @@ "output": 8192 } }, - "qwen2-5-vl-72b-instruct": { - "id": "qwen2-5-vl-72b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, "qwen2-5-14b-instruct": { "id": "qwen2-5-14b-instruct", "family": "qwen", @@ -16314,10 +1790,10 @@ "output": 8192 } }, - "qwen3-8b": { - "id": "qwen3-8b", + "qwen2-5-32b-instruct": { + "id": "qwen2-5-32b-instruct", "family": "qwen", - "reasoning": true, + "reasoning": false, "temperature": true, "toolCall": true, "modalities": { @@ -16333,9 +1809,69 @@ "output": 8192 } }, - "qvq-max": { - "id": "qvq-max", - "family": "qvq", + "qwen3-next-80b-a3b-instruct": { + "id": "qwen3-next-80b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 129024, + "output": 32768 + } + }, + "qwen-plus-character-ja": { + "id": "qwen-plus-character-ja", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 512 + } + }, + "qwen3-omni-flash-realtime": { + "id": "qwen3-omni-flash-realtime", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 65536, + "output": 16384 + } + }, + "qwen3-vl-30b-a3b": { + "id": "qwen3-vl-30b-a3b", + "family": "qwen", "reasoning": true, "temperature": true, "toolCall": true, @@ -16350,10 +1886,88 @@ }, "limit": { "context": 131072, + "output": 32768 + } + }, + "qwen3-vl-plus": { + "id": "qwen3-vl-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "qwen3-coder-30b-a3b-instruct": { + "id": "qwen3-coder-30b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, "output": 8192, "input": 128000 } }, + "qwen-turbo": { + "id": "qwen-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192, + "input": 1000000 + } + }, + "qwen-mt-turbo": { + "id": "qwen-mt-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192 + } + }, "qwen2-5-omni-7b": { "id": "qwen2-5-omni-7b", "family": "qwen", @@ -16377,122 +1991,16 @@ "output": 2048 } }, - "qwen2-5-vl-7b-instruct": { - "id": "qwen2-5-vl-7b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen-omni-turbo-realtime": { - "id": "qwen-omni-turbo-realtime", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text", - "audio" - ] - }, - "limit": { - "context": 32768, - "output": 2048 - } - }, - "qwen-omni-turbo": { - "id": "qwen-omni-turbo", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text", - "audio" - ] - }, - "limit": { - "context": 32768, - "output": 2048 - } - }, - "qwen-mt-plus": { - "id": "qwen-mt-plus", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 8192 - } - }, - "qwen3-livetranslate-flash-realtime": { - "id": "qwen3-livetranslate-flash-realtime", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text", - "audio" - ] - }, - "limit": { - "context": 53248, - "output": 4096 - } - }, - "qwen-plus": { - "id": "qwen-plus", + "qwen3.5-plus": { + "id": "qwen3.5-plus", "family": "qwen", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" @@ -16500,114 +2008,11 @@ }, "limit": { "context": 1000000, - "output": 32768, - "input": 995904 + "output": 65536 } }, - "qwen2-5-32b-instruct": { - "id": "qwen2-5-32b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen3-omni-flash": { - "id": "qwen3-omni-flash", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text", - "audio" - ] - }, - "limit": { - "context": 65536, - "output": 16384 - } - }, - "qwen-flash": { - "id": "qwen-flash", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 32768 - } - }, - "qwen2-5-72b-instruct": { - "id": "qwen2-5-72b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen3-omni-flash-realtime": { - "id": "qwen3-omni-flash-realtime", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text", - "audio" - ] - }, - "limit": { - "context": 65536, - "output": 16384 - } - }, - "qwen-vl-ocr": { - "id": "qwen-vl-ocr", + "qwen2-5-vl-72b-instruct": { + "id": "qwen2-5-vl-72b-instruct", "family": "qwen", "reasoning": false, "temperature": true, @@ -16621,1061 +2026,15 @@ "text" ] }, - "limit": { - "context": 34096, - "output": 4096 - } - }, - "qwq-plus": { - "id": "qwq-plus", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen3-vl-235b-a22b": { - "id": "qwen3-vl-235b-a22b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "qwen-plus-character-ja": { - "id": "qwen-plus-character-ja", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 512 - } - }, - "qwen-mt-turbo": { - "id": "qwen-mt-turbo", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 8192 - } - }, - "@cf/zai-org/glm-4.7-flash": { - "id": "@cf/zai-org/glm-4.7-flash", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "@cf/nvidia/nemotron-3-120b-a12b": { - "id": "@cf/nvidia/nemotron-3-120b-a12b", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "@cf/ibm-granite/granite-4.0-h-micro": { - "id": "@cf/ibm-granite/granite-4.0-h-micro", - "family": "granite", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/baai/bge-small-en-v1.5": { - "id": "@cf/baai/bge-small-en-v1.5", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/baai/bge-large-en-v1.5": { - "id": "@cf/baai/bge-large-en-v1.5", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/baai/bge-reranker-base": { - "id": "@cf/baai/bge-reranker-base", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/baai/bge-m3": { - "id": "@cf/baai/bge-m3", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/baai/bge-base-en-v1.5": { - "id": "@cf/baai/bge-base-en-v1.5", - "family": "bge", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/pfnet/plamo-embedding-1b": { - "id": "@cf/pfnet/plamo-embedding-1b", - "family": "plamo", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b": { - "id": "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", - "family": "deepseek-thinking", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/facebook/bart-large-cnn": { - "id": "@cf/facebook/bart-large-cnn", - "family": "bart", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/mistral/mistral-7b-instruct-v0.1": { - "id": "@cf/mistral/mistral-7b-instruct-v0.1", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/myshell-ai/melotts": { - "id": "@cf/myshell-ai/melotts", - "family": "melotts", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/pipecat-ai/smart-turn-v2": { - "id": "@cf/pipecat-ai/smart-turn-v2", - "family": "smart-turn", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/moonshotai/kimi-k2.5": { - "id": "@cf/moonshotai/kimi-k2.5", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "@cf/google/gemma-3-12b-it": { - "id": "@cf/google/gemma-3-12b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/qwen/qwq-32b": { - "id": "@cf/qwen/qwq-32b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/qwen/qwen3-30b-a3b-fp8": { - "id": "@cf/qwen/qwen3-30b-a3b-fp8", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/qwen/qwen2.5-coder-32b-instruct": { - "id": "@cf/qwen/qwen2.5-coder-32b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/qwen/qwen3-embedding-0.6b": { - "id": "@cf/qwen/qwen3-embedding-0.6b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3.1-8b-instruct-fp8": { - "id": "@cf/meta/llama-3.1-8b-instruct-fp8", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3-8b-instruct-awq": { - "id": "@cf/meta/llama-3-8b-instruct-awq", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3.1-8b-instruct-awq": { - "id": "@cf/meta/llama-3.1-8b-instruct-awq", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-4-scout-17b-16e-instruct": { - "id": "@cf/meta/llama-4-scout-17b-16e-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3.2-11b-vision-instruct": { - "id": "@cf/meta/llama-3.2-11b-vision-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3.2-3b-instruct": { - "id": "@cf/meta/llama-3.2-3b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-guard-3-8b": { - "id": "@cf/meta/llama-guard-3-8b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3.2-1b-instruct": { - "id": "@cf/meta/llama-3.2-1b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3.3-70b-instruct-fp8-fast": { - "id": "@cf/meta/llama-3.3-70b-instruct-fp8-fast", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3.1-8b-instruct": { - "id": "@cf/meta/llama-3.1-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/m2m100-1.2b": { - "id": "@cf/meta/m2m100-1.2b", - "family": "m2m", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-2-7b-chat-fp16": { - "id": "@cf/meta/llama-2-7b-chat-fp16", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/meta/llama-3-8b-instruct": { - "id": "@cf/meta/llama-3-8b-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/mistralai/mistral-small-3.1-24b-instruct": { - "id": "@cf/mistralai/mistral-small-3.1-24b-instruct", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/deepgram/aura-2-es": { - "id": "@cf/deepgram/aura-2-es", - "family": "aura", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/deepgram/nova-3": { - "id": "@cf/deepgram/nova-3", - "family": "nova", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/deepgram/aura-2-en": { - "id": "@cf/deepgram/aura-2-en", - "family": "aura", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/openai/gpt-oss-120b": { - "id": "@cf/openai/gpt-oss-120b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/openai/gpt-oss-20b": { - "id": "@cf/openai/gpt-oss-20b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/ai4bharat/indictrans2-en-indic-1b": { - "id": "@cf/ai4bharat/indictrans2-en-indic-1B", - "family": "indictrans", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/huggingface/distilbert-sst-2-int8": { - "id": "@cf/huggingface/distilbert-sst-2-int8", - "family": "distilbert", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "@cf/aisingapore/gemma-sea-lion-v4-27b-it": { - "id": "@cf/aisingapore/gemma-sea-lion-v4-27b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "llama3-70b-8192": { - "id": "llama3-70b-8192", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "qwen-qwq-32b": { - "id": "qwen-qwq-32b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "llama-3.1-8b-instant": { - "id": "llama-3.1-8b-instant", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32678 - } - }, - "llama-guard-3-8b": { - "id": "llama-guard-3-8b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "llama3-8b-8192": { - "id": "llama3-8b-8192", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "mistral-saba-24b": { - "id": "mistral-saba-24b", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, "limit": { "context": 32768, - "output": 32768 - } - }, - "llama-3.3-70b-versatile": { - "id": "llama-3.3-70b-versatile", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32678 - } - }, - "gemma2-9b-it": { - "id": "gemma2-9b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, "output": 8192 } }, - "meta-llama/llama-guard-4-12b": { - "id": "meta-llama/llama-guard-4-12b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 32768 - } - }, - "meta-llama/llama-4-maverick-17b-128e-instruct": { - "id": "meta-llama/llama-4-maverick-17b-128e-instruct", - "family": "llama", - "reasoning": false, + "qvq-max": { + "id": "qvq-max", + "family": "qvq", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -17689,69 +2048,13 @@ }, "limit": { "context": 131072, - "output": 8192 + "output": 8192, + "input": 128000 } }, - "zai-org/glm-5-fp8": { - "id": "zai-org/GLM-5-FP8", - "family": "glm", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 200000 - } - }, - "nvidia/nvidia-nemotron-3-super-120b-a12b-fp8": { - "id": "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "openpipe/qwen3-14b-instruct": { - "id": "OpenPipe/Qwen3-14B-Instruct", + "qwen3-14b": { + "id": "qwen3-14b", "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "coding-glm-4.7-free": { - "id": "coding-glm-4.7-free", - "family": "glm", "reasoning": true, "temperature": true, "toolCall": true, @@ -17764,406 +2067,13 @@ ] }, "limit": { - "context": 204800, - "output": 131072 + "context": 131072, + "output": 8192 } }, - "coding-minimax-m2.1-free": { - "id": "coding-minimax-m2.1-free", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "claude-opus-4-6-think": { - "id": "claude-opus-4-6-think", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000 - } - }, - "gemini-3-pro-preview-search": { - "id": "gemini-3-pro-preview-search", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65000 - } - }, - "deepseek-v3.2-think": { - "id": "deepseek-v3.2-think", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 64000 - } - }, - "gemini-3-pro-preview": { - "id": "gemini-3-pro-preview", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - } - }, - "deepseek-v3.2-fast": { - "id": "deepseek-v3.2-fast", - "family": "deepseek", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "coding-glm-4.7": { - "id": "coding-glm-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "coding-glm-5-free": { - "id": "coding-glm-5-free", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "claude-sonnet-4-6-think": { - "id": "claude-sonnet-4-6-think", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "k2p5": { - "id": "k2p5", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "devstral-medium-2507": { - "id": "devstral-medium-2507", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "labs-devstral-small-2512": { - "id": "labs-devstral-small-2512", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "devstral-medium-latest": { - "id": "devstral-medium-latest", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "open-mistral-7b": { - "id": "open-mistral-7b", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "output": 8000 - } - }, - "mistral-small-2506": { - "id": "mistral-small-2506", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "codestral-latest": { - "id": "codestral-latest", - "family": "codestral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 4096 - } - }, - "ministral-8b-latest": { - "id": "ministral-8b-latest", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "magistral-small": { - "id": "magistral-small", - "family": "magistral-small", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "mistral-large-2512": { - "id": "mistral-large-2512", - "family": "mistral-large", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 262144 - } - }, - "ministral-3b-latest": { - "id": "ministral-3b-latest", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "mistral-embed": { - "id": "mistral-embed", - "family": "mistral-embed", + "qwen3-embedding-8b": { + "id": "qwen3-embedding-8b", + "family": "qwen", "reasoning": false, "temperature": false, "toolCall": false, @@ -18176,13 +2086,13 @@ ] }, "limit": { - "context": 8000, - "output": 3072 + "context": 32768, + "output": 4096 } }, - "devstral-small-2505": { - "id": "devstral-small-2505", - "family": "devstral", + "llama-3.3-70b-instruct": { + "id": "llama-3.3-70b-instruct", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": true, @@ -18196,11 +2106,49 @@ }, "limit": { "context": 128000, - "output": 128000 + "output": 32768 } }, - "pixtral-12b": { - "id": "pixtral-12b", + "devstral-2-123b-instruct-2512": { + "id": "devstral-2-123b-instruct-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "deepseek-r1-distill-llama-70b": { + "id": "deepseek-r1-distill-llama-70b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "pixtral-12b-2409": { + "id": "pixtral-12b-2409", "family": "pixtral", "reasoning": false, "temperature": true, @@ -18216,18 +2164,38 @@ }, "limit": { "context": 128000, - "output": 128000 + "output": 4096 } }, - "open-mixtral-8x7b": { - "id": "open-mixtral-8x7b", - "family": "mixtral", + "whisper-large-v3": { + "id": "whisper-large-v3", + "family": "whisper", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + } + }, + "voxtral-small-24b-2507": { + "id": "voxtral-small-24b-2507", + "family": "voxtral", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "audio" ], "output": [ "text" @@ -18235,12 +2203,12 @@ }, "limit": { "context": 32000, - "output": 32000 + "output": 16384 } }, - "pixtral-large-latest": { - "id": "pixtral-large-latest", - "family": "pixtral", + "gemma-3-27b-it": { + "id": "gemma-3-27b-it", + "family": "gemma", "reasoning": false, "temperature": true, "toolCall": true, @@ -18254,16 +2222,17 @@ ] }, "limit": { - "context": 128000, - "output": 128000 + "context": 131072, + "output": 8192, + "input": 32768 } }, - "devstral-2512": { - "id": "devstral-2512", - "family": "devstral", + "bge-multilingual-gemma2": { + "id": "bge-multilingual-gemma2", + "family": "gemma", "reasoning": false, - "temperature": true, - "toolCall": true, + "temperature": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -18273,52 +2242,12 @@ ] }, "limit": { - "context": 262000, - "output": 262000 + "context": 8191, + "output": 3072 } }, - "mistral-large-latest": { - "id": "mistral-large-latest", - "family": "mistral-large", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "mistral-medium-2508": { - "id": "mistral-medium-2508", - "family": "mistral-medium", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "mistral-small-latest": { - "id": "mistral-small-latest", + "mistral-small-3.2-24b-instruct-2506": { + "id": "mistral-small-3.2-24b-instruct-2506", "family": "mistral-small", "reasoning": false, "temperature": true, @@ -18333,53 +2262,14 @@ ] }, "limit": { - "context": 128000, - "output": 16384 + "context": 131072, + "output": 131072 } }, - "open-mixtral-8x22b": { - "id": "open-mixtral-8x22b", - "family": "mixtral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 64000 - } - }, - "mistral-medium-latest": { - "id": "mistral-medium-latest", - "family": "mistral-medium", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "devstral-small-2507": { - "id": "devstral-small-2507", - "family": "devstral", - "reasoning": false, + "gpt-oss-120b": { + "id": "gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -18395,449 +2285,27 @@ "output": 128000 } }, - "magistral-medium-latest": { - "id": "magistral-medium-latest", - "family": "magistral-medium", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "gpt-4o-2024-11-20": { - "id": "gpt-4o-2024-11-20", - "family": "gpt", + "mistral-nemo-instruct-2407": { + "id": "mistral-nemo-instruct-2407", + "family": "mistral-nemo", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image" + "text" ], "output": [ "text" ] }, "limit": { - "context": 128000, - "output": 16384 - } - }, - "claude-opus-4-5-20251101": { - "id": "claude-opus-4-5-20251101", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000, - "input": 200000 - } - }, - "gpt-5.2-chat-latest": { - "id": "gpt-5.2-chat-latest", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "grok-4-0709": { - "id": "grok-4-0709", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8192 - } - }, - "gpt-5.3-codex-xhigh": { - "id": "gpt-5.3-codex-xhigh", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "grok-4-1-fast-non-reasoning": { - "id": "grok-4-1-fast-non-reasoning", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 30000, - "input": 128000 - } - }, - "gemini-3.1-flash-lite-preview": { - "id": "gemini-3.1-flash-lite-preview", - "family": "gemini-flash-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, + "context": 65536, "output": 65536 } }, - "claude-opus-4-20250514": { - "id": "claude-opus-4-20250514", - "family": "claude-opus", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000, - "input": 200000 - } - }, - "claude-sonnet-4-5-20250929": { - "id": "claude-sonnet-4-5-20250929", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000, - "input": 1000000 - } - }, - "o3-pro": { - "id": "o3-pro", - "family": "o-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "gemini-3.1-pro-preview": { - "id": "gemini-3.1-pro-preview", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536, - "input": 128000 - } - }, - "claude-3-7-sonnet-20250219": { - "id": "claude-3-7-sonnet-20250219", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 16000, - "input": 200000 - } - }, - "claude-haiku-4-5-20251001": { - "id": "claude-haiku-4-5-20251001", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000, - "input": 200000 - } - }, - "kimi-k2-turbo-preview": { - "id": "kimi-k2-turbo-preview", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen-2.5-coder-32b": { - "id": "qwen-2.5-coder-32b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "route-llm": { - "id": "route-llm", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "gpt-5.3-chat-latest": { - "id": "gpt-5.3-chat-latest", - "family": "gpt", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "claude-sonnet-4-20250514": { - "id": "claude-sonnet-4-20250514", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000, - "input": 200000 - } - }, - "gpt-5.1-chat-latest": { - "id": "gpt-5.1-chat-latest", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "claude-opus-4-1-20250805": { - "id": "claude-opus-4-1-20250805", - "family": "claude-opus", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000, - "input": 200000 - } - }, - "meta-llama/meta-llama-3.1-405b-instruct-turbo": { - "id": "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", + "llama-3.1-8b-instruct": { + "id": "llama-3.1-8b-instruct", "family": "llama", "reasoning": false, "temperature": true, @@ -18852,54 +2320,13 @@ }, "limit": { "context": 128000, - "output": 4096 + "output": 2048 } }, - "qwen/qwen2.5-72b-instruct": { - "id": "Qwen/Qwen2.5-72B-Instruct", - "family": "qwen", + "glm-4-flash": { + "id": "glm-4-flash", "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "accounts/fireworks/routers/kimi-k2p5-turbo": { - "id": "accounts/fireworks/routers/kimi-k2p5-turbo", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "accounts/fireworks/models/kimi-k2-instruct": { - "id": "accounts/fireworks/models/kimi-k2-instruct", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text" @@ -18910,75 +2337,37 @@ }, "limit": { "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "meta-llama-3-1-8b-instruct-fp8": { + "id": "Meta-Llama-3-1-8B-Instruct-FP8", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, "output": 16384 } }, - "accounts/fireworks/models/glm-4p7": { - "id": "accounts/fireworks/models/glm-4p7", - "family": "glm", + "claude-opus-4-thinking:32000": { + "id": "claude-opus-4-thinking:32000", "reasoning": true, - "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 198000 - } - }, - "accounts/fireworks/models/glm-5": { - "id": "accounts/fireworks/models/glm-5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 131072 - } - }, - "accounts/fireworks/models/deepseek-v3p1": { - "id": "accounts/fireworks/models/deepseek-v3p1", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "accounts/fireworks/models/minimax-m2p1": { - "id": "accounts/fireworks/models/minimax-m2p1", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" + "text", + "image", + "pdf" ], "output": [ "text" @@ -18986,131 +2375,38 @@ }, "limit": { "context": 200000, - "output": 200000 + "input": 200000, + "output": 32000 } }, - "accounts/fireworks/models/glm-4p5-air": { - "id": "accounts/fireworks/models/glm-4p5-air", - "family": "glm-air", + "gemini-2.5-pro-preview-05-06": { + "id": "gemini-2.5-pro-preview-05-06", "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "accounts/fireworks/models/deepseek-v3p2": { - "id": "accounts/fireworks/models/deepseek-v3p2", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 160000, - "output": 160000 - } - }, - "accounts/fireworks/models/minimax-m2p5": { - "id": "accounts/fireworks/models/minimax-m2p5", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 196608 - } - }, - "accounts/fireworks/models/gpt-oss-120b": { - "id": "accounts/fireworks/models/gpt-oss-120b", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "accounts/fireworks/models/kimi-k2p5": { - "id": "accounts/fireworks/models/kimi-k2p5", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, "toolCall": true, "modalities": { "input": [ "text", "image", - "video" + "audio", + "video", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 256000, - "output": 256000 - } - }, - "accounts/fireworks/models/kimi-k2-thinking": { - "id": "accounts/fireworks/models/kimi-k2-thinking", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] + "context": 1048576, + "input": 1048756, + "output": 65536 }, - "limit": { - "context": 256000, - "output": 256000 - } + "family": "gemini-pro", + "temperature": true }, - "accounts/fireworks/models/glm-4p5": { - "id": "accounts/fireworks/models/glm-4p5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, + "grok-3-mini-fast-beta": { + "id": "grok-3-mini-fast-beta", + "reasoning": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -19121,32 +2417,13 @@ }, "limit": { "context": 131072, + "input": 131072, "output": 131072 } }, - "accounts/fireworks/models/gpt-oss-20b": { - "id": "accounts/fireworks/models/gpt-oss-20b", - "family": "gpt-oss", + "command-a-reasoning-08-2025": { + "id": "command-a-reasoning-08-2025", "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "step-3.5-flash": { - "id": "step-3.5-flash", - "reasoning": true, - "temperature": true, "toolCall": true, "modalities": { "input": [ @@ -19159,14 +2436,15 @@ "limit": { "context": 256000, "input": 256000, - "output": 256000 - } + "output": 32000 + }, + "family": "command-a", + "temperature": true }, - "step-2-16k": { - "id": "step-2-16k", - "reasoning": true, - "temperature": true, - "toolCall": true, + "brave": { + "id": "brave", + "reasoning": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -19176,16 +2454,33 @@ ] }, "limit": { - "context": 16384, - "input": 16384, + "context": 8192, + "input": 8192, "output": 8192 } }, - "step-1-32k": { - "id": "step-1-32k", - "reasoning": true, - "temperature": true, - "toolCall": true, + "exa-research": { + "id": "exa-research", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "llama-3.3-70b-nova": { + "id": "Llama-3.3-70B-Nova", + "reasoning": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -19197,13298 +2492,11 @@ "limit": { "context": 32768, "input": 32768, - "output": 32768 - } - }, - "duo-chat-gpt-5-2-codex": { - "id": "duo-chat-gpt-5-2-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "duo-chat-opus-4-6": { - "id": "duo-chat-opus-4-6", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "duo-chat-gpt-5-mini": { - "id": "duo-chat-gpt-5-mini", - "family": "gpt-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "duo-chat-gpt-5-3-codex": { - "id": "duo-chat-gpt-5-3-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "duo-chat-sonnet-4-5": { - "id": "duo-chat-sonnet-4-5", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "duo-chat-haiku-4-5": { - "id": "duo-chat-haiku-4-5", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "duo-chat-gpt-5-codex": { - "id": "duo-chat-gpt-5-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "duo-chat-gpt-5-4-nano": { - "id": "duo-chat-gpt-5-4-nano", - "family": "gpt-nano", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "duo-chat-gpt-5-2": { - "id": "duo-chat-gpt-5-2", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "duo-chat-gpt-5-4-mini": { - "id": "duo-chat-gpt-5-4-mini", - "family": "gpt-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "duo-chat-sonnet-4-6": { - "id": "duo-chat-sonnet-4-6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "duo-chat-gpt-5-4": { - "id": "duo-chat-gpt-5-4", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1050000, - "input": 922000, - "output": 128000 - } - }, - "duo-chat-opus-4-5": { - "id": "duo-chat-opus-4-5", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "duo-chat-gpt-5-1": { - "id": "duo-chat-gpt-5-1", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "nex-agi/deepseek-v3.1-nex-n1": { - "id": "nex-agi/deepseek-v3.1-nex-n1", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192, - "input": 128000 - } - }, - "deepseek-ai/deepseek-r1-distill-qwen-32b": { - "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 131000 - } - }, - "deepseek-ai/deepseek-r1-distill-qwen-14b": { - "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 131000 - } - }, - "deepseek-ai/deepseek-v3.2-exp": { - "id": "deepseek-ai/deepseek-v3.2-exp", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536, - "input": 163840 - } - }, - "deepseek-ai/deepseek-vl2": { - "id": "deepseek-ai/deepseek-vl2", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4000, - "output": 4000 - } - }, - "deepseek-ai/deepseek-v3": { - "id": "deepseek-ai/DeepSeek-V3", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "bytedance-seed/seed-oss-36b-instruct": { - "id": "ByteDance-Seed/Seed-OSS-36B-Instruct", - "family": "seed", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, - "output": 262000 - } - }, - "tencent/hunyuan-a13b-instruct": { - "id": "tencent/hunyuan-a13b-instruct", - "family": "hunyuan", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "tencent/hunyuan-mt-7b": { - "id": "tencent/Hunyuan-MT-7B", - "family": "hunyuan", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192, - "input": 8192 - } - }, - "inclusionai/ling-flash-2.0": { - "id": "inclusionAI/Ling-flash-2.0", - "family": "ling", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 131000 - } - }, - "inclusionai/ring-flash-2.0": { - "id": "inclusionAI/Ring-flash-2.0", - "family": "ring", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 131000 - } - }, - "inclusionai/ling-mini-2.0": { - "id": "inclusionAI/Ling-mini-2.0", - "family": "ling", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 131000 - } - }, - "baidu/ernie-4.5-300b-a47b": { - "id": "baidu/ernie-4.5-300b-a47b", - "family": "ernie", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384, - "input": 131072 - } - }, - "qwen/qwen3-vl-32b-instruct": { - "id": "qwen/qwen3-vl-32b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "qwen/qwen2.5-vl-7b-instruct": { - "id": "Qwen/Qwen2.5-VL-7B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 33000, - "output": 4000 - } - }, - "qwen/qwen2.5-32b-instruct": { - "id": "Qwen/Qwen2.5-32B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 33000, - "output": 4000 - } - }, - "qwen/qwen3-8b": { - "id": "qwen/qwen3-8b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 8192 - } - }, - "qwen/qwen2.5-14b-instruct": { - "id": "Qwen/Qwen2.5-14B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 33000, - "output": 4000 - } - }, - "qwen/qwen2.5-72b-instruct-128k": { - "id": "Qwen/Qwen2.5-72B-Instruct-128K", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 4000 - } - }, - "qwen/qwen3-omni-30b-a3b-captioner": { - "id": "Qwen/Qwen3-Omni-30B-A3B-Captioner", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 66000, - "output": 66000 - } - }, - "qwen/qwen3-vl-8b-thinking": { - "id": "qwen/qwen3-vl-8b-thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "qwen/qwen3-vl-32b-thinking": { - "id": "Qwen/Qwen3-VL-32B-Thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, - "output": 262000 - } - }, - "qwen/qwen3-14b": { - "id": "Qwen/Qwen3-14B", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 40960 - } - }, - "thudm/glm-4-32b-0414": { - "id": "THUDM/GLM-4-32B-0414", - "family": "glm", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 65536, - "input": 128000 - } - }, - "thudm/glm-4-9b-0414": { - "id": "THUDM/GLM-4-9B-0414", - "family": "glm", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 8000, - "input": 32000 - } - }, - "thudm/glm-z1-32b-0414": { - "id": "THUDM/GLM-Z1-32B-0414", - "family": "glm-z", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 65536, - "input": 128000 - } - }, - "thudm/glm-z1-9b-0414": { - "id": "THUDM/GLM-Z1-9B-0414", - "family": "glm-z", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 8000, - "input": 32000 - } - }, - "essentialai/rnj-1-instruct": { - "id": "essentialai/rnj-1-instruct", - "family": "rnj", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192, - "input": 128000 - } - }, - "deepseek-ai/deepseek-v3-1": { - "id": "deepseek-ai/DeepSeek-V3-1", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "qwen/qwen3-235b-a22b-instruct-2507-tput": { - "id": "Qwen/Qwen3-235B-A22B-Instruct-2507-tput", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen/qwen3-coder-next-fp8": { - "id": "Qwen/Qwen3-Coder-Next-FP8", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "minimaxai/chat-completion/models/minimax-m2_5-high-throughput": { - "id": "minimaxai/chat-completion/models/MiniMax-M2_5-high-throughput", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "arcee_ai/afm/models/trinity-mini": { - "id": "arcee_ai/AFM/models/trinity-mini", - "family": "trinity-mini", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "deepseek-ai/deepseek-ocr/models/deepseek-ocr": { - "id": "deepseek-ai/deepseek-ocr/models/DeepSeek-OCR", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "clarifai/main/models/mm-poly-8b": { - "id": "clarifai/main/models/mm-poly-8b", - "family": "mm-poly", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 4096 - } - }, - "qwen/qwencoder/models/qwen3-coder-30b-a3b-instruct": { - "id": "qwen/qwenCoder/models/Qwen3-Coder-30B-A3B-Instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "qwen/qwenlm/models/qwen3-30b-a3b-instruct-2507": { - "id": "qwen/qwenLM/models/Qwen3-30B-A3B-Instruct-2507", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen/qwenlm/models/qwen3-30b-a3b-thinking-2507": { - "id": "qwen/qwenLM/models/Qwen3-30B-A3B-Thinking-2507", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "mistralai/completion/models/ministral-3-14b-reasoning-2512": { - "id": "mistralai/completion/models/Ministral-3-14B-Reasoning-2512", - "family": "ministral", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "mistralai/completion/models/ministral-3-3b-reasoning-2512": { - "id": "mistralai/completion/models/Ministral-3-3B-Reasoning-2512", - "family": "ministral", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "openai/chat-completion/models/gpt-oss-120b-high-throughput": { - "id": "openai/chat-completion/models/gpt-oss-120b-high-throughput", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, "output": 16384 } }, - "openai/chat-completion/models/gpt-oss-20b": { - "id": "openai/chat-completion/models/gpt-oss-20b", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "baai/bge-reranker-v2-m3": { - "id": "BAAI/bge-reranker-v2-m3", - "family": "bge", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 512, - "output": 512 - } - }, - "intfloat/multilingual-e5-large": { - "id": "intfloat/multilingual-e5-large", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 512, - "output": 1024 - } - }, - "mistralai/mistral-small-3.2-24b-instruct-2506": { - "id": "mistralai/Mistral-Small-3.2-24B-Instruct-2506", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 8192 - } - }, - "lucidquery-nexus-coder": { - "id": "lucidquery-nexus-coder", - "family": "lucid", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 250000, - "output": 60000 - } - }, - "lucidnova-rf1-100b": { - "id": "lucidnova-rf1-100b", - "family": "nova", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 120000, - "output": 8000 - } - }, - "glm-4.6v-flash": { - "id": "glm-4.6v-flash", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "deepseek-reasoner": { - "id": "deepseek-reasoner", - "family": "deepseek-thinking", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 65536, - "input": 64000 - } - }, - "deepseek-chat": { - "id": "deepseek-chat", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192, - "input": 128000 - } - }, - "qwen/qwen3-30b-a3b-2507": { - "id": "qwen/qwen3-30b-a3b-2507", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 16384 - } - }, - "qwen/qwen3-coder-30b": { - "id": "qwen/qwen3-coder-30b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "prime-intellect/intellect-3": { - "id": "prime-intellect/intellect-3", - "family": "intellect", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "nvidia/nemotron-nano-9b-v2:free": { - "id": "nvidia/nemotron-nano-9b-v2:free", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "nvidia/nemotron-nano-12b-v2-vl:free": { - "id": "nvidia/nemotron-nano-12b-v2-vl:free", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "nvidia/nemotron-3-nano-30b-a3b:free": { - "id": "nvidia/nemotron-3-nano-30b-a3b:free", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "nvidia/nemotron-nano-9b-v2": { - "id": "nvidia/nemotron-nano-9b-v2", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "nvidia/nemotron-3-super-120b-a12b-free": { - "id": "nvidia/nemotron-3-super-120b-a12b-free", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "arcee-ai/trinity-large-preview:free": { - "id": "arcee-ai/trinity-large-preview:free", - "family": "trinity", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 26200 - } - }, - "arcee-ai/trinity-mini:free": { - "id": "arcee-ai/trinity-mini:free", - "family": "trinity-mini", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "liquid/lfm-2.5-1.2b-thinking:free": { - "id": "liquid/lfm-2.5-1.2b-thinking:free", - "family": "liquid", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "liquid/lfm-2.5-1.2b-instruct:free": { - "id": "liquid/lfm-2.5-1.2b-instruct:free", - "family": "liquid", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "inception/mercury-2": { - "id": "inception/mercury-2", - "family": "mercury", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 50000 - } - }, - "inception/mercury": { - "id": "inception/mercury", - "family": "mercury", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "inception/mercury-coder": { - "id": "inception/mercury-coder", - "family": "mercury", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "sourceful/riverflow-v2-fast-preview": { - "id": "sourceful/riverflow-v2-fast-preview", - "family": "sourceful", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "sourceful/riverflow-v2-max-preview": { - "id": "sourceful/riverflow-v2-max-preview", - "family": "sourceful", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "sourceful/riverflow-v2-standard-preview": { - "id": "sourceful/riverflow-v2-standard-preview", - "family": "sourceful", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "stepfun/step-3.5-flash:free": { - "id": "stepfun/step-3.5-flash:free", - "family": "step", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "cognitivecomputations/dolphin-mistral-24b-venice-edition:free": { - "id": "cognitivecomputations/dolphin-mistral-24b-venice-edition:free", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "deepseek/deepseek-v3.1-terminus:exacto": { - "id": "deepseek/deepseek-v3.1-terminus:exacto", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "deepseek/deepseek-v3.2-speciale": { - "id": "deepseek/deepseek-v3.2-speciale", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163000, - "output": 65536, - "input": 163000 - } - }, - "deepseek/deepseek-chat-v3.1": { - "id": "deepseek/deepseek-chat-v3.1", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 7168 - } - }, - "deepseek/deepseek-chat-v3-0324": { - "id": "deepseek/deepseek-chat-v3-0324", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "openrouter/free": { - "id": "openrouter/free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32768 - } - }, - "moonshotai/kimi-k2-0905:exacto": { - "id": "moonshotai/kimi-k2-0905:exacto", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 16384 - } - }, - "moonshotai/kimi-k2:free": { - "id": "moonshotai/kimi-k2:free", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32800, - "output": 32800 - } - }, - "google/gemini-2.5-flash-lite-preview-09-2025": { - "id": "google/gemini-2.5-flash-lite-preview-09-2025", - "family": "gemini-flash-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "google/gemini-3.1-pro-preview-customtools": { - "id": "google/gemini-3.1-pro-preview-customtools", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "google/gemini-2.5-pro-preview-06-05": { - "id": "google/gemini-2.5-pro-preview-06-05", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "google/gemma-3n-e4b-it:free": { - "id": "google/gemma-3n-e4b-it:free", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2000 - } - }, - "google/gemini-2.5-flash-preview-09-2025": { - "id": "google/gemini-2.5-flash-preview-09-2025", - "family": "gemini-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "google/gemini-2.5-pro-preview-05-06": { - "id": "google/gemini-2.5-pro-preview-05-06", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65535 - } - }, - "google/gemma-3n-e2b-it:free": { - "id": "google/gemma-3n-e2b-it:free", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2000 - } - }, - "google/gemini-2.0-flash-001": { - "id": "google/gemini-2.0-flash-001", - "family": "gemini-flash", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 8192 - } - }, - "google/gemma-3-12b-it:free": { - "id": "google/gemma-3-12b-it:free", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 8192 - } - }, - "google/gemma-2-9b-it": { - "id": "google/gemma-2-9b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1639 - } - }, - "google/gemma-3-4b-it:free": { - "id": "google/gemma-3-4b-it:free", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 8192 - } - }, - "google/gemma-3-4b-it": { - "id": "google/gemma-3-4b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 19200 - } - }, - "google/gemma-3-27b-it:free": { - "id": "google/gemma-3-27b-it:free", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "z-ai/glm-4.6:exacto": { - "id": "z-ai/glm-4.6:exacto", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000 - } - }, - "z-ai/glm-4.7-flash": { - "id": "z-ai/glm-4.7-flash", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 40551 - } - }, - "z-ai/glm-4.5-air:free": { - "id": "z-ai/glm-4.5-air:free", - "family": "glm-air", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 96000 - } - }, - "z-ai/glm-4.5v": { - "id": "z-ai/glm-4.5v", - "family": "glmv", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 96000, - "input": 64000 - } - }, - "qwen/qwen3-coder:free": { - "id": "qwen/qwen3-coder:free", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 66536 - } - }, - "qwen/qwen3-coder-flash": { - "id": "qwen/qwen3-coder-flash", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65536 - } - }, - "qwen/qwen3-coder:exacto": { - "id": "qwen/qwen3-coder:exacto", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "qwen/qwen-2.5-coder-32b-instruct": { - "id": "qwen/qwen-2.5-coder-32b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 8192 - } - }, - "qwen/qwen3.5-plus-02-15": { - "id": "qwen/qwen3.5-plus-02-15", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65536 - } - }, - "qwen/qwen3-235b-a22b-07-25": { - "id": "qwen/qwen3-235b-a22b-07-25", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "qwen/qwen3-next-80b-a3b-instruct:free": { - "id": "qwen/qwen3-next-80b-a3b-instruct:free", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen/qwen3-4b:free": { - "id": "qwen/qwen3-4b:free", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 40960 - } - }, - "x-ai/grok-3": { - "id": "x-ai/grok-3", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "x-ai/grok-3-mini-beta": { - "id": "x-ai/grok-3-mini-beta", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "x-ai/grok-3-mini": { - "id": "x-ai/grok-3-mini", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "x-ai/grok-4.20-multi-agent-beta": { - "id": "x-ai/grok-4.20-multi-agent-beta", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 32768 - } - }, - "x-ai/grok-4.20-beta": { - "id": "x-ai/grok-4.20-beta", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 32768 - } - }, - "x-ai/grok-3-beta": { - "id": "x-ai/grok-3-beta", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "meta-llama/llama-3.3-70b-instruct:free": { - "id": "meta-llama/llama-3.3-70b-instruct:free", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "meta-llama/llama-3.2-11b-vision-instruct": { - "id": "meta-llama/llama-3.2-11b-vision-instruct", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "meta-llama/llama-3.2-3b-instruct:free": { - "id": "meta-llama/llama-3.2-3b-instruct:free", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "mistralai/devstral-medium-2507": { - "id": "mistralai/devstral-medium-2507", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "mistralai/mistral-medium-3": { - "id": "mistralai/mistral-medium-3", - "family": "mistral-medium", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768, - "input": 131072 - } - }, - "mistralai/codestral-2508": { - "id": "mistralai/codestral-2508", - "family": "codestral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32768, - "input": 256000 - } - }, - "mistralai/mistral-small-3.1-24b-instruct": { - "id": "mistralai/mistral-small-3.1-24b-instruct", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 131072 - } - }, - "mistralai/devstral-2512": { - "id": "mistralai/devstral-2512", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "mistralai/mistral-small-3.2-24b-instruct": { - "id": "mistralai/mistral-small-3.2-24b-instruct", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "mistralai/devstral-small-2507": { - "id": "mistralai/devstral-small-2507", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "mistralai/mistral-medium-3.1": { - "id": "mistralai/mistral-medium-3.1", - "family": "mistral-medium", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768, - "input": 131072 - } - }, - "openai/gpt-oss-120b:exacto": { - "id": "openai/gpt-oss-120b:exacto", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "openai/gpt-5.2-chat": { - "id": "openai/gpt-5.2-chat", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 16384, - "input": 400000 - } - }, - "openai/gpt-5-image": { - "id": "openai/gpt-5-image", - "family": "gpt", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "image", - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "openai/gpt-oss-20b:free": { - "id": "openai/gpt-oss-20b:free", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "openai/gpt-oss-safeguard-20b": { - "id": "openai/gpt-oss-safeguard-20b", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - } - }, - "openai/gpt-oss-120b:free": { - "id": "openai/gpt-oss-120b:free", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "minimax/minimax-m1": { - "id": "minimax/minimax-m1", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 40000 - } - }, - "minimax/minimax-01": { - "id": "minimax/minimax-01", - "family": "minimax", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000192, - "output": 16384, - "input": 1000192 - } - }, - "bytedance-seed/seedream-4.5": { - "id": "bytedance-seed/seedream-4.5", - "family": "seed", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 4096, - "output": 4096 - } - }, - "black-forest-labs/flux.2-pro": { - "id": "black-forest-labs/flux.2-pro", - "family": "flux", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 46864, - "output": 46864 - } - }, - "black-forest-labs/flux.2-flex": { - "id": "black-forest-labs/flux.2-flex", - "family": "flux", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 67344, - "output": 67344 - } - }, - "black-forest-labs/flux.2-max": { - "id": "black-forest-labs/flux.2-max", - "family": "flux", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 46864, - "output": 46864 - } - }, - "black-forest-labs/flux.2-klein-4b": { - "id": "black-forest-labs/flux.2-klein-4b", - "family": "flux", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 40960, - "output": 40960 - } - }, - "nousresearch/hermes-3-llama-3.1-405b:free": { - "id": "nousresearch/hermes-3-llama-3.1-405b:free", - "family": "hermes", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "ai21-labs/ai21-jamba-1.5-mini": { - "id": "ai21-labs/ai21-jamba-1.5-mini", - "family": "jamba", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 4096 - } - }, - "ai21-labs/ai21-jamba-1.5-large": { - "id": "ai21-labs/ai21-jamba-1.5-large", - "family": "jamba", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 4096 - } - }, - "microsoft/mai-ds-r1": { - "id": "microsoft/mai-ds-r1", - "family": "mai", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 8192 - } - }, - "microsoft/phi-3.5-mini-instruct": { - "id": "microsoft/phi-3.5-mini-instruct", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "microsoft/phi-4": { - "id": "microsoft/phi-4", - "family": "phi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "microsoft/phi-3-mini-4k-instruct": { - "id": "microsoft/phi-3-mini-4k-instruct", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 1024 - } - }, - "microsoft/phi-4-mini-reasoning": { - "id": "microsoft/phi-4-mini-reasoning", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "microsoft/phi-3-mini-128k-instruct": { - "id": "microsoft/phi-3-mini-128k-instruct", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "microsoft/phi-4-reasoning": { - "id": "microsoft/phi-4-reasoning", - "family": "phi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "core42/jais-30b-chat": { - "id": "core42/jais-30b-chat", - "family": "jais", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - } - }, - "mistral-ai/ministral-3b": { - "id": "mistral-ai/ministral-3b", - "family": "ministral", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "mistral-ai/mistral-medium-2505": { - "id": "mistral-ai/mistral-medium-2505", - "family": "mistral-medium", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "mistral-ai/mistral-nemo": { - "id": "mistral-ai/mistral-nemo", - "family": "mistral-nemo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "mistral-ai/mistral-large-2411": { - "id": "mistral-ai/mistral-large-2411", - "family": "mistral-large", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "mistral-ai/mistral-small-2503": { - "id": "mistral-ai/mistral-small-2503", - "family": "mistral-small", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "mistral-ai/codestral-2501": { - "id": "mistral-ai/codestral-2501", - "family": "codestral", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 8192 - } - }, - "deepseek/deepseek-r1": { - "id": "deepseek/deepseek-r1", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 16000 - } - }, - "meta/llama-3.2-90b-vision-instruct": { - "id": "meta/llama-3.2-90b-vision-instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "meta/meta-llama-3.1-405b-instruct": { - "id": "meta/meta-llama-3.1-405b-instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "meta/meta-llama-3-8b-instruct": { - "id": "meta/meta-llama-3-8b-instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - } - }, - "meta/meta-llama-3-70b-instruct": { - "id": "meta/meta-llama-3-70b-instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 2048 - } - }, - "meta/meta-llama-3.1-70b-instruct": { - "id": "meta/meta-llama-3.1-70b-instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "meta/meta-llama-3.1-8b-instruct": { - "id": "meta/meta-llama-3.1-8b-instruct", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "meta/llama-4-maverick-17b-128e-instruct-fp8": { - "id": "meta/llama-4-maverick-17b-128e-instruct-fp8", - "family": "llama", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "openai/o1-preview": { - "id": "openai/o1-preview", - "family": "o", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768, - "input": 128000 - } - }, - "openai/o1-mini": { - "id": "openai/o1-mini", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 65536 - } - }, - "cohere/cohere-command-a": { - "id": "cohere/cohere-command-a", - "family": "command-a", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "cohere/cohere-command-r-plus-08-2024": { - "id": "cohere/cohere-command-r-plus-08-2024", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "cohere/cohere-command-r": { - "id": "cohere/cohere-command-r", - "family": "command-r", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "cohere/cohere-command-r-08-2024": { - "id": "cohere/cohere-command-r-08-2024", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "cohere/cohere-command-r-plus": { - "id": "cohere/cohere-command-r-plus", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "qwen-max-latest": { - "id": "qwen-max-latest", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen3-max-2025-09-23": { - "id": "qwen3-max-2025-09-23", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 258048, - "output": 65536 - } - }, - "gemini-2.5-flash-lite-preview-09-2025": { - "id": "gemini-2.5-flash-lite-preview-09-2025", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - }, - "family": "gemini-flash-lite" - }, - "claude-opus-4-1-20250805-thinking": { - "id": "claude-opus-4-1-20250805-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "gemini-2.5-flash-preview-09-2025": { - "id": "gemini-2.5-flash-preview-09-2025", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - }, - "family": "gemini-flash" - }, - "grok-4-1-fast-reasoning": { - "id": "grok-4-1-fast-reasoning", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192, - "input": 128000 - }, - "family": "grok" - }, - "kimi-k2-0905-preview": { - "id": "kimi-k2-0905-preview", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - }, - "family": "kimi" - }, - "claude-sonnet-4-5-20250929-thinking": { - "id": "claude-sonnet-4-5-20250929-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000, - "input": 1000000 - } - }, - "doubao-seed-1-6-vision-250815": { - "id": "doubao-seed-1-6-vision-250815", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "doubao-seed-1-6-thinking-250715": { - "id": "doubao-seed-1-6-thinking-250715", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 16000 - } - }, - "doubao-seed-1-8-251215": { - "id": "doubao-seed-1-8-251215", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192, - "input": 128000 - } - }, - "ministral-14b-2512": { - "id": "ministral-14b-2512", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "gemini-2.5-flash-nothink": { - "id": "gemini-2.5-flash-nothink", - "family": "gemini-flash", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65536 - } - }, - "claude-opus-4-5-20251101-thinking": { - "id": "claude-opus-4-5-20251101-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "gemini-3-pro-image-preview": { - "id": "gemini-3-pro-image-preview", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - } - }, - "gpt-5-thinking": { - "id": "gpt-5-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "deepseek-v3.2-thinking": { - "id": "deepseek-v3.2-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "chatgpt-4o-latest": { - "id": "chatgpt-4o-latest", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "kimi-k2-thinking-turbo": { - "id": "kimi-k2-thinking-turbo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - }, - "family": "kimi-thinking" - }, - "doubao-seed-code-preview-251028": { - "id": "doubao-seed-code-preview-251028", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "grok-4.1": { - "id": "grok-4.1", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-sonnet-4.6": { - "id": "claude-sonnet-4.6", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 128000, - "output": 32000 - } - }, - "claude-haiku-4.5": { - "id": "claude-haiku-4.5", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 144000, - "input": 128000, - "output": 32000 - } - }, - "claude-opus-4.5": { - "id": "claude-opus-4.5", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 160000, - "input": 128000, - "output": 32000 - } - }, - "claude-sonnet-4.5": { - "id": "claude-sonnet-4.5", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 144000, - "input": 128000, - "output": 32000 - } - }, - "claude-opus-4.6": { - "id": "claude-opus-4.6", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 144000, - "input": 128000, - "output": 64000 - } - }, - "claude-opus-41": { - "id": "claude-opus-41", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 80000, - "output": 16000 - } - }, - "kimi-k2-0711-preview": { - "id": "kimi-k2-0711-preview", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "gemini-embedding-001": { - "id": "gemini-embedding-001", - "family": "gemini", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2048, - "output": 3072 - } - }, - "gemini-3.1-pro-preview-customtools": { - "id": "gemini-3.1-pro-preview-customtools", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "gemini-2.5-pro-preview-06-05": { - "id": "gemini-2.5-pro-preview-06-05", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - } - }, - "gemini-2.5-flash-preview-04-17": { - "id": "gemini-2.5-flash-preview-04-17", - "family": "gemini-flash", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - } - }, - "gemini-2.5-pro-preview-05-06": { - "id": "gemini-2.5-pro-preview-05-06", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - } - }, - "gemini-2.5-flash-preview-05-20": { - "id": "gemini-2.5-flash-preview-05-20", - "family": "gemini-flash", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048000, - "output": 65536, - "input": 1048000 - } - }, - "gemini-flash-latest": { - "id": "gemini-flash-latest", - "family": "gemini-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "gemini-2.5-flash-lite-preview-06-17": { - "id": "gemini-2.5-flash-lite-preview-06-17", - "family": "gemini-flash-lite", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 - } - }, - "gemini-flash-lite-latest": { - "id": "gemini-flash-lite-latest", - "family": "gemini-flash-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "zai-org/glm-5-maas": { - "id": "zai-org/glm-5-maas", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 131072 - } - }, - "zai-org/glm-4.7-maas": { - "id": "zai-org/glm-4.7-maas", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000 - } - }, - "deepseek-ai/deepseek-v3.1-maas": { - "id": "deepseek-ai/deepseek-v3.1-maas", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 32768 - } - }, - "qwen/qwen3-235b-a22b-instruct-2507-maas": { - "id": "qwen/qwen3-235b-a22b-instruct-2507-maas", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 16384 - } - }, - "meta/llama-4-maverick-17b-128e-instruct-maas": { - "id": "meta/llama-4-maverick-17b-128e-instruct-maas", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 524288, - "output": 8192 - } - }, - "meta/llama-3.3-70b-instruct-maas": { - "id": "meta/llama-3.3-70b-instruct-maas", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "openai/gpt-oss-20b-maas": { - "id": "openai/gpt-oss-20b-maas", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "openai/gpt-oss-120b-maas": { - "id": "openai/gpt-oss-120b-maas", - "family": "gpt-oss", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "gemma-3-27b": { - "id": "gemma-3-27b", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "qwen3-embedding-4b": { - "id": "qwen3-embedding-4b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 2560 - } - }, - "qwen3-coder-30b-a3b": { - "id": "qwen3-coder-30b-a3b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "gemini-3.1-flash-image-preview": { - "id": "gemini-3.1-flash-image-preview", - "family": "gemini-flash", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "gemini-live-2.5-flash": { - "id": "gemini-live-2.5-flash", - "family": "gemini-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text", - "audio" - ] - }, - "limit": { - "context": 128000, - "output": 8000 - } - }, - "gemini-live-2.5-flash-preview-native-audio": { - "id": "gemini-live-2.5-flash-preview-native-audio", - "family": "gemini-flash", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "audio", - "video" - ], - "output": [ - "text", - "audio" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "gemini-2.5-flash-preview-tts": { - "id": "gemini-2.5-flash-preview-tts", - "family": "gemini-flash", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "audio" - ] - }, - "limit": { - "context": 8000, - "output": 16000 - } - }, - "gemini-2.5-pro-preview-tts": { - "id": "gemini-2.5-pro-preview-tts", - "family": "gemini-flash", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "audio" - ] - }, - "limit": { - "context": 8000, - "output": 16000 - } - }, - "gemini-2.5-flash-image-preview": { - "id": "gemini-2.5-flash-image-preview", - "family": "gemini-flash", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "gemini-1.5-flash-8b": { - "id": "gemini-1.5-flash-8b", - "family": "gemini-flash", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 8192 - } - }, - "gemini-1.5-flash": { - "id": "gemini-1.5-flash", - "family": "gemini-flash", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 8192 - } - }, - "gemini-1.5-pro": { - "id": "gemini-1.5-pro", - "family": "gemini-pro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "audio", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 8192 - } - }, - "anthropic--claude-4.5-opus": { - "id": "anthropic--claude-4.5-opus", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic--claude-4-sonnet": { - "id": "anthropic--claude-4-sonnet", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic--claude-4.5-sonnet": { - "id": "anthropic--claude-4.5-sonnet", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic--claude-3-sonnet": { - "id": "anthropic--claude-3-sonnet", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "anthropic--claude-3.7-sonnet": { - "id": "anthropic--claude-3.7-sonnet", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "sonar": { - "id": "sonar", - "family": "sonar", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 127000, - "output": 128000, - "input": 127000 - } - }, - "anthropic--claude-3.5-sonnet": { - "id": "anthropic--claude-3.5-sonnet", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "sonar-deep-research": { - "id": "sonar-deep-research", - "family": "sonar-deep-research", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 60000, - "output": 128000, - "input": 60000 - } - }, - "anthropic--claude-4.6-sonnet": { - "id": "anthropic--claude-4.6-sonnet", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "anthropic--claude-4.5-haiku": { - "id": "anthropic--claude-4.5-haiku", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "anthropic--claude-3-opus": { - "id": "anthropic--claude-3-opus", - "family": "claude-opus", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "sonar-pro": { - "id": "sonar-pro", - "family": "sonar-pro", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000, - "input": 200000 - } - }, - "anthropic--claude-3-haiku": { - "id": "anthropic--claude-3-haiku", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "anthropic--claude-4.6-opus": { - "id": "anthropic--claude-4.6-opus", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "anthropic--claude-4-opus": { - "id": "anthropic--claude-4-opus", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "google-gemma-3-27b-it": { - "id": "google-gemma-3-27b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 16384 - } - }, - "openai-gpt-4o-2024-11-20": { - "id": "openai-gpt-4o-2024-11-20", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "claude-opus-45": { - "id": "claude-opus-45", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 49500 - } - }, - "zai-org-glm-5": { - "id": "zai-org-glm-5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 32000 - } - }, - "zai-org-glm-4.7": { - "id": "zai-org-glm-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 16384 - } - }, - "zai-org-glm-4.6": { - "id": "zai-org-glm-4.6", - "family": "glm", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 16384 - } - }, - "openai-gpt-53-codex": { - "id": "openai-gpt-53-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "kimi-k2-5": { - "id": "kimi-k2-5", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536 - } - }, - "mistral-small-3-2-24b-instruct": { - "id": "mistral-small-3-2-24b-instruct", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 16384 - } - }, - "mistral-31-24b": { - "id": "mistral-31-24b", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "grok-4-20-multi-agent-beta": { - "id": "grok-4-20-multi-agent-beta", - "family": "grok-beta", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 128000 - } - }, - "openai-gpt-54-pro": { - "id": "openai-gpt-54-pro", - "family": "gpt-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "qwen3-4b": { - "id": "qwen3-4b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 4096 - } - }, - "grok-4-20-beta": { - "id": "grok-4-20-beta", - "family": "grok-beta", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 128000 - } - }, - "olafangensan-glm-4.7-flash-heretic": { - "id": "olafangensan-glm-4.7-flash-heretic", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 24000 - } - }, - "minimax-m25": { - "id": "minimax-m25", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 32768 - } - }, - "zai-org-glm-4.7-flash": { - "id": "zai-org-glm-4.7-flash", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "qwen3-coder-480b-a35b-instruct-turbo": { - "id": "qwen3-coder-480b-a35b-instruct-turbo", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536 - } - }, - "openai-gpt-oss-120b": { - "id": "openai-gpt-oss-120b", - "family": "gpt-oss", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "grok-41-fast": { - "id": "grok-41-fast", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 30000 - } - }, - "openai-gpt-52": { - "id": "openai-gpt-52", - "family": "gpt", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536 - } - }, - "openai-gpt-54": { - "id": "openai-gpt-54", - "family": "gpt", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 131072 - } - }, - "gemini-3-1-pro-preview": { - "id": "gemini-3-1-pro-preview", - "family": "gemini-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "audio", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "openai-gpt-4o-mini-2024-07-18": { - "id": "openai-gpt-4o-mini-2024-07-18", - "family": "gpt-mini", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "llama-3.3-70b": { - "id": "llama-3.3-70b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "qwen3-next-80b": { - "id": "qwen3-next-80b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 16384 - } - }, - "hermes-3-llama-3.1-405b": { - "id": "hermes-3-llama-3.1-405b", - "family": "hermes", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "qwen3-5-9b": { - "id": "qwen3-5-9b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536 - } - }, - "minimax-m21": { - "id": "minimax-m21", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 32768 - } - }, - "qwen3-5-35b-a3b": { - "id": "qwen3-5-35b-a3b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536 - } - }, - "llama-3.2-3b": { - "id": "llama-3.2-3b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "venice-uncensored": { - "id": "venice-uncensored", - "family": "venice", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - } - }, - "nvidia-nemotron-3-nano-30b-a3b": { - "id": "nvidia-nemotron-3-nano-30b-a3b", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "openai-gpt-52-codex": { - "id": "openai-gpt-52-codex", - "family": "gpt-codex", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536 - } - }, - "minimax-m27": { - "id": "minimax-m27", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 32768 - } - }, - "venice-uncensored-role-play": { - "id": "venice-uncensored-role-play", - "family": "venice", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "claude-sonnet-45": { - "id": "claude-sonnet-45", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 198000, - "output": 49500 - } - }, - "nova-2-lite-v1": { - "id": "nova-2-lite-v1", - "family": "nova-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "nova-2-pro-v1": { - "id": "nova-2-pro-v1", - "family": "nova-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "glm-4.7-flashx": { - "id": "glm-4.7-flashx", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 131072 - } - }, - "public/deepseek-v3": { - "id": "public/deepseek-v3", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "public/deepseek-r1": { - "id": "public/deepseek-r1", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32000 - } - }, - "public/minimax-m25": { - "id": "public/minimax-m25", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "gpt-5-4": { - "id": "gpt-5-4", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 272000, - "output": 128000 - } - }, - "deepseek-v3-2": { - "id": "deepseek-v3-2", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "minimax-m2-5": { - "id": "minimax-m2-5", - "family": "minimax", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 192000, - "output": 8192 - } - }, - "gpt-5-3-codex": { - "id": "gpt-5-3-codex", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "meta-llama-3_3-70b-instruct": { - "id": "meta-llama-3_3-70b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "mistral-7b-instruct-v0.3": { - "id": "mistral-7b-instruct-v0.3", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 65536 - } - }, - "qwen2.5-coder-32b-instruct": { - "id": "qwen2.5-coder-32b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "mixtral-8x7b-instruct-v0.1": { - "id": "mixtral-8x7b-instruct-v0.1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "neuralmagic/meta-llama-3.1-8b-instruct-fp8": { - "id": "neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "neuralmagic/mistral-nemo-instruct-2407-fp8": { - "id": "neuralmagic/Mistral-Nemo-Instruct-2407-FP8", - "family": "mistral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "qwen/qwen3-vl-embedding-8b": { - "id": "Qwen/Qwen3-VL-Embedding-8B", - "family": "qwen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 4096 - } - }, - "qwen/qwen3-vl-235b-a22b-instruct-fp8": { - "id": "Qwen/Qwen3-VL-235B-A22B-Instruct-FP8", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 218000, - "output": 8192 - } - }, - "cortecs/llama-3.3-70b-instruct-fp8-dynamic": { - "id": "cortecs/Llama-3.3-70B-Instruct-FP8-Dynamic", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "speakleash/bielik-11b-v2.6-instruct": { - "id": "speakleash/Bielik-11B-v2.6-Instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 32000 - } - }, - "speakleash/bielik-11b-v3.0-instruct": { - "id": "speakleash/Bielik-11B-v3.0-Instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 32000 - } - }, - "anthropic/claude-3-7-sonnet": { - "id": "anthropic/claude-3-7-sonnet", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "xai/grok-4-fast": { - "id": "xai/grok-4-fast", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 64000 - } - }, - "pro/zai-org/glm-4.7": { - "id": "Pro/zai-org/GLM-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 205000, - "output": 205000 - } - }, - "pro/zai-org/glm-5": { - "id": "Pro/zai-org/GLM-5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 205000, - "output": 205000 - } - }, - "pro/minimaxai/minimax-m2.5": { - "id": "Pro/MiniMaxAI/MiniMax-M2.5", - "family": "minimax", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 192000, - "output": 131000 - } - }, - "pro/minimaxai/minimax-m2.1": { - "id": "Pro/MiniMaxAI/MiniMax-M2.1", - "family": "minimax", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 197000, - "output": 131000 - } - }, - "pro/deepseek-ai/deepseek-r1": { - "id": "Pro/deepseek-ai/DeepSeek-R1", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 164000, - "output": 164000 - } - }, - "pro/deepseek-ai/deepseek-v3.2": { - "id": "Pro/deepseek-ai/DeepSeek-V3.2", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 164000, - "output": 164000 - } - }, - "pro/deepseek-ai/deepseek-v3": { - "id": "Pro/deepseek-ai/DeepSeek-V3", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 164000, - "output": 164000 - } - }, - "pro/deepseek-ai/deepseek-v3.1-terminus": { - "id": "Pro/deepseek-ai/DeepSeek-V3.1-Terminus", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 164000, - "output": 164000 - } - }, - "pro/moonshotai/kimi-k2-instruct-0905": { - "id": "Pro/moonshotai/Kimi-K2-Instruct-0905", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, - "output": 262000 - } - }, - "pro/moonshotai/kimi-k2.5": { - "id": "Pro/moonshotai/Kimi-K2.5", - "family": "kimi", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, - "output": 262000 - } - }, - "pro/moonshotai/kimi-k2-thinking": { - "id": "Pro/moonshotai/Kimi-K2-Thinking", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, - "output": 262000 - } - }, - "paddlepaddle/paddleocr-vl-1.5": { - "id": "PaddlePaddle/PaddleOCR-VL-1.5", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384 - } - }, - "kwaipilot/kat-dev": { - "id": "Kwaipilot/KAT-Dev", - "family": "kat-coder", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "deepseek-ai/deepseek-ocr": { - "id": "deepseek-ai/DeepSeek-OCR", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "ascend-tribe/pangu-pro-moe": { - "id": "ascend-tribe/pangu-pro-moe", - "family": "pangu", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "qwen/qwen3.5-9b": { - "id": "qwen/qwen3.5-9b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32768 - } - }, - "qwen/qwen3.5-122b-a10b": { - "id": "qwen/qwen3.5-122b-a10b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "qwen/qwen3.5-35b-a3b": { - "id": "qwen/qwen3.5-35b-a3b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "qwen/qwen3.5-4b": { - "id": "Qwen/Qwen3.5-4B", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "qwen/qwen3.5-27b": { - "id": "qwen/qwen3.5-27b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "gpt-5-chat-latest": { - "id": "gpt-5-chat-latest", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000, - "input": 272000 - } - }, - "llama-4-scout": { - "id": "llama-4-scout", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "codex-mini-latest": { - "id": "codex-mini-latest", - "family": "gpt-codex-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "qwen2.5-coder-7b-fast": { - "id": "qwen2.5-coder-7b-fast", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 8192 - } - }, - "sonar-reasoning-pro": { - "id": "sonar-reasoning-pro", - "family": "sonar-reasoning", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 127000, - "output": 128000, - "input": 127000 - } - }, - "llama-3.1-8b-instruct-turbo": { - "id": "llama-3.1-8b-instruct-turbo", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "ernie-4.5-21b-a3b-thinking": { - "id": "ernie-4.5-21b-a3b-thinking", - "family": "ernie", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8000 - } - }, - "llama-prompt-guard-2-22m": { - "id": "llama-prompt-guard-2-22m", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 512, - "output": 2 - } - }, - "gpt-4.1-mini-2025-04-14": { - "id": "gpt-4.1-mini-2025-04-14", - "family": "gpt-mini", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1047576, - "output": 32768 - } - }, - "llama-guard-4": { - "id": "llama-guard-4", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 1024 - } - }, - "sonar-reasoning": { - "id": "sonar-reasoning", - "family": "sonar-reasoning", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 127000, - "output": 4096 - } - }, - "deepseek-v3.1-terminus": { - "id": "deepseek-v3.1-terminus", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "claude-3.5-sonnet-v2": { - "id": "claude-3.5-sonnet-v2", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "mistral-small": { - "id": "mistral-small", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "qwen3-vl-235b-a22b-instruct": { - "id": "qwen3-vl-235b-a22b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 16384 - } - }, - "qwen3-235b-a22b-thinking": { - "id": "qwen3-235b-a22b-thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 81920 - } - }, - "claude-3-haiku-20240307": { - "id": "claude-3-haiku-20240307", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "kimi-k2-0711": { - "id": "kimi-k2-0711", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "llama-4-maverick": { - "id": "llama-4-maverick", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "deepseek-tng-r1t2-chimera": { - "id": "deepseek-tng-r1t2-chimera", - "family": "deepseek-thinking", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 130000, - "output": 163840 - } - }, - "claude-opus-4": { - "id": "claude-opus-4", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "llama-prompt-guard-2-86m": { - "id": "llama-prompt-guard-2-86m", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 512, - "output": 2 - } - }, - "gemma-3-12b-it": { - "id": "gemma-3-12b-it", - "family": "gemma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "hermes-2-pro-llama-3-8b": { - "id": "hermes-2-pro-llama-3-8b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "zai/glm-5": { - "id": "zai/glm-5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202800, - "output": 131072 - } - }, - "zai/glm-4.7-flashx": { - "id": "zai/glm-4.7-flashx", - "family": "glm-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 128000 - } - }, - "zai/glm-4.5-air": { - "id": "zai/glm-4.5-air", - "family": "glm-air", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 96000 - } - }, - "zai/glm-4.5": { - "id": "zai/glm-4.5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "zai/glm-4.7-flash": { - "id": "zai/glm-4.7-flash", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 131000 - } - }, - "zai/glm-4.6": { - "id": "zai/glm-4.6", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 96000 - } - }, - "zai/glm-4.7": { - "id": "zai/glm-4.7", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 120000 - } - }, - "zai/glm-4.6v-flash": { - "id": "zai/glm-4.6v-flash", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 24000 - } - }, - "zai/glm-5-turbo": { - "id": "zai/glm-5-turbo", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202800, - "output": 131100 - } - }, - "zai/glm-4.5v": { - "id": "zai/glm-4.5v", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 66000, - "output": 66000 - } - }, - "zai/glm-4.6v": { - "id": "zai/glm-4.6v", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 24000 - } - }, - "nvidia/nemotron-nano-12b-v2-vl": { - "id": "nvidia/nemotron-nano-12b-v2-vl", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "arcee-ai/trinity-large-preview": { - "id": "arcee-ai/trinity-large-preview", - "family": "trinity", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 131000 - } - }, - "arcee-ai/trinity-mini": { - "id": "arcee-ai/trinity-mini", - "family": "trinity-mini", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192, - "input": 131072 - } - }, - "inception/mercury-coder-small": { - "id": "inception/mercury-coder-small", - "family": "mercury", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 16384 - } - }, - "voyage/voyage-3-large": { - "id": "voyage/voyage-3-large", - "family": "voyage", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "voyage/voyage-code-3": { - "id": "voyage/voyage-code-3", - "family": "voyage", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "voyage/voyage-law-2": { - "id": "voyage/voyage-law-2", - "family": "voyage", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "voyage/voyage-finance-2": { - "id": "voyage/voyage-finance-2", - "family": "voyage", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "voyage/voyage-code-2": { - "id": "voyage/voyage-code-2", - "family": "voyage", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "voyage/voyage-4-lite": { - "id": "voyage/voyage-4-lite", - "family": "voyage", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 0 - } - }, - "voyage/voyage-3.5-lite": { - "id": "voyage/voyage-3.5-lite", - "family": "voyage", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "voyage/voyage-4-large": { - "id": "voyage/voyage-4-large", - "family": "voyage", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 0 - } - }, - "voyage/voyage-3.5": { - "id": "voyage/voyage-3.5", - "family": "voyage", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "voyage/voyage-4": { - "id": "voyage/voyage-4", - "family": "voyage", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 0 - } - }, - "amazon/nova-2-lite": { - "id": "amazon/nova-2-lite", - "family": "nova", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 1000000 - } - }, - "amazon/titan-embed-text-v2": { - "id": "amazon/titan-embed-text-v2", - "family": "titan-embed", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "amazon/nova-lite": { - "id": "amazon/nova-lite", - "family": "nova-lite", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 300000, - "output": 8192 - } - }, - "amazon/nova-pro": { - "id": "amazon/nova-pro", - "family": "nova-pro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 300000, - "output": 8192 - } - }, - "amazon/nova-micro": { - "id": "amazon/nova-micro", - "family": "nova-micro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "alibaba/qwen-3-235b": { - "id": "alibaba/qwen-3-235b", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 16384 - } - }, - "alibaba/qwen3-max-preview": { - "id": "alibaba/qwen3-max-preview", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "alibaba/qwen3-next-80b-a3b-thinking": { - "id": "alibaba/qwen3-next-80b-a3b-thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "alibaba/qwen3-max-thinking": { - "id": "alibaba/qwen3-max-thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 65536 - } - }, - "alibaba/qwen3-vl-instruct": { - "id": "alibaba/qwen3-vl-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 129024 - } - }, - "alibaba/qwen3-embedding-8b": { - "id": "alibaba/qwen3-embedding-8b", - "family": "qwen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "alibaba/qwen3-coder-next": { - "id": "alibaba/qwen3-coder-next", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "alibaba/qwen3-coder": { - "id": "alibaba/qwen3-coder", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 66536 - } - }, - "alibaba/qwen-3-30b": { - "id": "alibaba/qwen-3-30b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 16384 - } - }, - "alibaba/qwen3-embedding-0.6b": { - "id": "alibaba/qwen3-embedding-0.6b", - "family": "qwen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "alibaba/qwen-3-14b": { - "id": "alibaba/qwen-3-14b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 16384 - } - }, - "alibaba/qwen3-235b-a22b-thinking": { - "id": "alibaba/qwen3-235b-a22b-thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262114, - "output": 262114 - } - }, - "alibaba/qwen3-vl-thinking": { - "id": "alibaba/qwen3-vl-thinking", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 129024 - } - }, - "alibaba/qwen3.5-flash": { - "id": "alibaba/qwen3.5-flash", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "alibaba/qwen3-next-80b-a3b-instruct": { - "id": "alibaba/qwen3-next-80b-a3b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "alibaba/qwen3.5-plus": { - "id": "alibaba/qwen3.5-plus", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000 - } - }, - "alibaba/qwen3-max": { - "id": "alibaba/qwen3-max", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "alibaba/qwen-3-32b": { - "id": "alibaba/qwen-3-32b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 16384 - } - }, - "alibaba/qwen3-coder-plus": { - "id": "alibaba/qwen3-coder-plus", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 1000000 - } - }, - "alibaba/qwen3-embedding-4b": { - "id": "alibaba/qwen3-embedding-4b", - "family": "qwen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "alibaba/qwen3-coder-30b-a3b": { - "id": "alibaba/qwen3-coder-30b-a3b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 160000, - "output": 32768 - } - }, - "bfl/flux-pro-1.0-fill": { - "id": "bfl/flux-pro-1.0-fill", - "family": "flux", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 512, - "output": 0 - } - }, - "bfl/flux-pro-1.1": { - "id": "bfl/flux-pro-1.1", - "family": "flux", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 512, - "output": 0 - } - }, - "bfl/flux-kontext-max": { - "id": "bfl/flux-kontext-max", - "family": "flux", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 512, - "output": 0 - } - }, - "bfl/flux-kontext-pro": { - "id": "bfl/flux-kontext-pro", - "family": "flux", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 512, - "output": 0 - } - }, - "bfl/flux-pro-1.1-ultra": { - "id": "bfl/flux-pro-1.1-ultra", - "family": "flux", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 512, - "output": 0 - } - }, - "mistral/codestral-embed": { - "id": "mistral/codestral-embed", - "family": "codestral-embed", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "mistral/devstral-small-2": { - "id": "mistral/devstral-small-2", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "mistral/devstral-2": { - "id": "mistral/devstral-2", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "mistral/mistral-large-3": { - "id": "mistral/mistral-large-3", - "family": "mistral-large", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "mistral/mistral-embed": { - "id": "mistral/mistral-embed", - "family": "mistral-embed", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "mistral/ministral-14b": { - "id": "mistral/ministral-14b", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 256000 - } - }, - "mistral/mistral-nemo": { - "id": "mistral/mistral-nemo", - "family": "mistral-nemo", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 60288, - "output": 16000 - } - }, - "mistral/mistral-medium": { - "id": "mistral/mistral-medium", - "family": "mistral-medium", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 64000 - } - }, - "mistral/devstral-small": { - "id": "mistral/devstral-small", - "family": "devstral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 64000 - } - }, - "mistral/codestral": { - "id": "mistral/codestral", - "family": "codestral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 4096 - } - }, - "mistral/mixtral-8x22b-instruct": { - "id": "mistral/mixtral-8x22b-instruct", - "family": "mixtral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "output": 64000 - } - }, - "mistral/mistral-small": { - "id": "mistral/mistral-small", - "family": "mistral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "mistral/ministral-8b": { - "id": "mistral/ministral-8b", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "mistral/pixtral-large": { - "id": "mistral/pixtral-large", - "family": "pixtral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "mistral/pixtral-12b": { - "id": "mistral/pixtral-12b", - "family": "pixtral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "mistral/magistral-small": { - "id": "mistral/magistral-small", - "family": "magistral-small", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "mistral/magistral-medium": { - "id": "mistral/magistral-medium", - "family": "magistral-medium", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "mistral/ministral-3b": { - "id": "mistral/ministral-3b", - "family": "ministral", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "kwaipilot/kat-coder-pro-v1": { - "id": "kwaipilot/kat-coder-pro-v1", - "family": "kat-coder", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "deepseek/deepseek-v3": { - "id": "deepseek/deepseek-v3", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 16384 - } - }, - "deepseek/deepseek-v3.2-thinking": { - "id": "deepseek/deepseek-v3.2-thinking", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 64000 - } - }, - "moonshotai/kimi-k2-turbo": { - "id": "moonshotai/kimi-k2-turbo", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 16384 - } - }, - "google/gemini-embedding-001": { - "id": "google/gemini-embedding-001", - "family": "gemini-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "google/imagen-4.0-fast-generate-001": { - "id": "google/imagen-4.0-fast-generate-001", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/text-embedding-005": { - "id": "google/text-embedding-005", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "google/imagen-4.0-ultra-generate-001": { - "id": "google/imagen-4.0-ultra-generate-001", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "google/gemini-3.1-flash-image-preview": { - "id": "google/gemini-3.1-flash-image-preview", - "family": "gemini", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image", - "text" - ] - }, - "limit": { - "context": 65536, - "output": 65536 - } - }, - "google/text-multilingual-embedding-002": { - "id": "google/text-multilingual-embedding-002", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "google/gemini-embedding-2": { - "id": "google/gemini-embedding-2", - "family": "gemini-embedding", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "google/gemini-2.5-flash-image": { - "id": "google/gemini-2.5-flash-image", - "family": "gemini-flash", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "image", - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "google/gemini-3-pro-image": { - "id": "google/gemini-3-pro-image", - "family": "gemini-pro", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 65536, - "output": 32768 - } - }, - "google/gemini-2.5-flash-image-preview": { - "id": "google/gemini-2.5-flash-image-preview", - "family": "gemini-flash", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "google/imagen-4.0-generate-001": { - "id": "google/imagen-4.0-generate-001", - "family": "imagen", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 480, - "output": 0 - } - }, - "meituan/longcat-flash-thinking": { - "id": "meituan/longcat-flash-thinking", - "family": "longcat", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "meituan/longcat-flash-thinking-2601": { - "id": "meituan/longcat-flash-thinking-2601", - "family": "longcat", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "bytedance/seed-1.6": { - "id": "bytedance/seed-1.6", - "family": "seed", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "bytedance/seed-1.8": { - "id": "bytedance/seed-1.8", - "family": "seed", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 64000 - } - }, - "meta/llama-3.1-8b": { - "id": "meta/llama-3.1-8b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "meta/llama-3.2-11b": { - "id": "meta/llama-3.2-11b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "meta/llama-3.1-70b": { - "id": "meta/llama-3.1-70b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "meta/llama-3.2-90b": { - "id": "meta/llama-3.2-90b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "meta/llama-3.2-1b": { - "id": "meta/llama-3.2-1b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "meta/llama-3.2-3b": { - "id": "meta/llama-3.2-3b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192 - } - }, - "meta/llama-4-maverick": { - "id": "meta/llama-4-maverick", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "meta/llama-3.3-70b": { - "id": "meta/llama-3.3-70b", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "meta/llama-4-scout": { - "id": "meta/llama-4-scout", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "vercel/v0-1.5-md": { - "id": "vercel/v0-1.5-md", - "family": "v0", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "vercel/v0-1.0-md": { - "id": "vercel/v0-1.0-md", - "family": "v0", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32000 - } - }, - "openai/text-embedding-ada-002": { - "id": "openai/text-embedding-ada-002", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 6656, - "output": 1536 - } - }, - "openai/gpt-4o-mini-search-preview": { - "id": "openai/gpt-4o-mini-search-preview", - "family": "gpt-mini", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "openai/text-embedding-3-small": { - "id": "openai/text-embedding-3-small", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 6656, - "output": 1536 - } - }, - "openai/text-embedding-3-large": { - "id": "openai/text-embedding-3-large", - "family": "text-embedding", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 6656, - "output": 1536 - } - }, - "openai/gpt-5.1-thinking": { - "id": "openai/gpt-5.1-thinking", - "family": "gpt", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "openai/codex-mini": { - "id": "openai/codex-mini", - "family": "gpt-codex-mini", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 100000, - "output": 100000 - } - }, - "morph/morph-v3-large": { - "id": "morph/morph-v3-large", - "family": "morph", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "morph/morph-v3-fast": { - "id": "morph/morph-v3-fast", - "family": "morph", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 81920, - "output": 38000 - } - }, - "cohere/embed-v4.0": { - "id": "cohere/embed-v4.0", - "family": "cohere-embed", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 1536 - } - }, - "cohere/command-a": { - "id": "cohere/command-a", - "family": "command", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8192 - } - }, - "minimax/minimax-m2.1-lightning": { - "id": "minimax/minimax-m2.1-lightning", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "recraft/recraft-v2": { - "id": "recraft/recraft-v2", - "family": "recraft", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 512, - "output": 0 - } - }, - "recraft/recraft-v3": { - "id": "recraft/recraft-v3", - "family": "recraft", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 512, - "output": 0 - } - }, - "perplexity/sonar-reasoning-pro": { - "id": "perplexity/sonar-reasoning-pro", - "family": "sonar-reasoning", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 25600 - } - }, - "perplexity/sonar-reasoning": { - "id": "perplexity/sonar-reasoning", - "family": "sonar-reasoning", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 127000, - "output": 8000 - } - }, - "perplexity/sonar-pro": { - "id": "perplexity/sonar-pro", - "family": "sonar-pro", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8000 - } - }, - "anthropic/claude-3.5-sonnet-20240620": { - "id": "anthropic/claude-3.5-sonnet-20240620", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "xai/grok-4.20-non-reasoning-beta": { - "id": "xai/grok-4.20-non-reasoning-beta", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "xai/grok-4.20-non-reasoning": { - "id": "xai/grok-4.20-non-reasoning", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "xai/grok-imagine-image": { - "id": "xai/grok-imagine-image", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "xai/grok-4.20-reasoning": { - "id": "xai/grok-4.20-reasoning", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "xai/grok-4.20-reasoning-beta": { - "id": "xai/grok-4.20-reasoning-beta", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "xai/grok-4.20-multi-agent": { - "id": "xai/grok-4.20-multi-agent", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "xai/grok-imagine-image-pro": { - "id": "xai/grok-imagine-image-pro", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text", - "image" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "xai/grok-4.20-multi-agent-beta": { - "id": "xai/grok-4.20-multi-agent-beta", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 2000000 - } - }, - "xai/grok-3-fast": { - "id": "xai/grok-3-fast", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "xai/grok-3-mini-fast": { - "id": "xai/grok-3-mini-fast", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "xai/grok-2-vision": { - "id": "xai/grok-2-vision", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096 - } - }, - "gpt-4o-2024-05-13": { - "id": "gpt-4o-2024-05-13", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "o3-deep-research": { - "id": "o3-deep-research", - "family": "o", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "o4-mini-deep-research": { - "id": "o4-mini-deep-research", - "family": "o-mini", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "gpt-3.5-turbo": { - "id": "gpt-3.5-turbo", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16385, - "output": 4096 - } - }, - "o1-pro": { - "id": "o1-pro", - "family": "o-pro", - "reasoning": true, - "temperature": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000 - } - }, - "gpt-5.2-pro": { - "id": "gpt-5.2-pro", - "family": "gpt-pro", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 272000, - "output": 128000 - } - }, - "gpt-4o-2024-08-06": { - "id": "gpt-4o-2024-08-06", - "family": "gpt", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "auto": { - "id": "auto", - "family": "auto", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 32000 - } - }, - "morph-v3-fast": { - "id": "morph-v3-fast", - "family": "morph", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "output": 16000 - } - }, - "morph-v3-large": { - "id": "morph-v3-large", - "family": "morph", - "reasoning": false, - "temperature": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 32000 - } - }, - "c4ai-aya-expanse-32b": { - "id": "c4ai-aya-expanse-32b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "command-a-03-2025": { - "id": "command-a-03-2025", - "family": "command-a", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8000 - } - }, - "command-r7b-arabic-02-2025": { - "id": "command-r7b-arabic-02-2025", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "command-a-translate-08-2025": { - "id": "command-a-translate-08-2025", - "family": "command-a", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "output": 8000 - } - }, - "command-r-08-2024": { - "id": "command-r-08-2024", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "command-r-plus-08-2024": { - "id": "command-r-plus-08-2024", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "command-a-reasoning-08-2025": { - "id": "command-a-reasoning-08-2025", - "family": "command-a", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 8192, - "input": 256000 - } - }, - "c4ai-aya-expanse-8b": { - "id": "c4ai-aya-expanse-8b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "output": 4000 - } - }, - "c4ai-aya-vision-8b": { - "id": "c4ai-aya-vision-8b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "output": 4000 - } - }, - "c4ai-aya-vision-32b": { - "id": "c4ai-aya-vision-32b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "output": 4000 - } - }, - "command-r7b-12-2024": { - "id": "command-r7b-12-2024", - "family": "command-r", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "command-a-vision-07-2025": { - "id": "command-a-vision-07-2025", - "family": "command-a", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8000 - } - }, - "v0-1.0-md": { - "id": "v0-1.0-md", - "family": "v0", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000, - "input": 200000 - } - }, - "v0-1.5-md": { - "id": "v0-1.5-md", - "family": "v0", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000, - "input": 200000 - } - }, - "v0-1.5-lg": { - "id": "v0-1.5-lg", - "family": "v0", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 64000, - "input": 1000000 - } - }, - "llama-3_1-nemotron-ultra-253b-v1": { - "id": "Llama-3_1-Nemotron-Ultra-253B-v1", - "family": "llama", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 4096 - } - }, - "deepseek-r1-distill-qwen-32b": { - "id": "deepseek-r1-distill-qwen-32b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384 - } - }, - "glm-5-fp8": { - "id": "GLM-5-FP8", - "family": "glm", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202000, - "output": 131072 - } - }, - "nvidia-nemotron-3-super-120b-a12b-nvfp4": { - "id": "NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 260000, - "output": 8192 - } - }, - "nvidia/nemotron-120b-a12b": { - "id": "nvidia/Nemotron-120B-A12B", - "family": "nemotron", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32678 - } - }, - "claude-3-5-haiku-latest": { - "id": "claude-3-5-haiku-latest", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "claude-3-5-sonnet-20241022": { - "id": "claude-3-5-sonnet-20241022", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192, - "input": 200000 - } - }, - "claude-3-sonnet-20240229": { - "id": "claude-3-sonnet-20240229", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "claude-sonnet-4-0": { - "id": "claude-sonnet-4-0", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-opus-4-0": { - "id": "claude-opus-4-0", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "claude-3-5-haiku-20241022": { - "id": "claude-3-5-haiku-20241022", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192, - "input": 200000 - } - }, - "claude-3-5-sonnet-20240620": { - "id": "claude-3-5-sonnet-20240620", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192, - "input": 200000 - } - }, - "claude-3-7-sonnet-latest": { - "id": "claude-3-7-sonnet-latest", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-3-opus-20240229": { - "id": "claude-3-opus-20240229", - "family": "claude-opus", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 4096 - } - }, - "hunyuan-turbos": { - "id": "hunyuan-turbos", - "family": "hunyuan", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "tc-code-latest": { - "id": "tc-code-latest", - "family": "auto", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "hunyuan-t1": { - "id": "hunyuan-t1", - "family": "hunyuan", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "hunyuan-2.0-instruct": { - "id": "hunyuan-2.0-instruct", - "family": "hunyuan", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "hunyuan-2.0-thinking": { - "id": "hunyuan-2.0-thinking", - "family": "hunyuan", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "claude-sonnet-4-5@20250929": { - "id": "claude-sonnet-4-5@20250929", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-opus-4-1@20250805": { - "id": "claude-opus-4-1@20250805", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "claude-3-7-sonnet@20250219": { - "id": "claude-3-7-sonnet@20250219", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-opus-4@20250514": { - "id": "claude-opus-4@20250514", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 32000 - } - }, - "claude-opus-4-5@20251101": { - "id": "claude-opus-4-5@20251101", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-3-5-haiku@20241022": { - "id": "claude-3-5-haiku@20241022", - "family": "claude-haiku", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "claude-sonnet-4@20250514": { - "id": "claude-sonnet-4@20250514", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-3-5-sonnet@20241022": { - "id": "claude-3-5-sonnet@20241022", - "family": "claude-sonnet", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8192 - } - }, - "claude-opus-4-6@default": { - "id": "claude-opus-4-6@default", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "claude-haiku-4-5@20251001": { - "id": "claude-haiku-4-5@20251001", - "family": "claude-haiku", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "claude-sonnet-4-6@default": { - "id": "claude-sonnet-4-6@default", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "giga-potato-thinking": { - "id": "giga-potato-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "corethink:free": { - "id": "corethink:free", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 78000, - "output": 8192 - } - }, - "morph-warp-grep-v2": { - "id": "morph-warp-grep-v2", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "giga-potato": { - "id": "giga-potato", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 32000 - } - }, - "allenai/olmo-2-0325-32b-instruct": { - "id": "allenai/olmo-2-0325-32b-instruct", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "allenai/olmo-3-7b-instruct": { - "id": "allenai/olmo-3-7b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 65536 - } - }, - "allenai/olmo-3-32b-think": { - "id": "allenai/olmo-3-32b-think", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 8192, - "input": 128000 - }, - "family": "allenai" - }, - "allenai/molmo-2-8b": { - "id": "allenai/molmo-2-8b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 36864, - "output": 36864, - "input": 36864 - }, - "family": "allenai" - }, - "allenai/olmo-3.1-32b-instruct": { - "id": "allenai/olmo-3.1-32b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 8192, - "input": 65536 - }, - "family": "allenai" - }, - "allenai/olmo-3-7b-think": { - "id": "allenai/olmo-3-7b-think", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 65536 - } - }, - "allenai/olmo-3.1-32b-think": { - "id": "allenai/olmo-3.1-32b-think", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 8192, - "input": 65536 - }, - "family": "allenai" - }, - "nvidia/nemotron-3-super-120b-a12b:free": { - "id": "nvidia/nemotron-3-super-120b-a12b:free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "ibm-granite/granite-4.0-h-micro": { - "id": "ibm-granite/granite-4.0-h-micro", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 32768 - } - }, - "arcee-ai/coder-large": { - "id": "arcee-ai/coder-large", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "arcee-ai/virtuoso-large": { - "id": "arcee-ai/virtuoso-large", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 64000 - } - }, - "arcee-ai/maestro-reasoning": { - "id": "arcee-ai/maestro-reasoning", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32000 - } - }, - "arcee-ai/spotlight": { - "id": "arcee-ai/spotlight", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65537 - } - }, - "alfredpros/codellama-7b-instruct-solidity": { - "id": "alfredpros/codellama-7b-instruct-solidity", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 4096 - } - }, - "liquid/lfm-2.2-6b": { - "id": "liquid/lfm-2.2-6b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "liquid/lfm-2-24b-a2b": { - "id": "liquid/lfm-2-24b-a2b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "liquid/lfm2-8b-a1b": { - "id": "liquid/lfm2-8b-a1b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "upstage/solar-pro-3": { - "id": "upstage/solar-pro-3", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "switchpoint/router": { - "id": "switchpoint/router", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "kilo-auto/balanced": { - "id": "kilo-auto/balanced", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "kilo-auto/free": { - "id": "kilo-auto/free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "kilo-auto/small": { - "id": "kilo-auto/small", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "kilo-auto/frontier": { - "id": "kilo-auto/frontier", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "amazon/nova-micro-v1": { - "id": "amazon/nova-micro-v1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 5120, - "input": 128000 - }, - "family": "nova-micro" - }, - "amazon/nova-lite-v1": { - "id": "amazon/nova-lite-v1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 300000, - "output": 5120, - "input": 300000 - }, - "family": "nova-lite" - }, - "amazon/nova-premier-v1": { - "id": "amazon/nova-premier-v1", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 32000 - } - }, - "amazon/nova-2-lite-v1": { - "id": "amazon/nova-2-lite-v1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65535, - "input": 1000000 - }, - "family": "nova" - }, - "amazon/nova-pro-v1": { - "id": "amazon/nova-pro-v1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 300000, - "output": 32000, - "input": 300000 - }, - "family": "nova-pro" - }, - "anthracite-org/magnum-v4-72b": { - "id": "anthracite-org/magnum-v4-72b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 8192, - "input": 16384 - }, - "family": "llama" - }, - "alibaba/tongyi-deepresearch-30b-a3b": { - "id": "alibaba/tongyi-deepresearch-30b-a3b", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "aion-labs/aion-1.0-mini": { - "id": "aion-labs/aion-1.0-mini", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192, - "input": 131072 - }, - "family": "deepseek" - }, - "aion-labs/aion-2.0": { - "id": "aion-labs/aion-2.0", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "aion-labs/aion-rp-llama-3.1-8b": { - "id": "aion-labs/aion-rp-llama-3.1-8b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384, - "input": 32768 - }, - "family": "llama" - }, - "aion-labs/aion-1.0": { - "id": "aion-labs/aion-1.0", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 8192, - "input": 65536 - }, - "family": "llama" - }, - "relace/relace-search": { - "id": "relace/relace-search", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 128000 - } - }, - "relace/relace-apply-3": { - "id": "relace/relace-apply-3", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 128000 - } - }, - "thedrummer/rocinante-12b": { - "id": "thedrummer/rocinante-12b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "thedrummer/cydonia-24b-v4.1": { - "id": "thedrummer/cydonia-24b-v4.1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 131072 - } - }, - "thedrummer/unslopnemo-12b": { - "id": "thedrummer/unslopnemo-12b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "thedrummer/skyfall-36b-v2": { - "id": "thedrummer/skyfall-36b-v2", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "mancer/weaver": { - "id": "mancer/weaver", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "output": 2000 - } - }, - "deepseek/deepseek-r1-distill-qwen-32b": { - "id": "deepseek/deepseek-r1-distill-qwen-32b", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "alpindale/goliath-120b": { - "id": "alpindale/goliath-120b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 6144, - "output": 1024 - } - }, - "openrouter/hunter-alpha": { - "id": "openrouter/hunter-alpha", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 32000 - } - }, - "openrouter/auto": { - "id": "openrouter/auto", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "image", - "text" - ] - }, - "limit": { - "context": 2000000, - "output": 32768 - } - }, - "openrouter/healer-alpha": { - "id": "openrouter/healer-alpha", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32000 - } - }, - "openrouter/bodybuilder": { - "id": "openrouter/bodybuilder", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "google/gemini-2.5-pro-preview": { - "id": "google/gemini-2.5-pro-preview", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536 - } - }, - "google/gemini-2.0-flash-lite-001": { - "id": "google/gemini-2.0-flash-lite-001", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "image", - "pdf", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 8192 - } - }, - "z-ai/glm-4-32b": { - "id": "z-ai/glm-4-32b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 32768 - } - }, - "deepcogito/cogito-v2.1-671b": { - "id": "deepcogito/cogito-v2.1-671b", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - }, - "family": "cogito" - }, - "bytedance/ui-tars-1.5-7b": { - "id": "bytedance/ui-tars-1.5-7b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 2048 - } - }, - "undi95/remm-slerp-l2-13b": { - "id": "undi95/remm-slerp-l2-13b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 6144, - "output": 4096, - "input": 6144 - }, - "family": "llama" - }, - "qwen/qwen-vl-plus": { - "id": "qwen/qwen-vl-plus", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen/qwen-vl-max": { - "id": "qwen/qwen-vl-max", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "qwen/qwen-2.5-vl-7b-instruct": { - "id": "qwen/qwen-2.5-vl-7b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 6554 - } - }, - "qwen/qwen3-max-thinking": { - "id": "qwen/qwen3-max-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "qwen/qwen-max": { - "id": "qwen/qwen-max", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 8192 - } - }, - "qwen/qwen-turbo": { - "id": "qwen/qwen-turbo", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen/qwen3-235b-a22b-2507": { - "id": "qwen/qwen3-235b-a22b-2507", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 52429 - } - }, - "qwen/qwen-2.5-7b-instruct": { - "id": "qwen/qwen-2.5-7b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 6554 - } - }, - "qwen/qwen-plus": { - "id": "qwen/qwen-plus", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 32768 - } - }, - "qwen/qwen-plus-2025-07-28": { - "id": "qwen/qwen-plus-2025-07-28", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 32768 - } - }, - "qwen/qwen3-30b-a3b": { - "id": "Qwen/Qwen3-30B-A3B", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 40960, - "output": 40960 - }, - "family": "qwen" - }, - "qwen/qwen-plus-2025-07-28:thinking": { - "id": "qwen/qwen-plus-2025-07-28:thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 32768 - } - }, - "qwen/qwen3.5-flash-02-23": { - "id": "qwen/qwen3.5-flash-02-23", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 65536 - } - }, - "eleutherai/llemma_7b": { - "id": "eleutherai/llemma_7b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 4096 - } - }, - "x-ai/grok-code-fast-1:optimized:free": { - "id": "x-ai/grok-code-fast-1:optimized:free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 10000 - } - }, - "meta-llama/llama-4-scout": { - "id": "meta-llama/llama-4-scout", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 328000, - "output": 65536, - "input": 328000 - }, - "family": "llama" - }, - "meta-llama/llama-3.2-3b-instruct": { - "id": "meta-llama/llama-3.2-3b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192, - "input": 131072 - }, - "family": "llama" - }, - "meta-llama/llama-3.2-1b-instruct": { - "id": "meta-llama/llama-3.2-1b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 60000, - "output": 12000 - } - }, - "meta-llama/llama-3.1-405b-instruct": { - "id": "meta-llama/llama-3.1-405b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 26200 - } - }, - "meta-llama/llama-4-maverick": { - "id": "meta-llama/llama-4-maverick", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048576, - "output": 65536, - "input": 1048576 - }, - "family": "llama" - }, - "meta-llama/llama-3.1-405b": { - "id": "meta-llama/llama-3.1-405b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768 - } - }, - "tngtech/deepseek-r1t2-chimera": { - "id": "tngtech/deepseek-r1t2-chimera", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "mistralai/ministral-3b-2512": { - "id": "mistralai/ministral-3b-2512", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768, - "input": 131072 - }, - "family": "ministral" - }, - "mistralai/mistral-saba": { - "id": "mistralai/mistral-saba", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "output": 32768, - "input": 32000 - }, - "family": "mistral" - }, - "mistralai/mistral-small-24b-instruct-2501": { - "id": "mistralai/mistral-small-24b-instruct-2501", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384 - } - }, - "mistralai/pixtral-large-2411": { - "id": "mistralai/pixtral-large-2411", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "mistralai/mistral-small-creative": { - "id": "mistralai/mistral-small-creative", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 32768, - "input": 32768 - }, - "family": "mistral-small" - }, - "mistralai/mistral-large-2512": { - "id": "mistralai/mistral-large-2512", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 52429 - } - }, - "mistralai/ministral-8b-2512": { - "id": "mistralai/ministral-8b-2512", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768, - "input": 262144 - }, - "family": "ministral" - }, - "mistralai/ministral-14b-2512": { - "id": "mistralai/ministral-14b-2512", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768, - "input": 262144 - }, - "family": "ministral" - }, - "mistralai/devstral-medium": { - "id": "mistralai/devstral-medium", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "mistralai/mistral-large-2407": { - "id": "mistralai/mistral-large-2407", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "mistralai/devstral-small": { - "id": "mistralai/devstral-small", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "mistralai/mixtral-8x22b-instruct": { - "id": "mistralai/mixtral-8x22b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "output": 13108 - } - }, - "mistralai/mistral-large-2411": { - "id": "mistralai/mistral-large-2411", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 26215 - } - }, - "mistralai/mistral-7b-instruct-v0.1": { - "id": "mistralai/mistral-7b-instruct-v0.1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2824, - "output": 565 - } - }, - "mistralai/mistral-large": { - "id": "mistralai/mistral-large", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 256000, - "input": 128000 - }, - "family": "mistral-large" - }, - "mistralai/mixtral-8x7b-instruct": { - "id": "mistralai/mixtral-8x7b-instruct", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384 - } - }, - "openai/gpt-4o-2024-11-20": { - "id": "openai/gpt-4o-2024-11-20", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - }, - "family": "gpt" - }, - "openai/gpt-4o:extended": { - "id": "openai/gpt-4o:extended", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 64000 - } - }, - "openai/gpt-4o-2024-05-13": { - "id": "openai/gpt-4o-2024-05-13", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "openai/gpt-4o-audio-preview": { - "id": "openai/gpt-4o-audio-preview", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "audio", - "text" - ], - "output": [ - "audio", - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "openai/gpt-4o-mini-2024-07-18": { - "id": "openai/gpt-4o-mini-2024-07-18", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "openai/gpt-audio": { - "id": "openai/gpt-audio", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "audio", - "text" - ], - "output": [ - "audio", - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "openai/gpt-3.5-turbo-16k": { - "id": "openai/gpt-3.5-turbo-16k", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16385, - "output": 4096 - } - }, - "openai/gpt-5-image-mini": { - "id": "openai/gpt-5-image-mini", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "image", - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "openai/gpt-4-turbo-preview": { - "id": "openai/gpt-4-turbo-preview", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096, - "input": 128000 - }, - "family": "gpt" - }, - "openai/gpt-3.5-turbo-0613": { - "id": "openai/gpt-3.5-turbo-0613", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4095, - "output": 4096 - } - }, - "openai/gpt-4-0314": { - "id": "openai/gpt-4-0314", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8191, - "output": 4096 - } - }, - "openai/gpt-audio-mini": { - "id": "openai/gpt-audio-mini", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "audio", - "text" - ], - "output": [ - "audio", - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384 - } - }, - "openai/gpt-4-1106-preview": { - "id": "openai/gpt-4-1106-preview", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096 - } - }, - "openai/gpt-4o-2024-08-06": { - "id": "openai/gpt-4o-2024-08-06", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - }, - "family": "gpt" - }, - "openai/o4-mini-high": { - "id": "openai/o4-mini-high", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 100000, - "input": 200000 - }, - "family": "o-mini" - }, - "openai/gpt-4o-search-preview": { - "id": "openai/gpt-4o-search-preview", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 16384, - "input": 128000 - }, - "family": "gpt" - }, - "cohere/command-r-08-2024": { - "id": "cohere/command-r-08-2024", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "cohere/command-r-plus-08-2024": { - "id": "cohere/command-r-plus-08-2024", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4096, - "input": 128000 - }, - "family": "command-r" - }, - "cohere/command-r7b-12-2024": { - "id": "cohere/command-r7b-12-2024", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 4000 - } - }, - "minimax/minimax-m2-her": { - "id": "minimax/minimax-m2-her", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65532, - "output": 2048, - "input": 65532 - }, - "family": "minimax" - }, - "minimax/minimax-m2.5:free": { - "id": "minimax/minimax-m2.5:free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "sao10k/l3.1-70b-hanami-x1": { - "id": "Sao10K/L3.1-70B-Hanami-x1", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "output": 16384, - "input": 16384 - }, - "family": "llama" - }, - "sao10k/l3-lunaris-8b": { - "id": "sao10k/l3-lunaris-8b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "sao10k/l3.1-euryale-70b": { - "id": "sao10k/l3.1-euryale-70b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "sao10k/l3-euryale-70b": { - "id": "sao10k/l3-euryale-70b", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "sao10k/l3.3-euryale-70b": { - "id": "sao10k/l3.3-euryale-70b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "writer/palmyra-x5": { - "id": "writer/palmyra-x5", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1040000, - "output": 8192 - } - }, - "perplexity/sonar-deep-research": { - "id": "perplexity/sonar-deep-research", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 25600 - } - }, - "perplexity/sonar-pro-search": { - "id": "perplexity/sonar-pro-search", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 8000 - } - }, - "bytedance-seed/seed-2.0-mini": { - "id": "bytedance-seed/seed-2.0-mini", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "bytedance-seed/seed-1.6": { - "id": "bytedance-seed/seed-1.6", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "bytedance-seed/seed-1.6-flash": { - "id": "bytedance-seed/seed-1.6-flash", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 32768 - } - }, - "bytedance-seed/seed-2.0-lite": { - "id": "bytedance-seed/seed-2.0-lite", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text", - "video" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 131072 - } - }, - "anthropic/claude-3.7-sonnet:thinking": { - "id": "anthropic/claude-3.7-sonnet:thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "pdf", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "output": 64000 - } - }, - "ai21/jamba-large-1.7": { - "id": "ai21/jamba-large-1.7", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "output": 4096 - } - }, - "kilo/auto": { - "id": "kilo/auto", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 128000 - } - }, - "kilo/auto-free": { - "id": "kilo/auto-free", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 204800, - "output": 131072 - } - }, - "kilo/auto-small": { - "id": "kilo/auto-small", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "image", - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "output": 128000 - } - }, - "inflection/inflection-3-productivity": { - "id": "inflection/inflection-3-productivity", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "output": 4096, - "input": 8000 - }, - "family": "gpt" - }, - "inflection/inflection-3-pi": { - "id": "inflection/inflection-3-pi", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "output": 4096, - "input": 8000 - }, - "family": "gpt" - }, - "nousresearch/hermes-3-llama-3.1-70b": { - "id": "nousresearch/hermes-3-llama-3.1-70b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 32768 - } - }, - "nousresearch/hermes-3-llama-3.1-405b": { - "id": "nousresearch/hermes-3-llama-3.1-405b", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "exa-research-pro": { - "id": "exa-research-pro", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "gemini-2.0-pro-exp-02-05": { - "id": "gemini-2.0-pro-exp-02-05", + "gemini-exp-1206": { + "id": "gemini-exp-1206", "reasoning": false, "toolCall": false, "modalities": { @@ -32506,27 +2514,8 @@ "output": 8192 } }, - "qwen-image": { - "id": "qwen-image", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "llama-3.3-70b-shakudo": { - "id": "Llama-3.3-70B-Shakudo", + "auto-model-basic": { + "id": "auto-model-basic", "reasoning": false, "toolCall": false, "modalities": { @@ -32538,215 +2527,13 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 16384 + "context": 1000000, + "input": 1000000, + "output": 1000000 } }, - "ernie-4.5-8k-preview": { - "id": "ernie-4.5-8k-preview", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "input": 8000, - "output": 16384 - } - }, - "claude-3-7-sonnet-thinking:128000": { - "id": "claude-3-7-sonnet-thinking:128000", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 64000 - } - }, - "phi-4-multimodal-instruct": { - "id": "phi-4-multimodal-instruct", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "z-image-turbo": { - "id": "z-image-turbo", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "llama-3.3+(3v3.3)-70b-tenyxchat-daybreakstorywriter": { - "id": "Llama-3.3+(3v3.3)-70B-TenyxChat-DaybreakStorywriter", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "mistral-small-31-24b-instruct": { - "id": "mistral-small-31-24b-instruct", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 131072 - } - }, - "llama-3.3-70b-the-omega-directive-unslop-v2.0": { - "id": "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.0", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "baichuan-m2": { - "id": "Baichuan-M2", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "doubao-1.5-vision-pro-32k": { - "id": "doubao-1.5-vision-pro-32k", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 8192 - } - }, - "glm-4.5-air-derestricted-iceblink-v2-reextract": { - "id": "GLM-4.5-Air-Derestricted-Iceblink-v2-ReExtract", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 65536 - } - }, - "llama-3.3-70b-arliai-rpmax-v1.4": { - "id": "Llama-3.3-70B-ArliAI-RPMax-v1.4", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "jamba-large-1.6": { - "id": "jamba-large-1.6", + "jamba-mini": { + "id": "jamba-mini", "reasoning": false, "toolCall": false, "modalities": { @@ -32763,8 +2550,366 @@ "output": 4096 } }, - "llama-3.3-70b-aurora-borealis": { - "id": "Llama-3.3-70B-Aurora-Borealis", + "yi-large": { + "id": "yi-large", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 4096 + } + }, + "auto-model-premium": { + "id": "auto-model-premium", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "azure-gpt-4o": { + "id": "azure-gpt-4o", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "deepseek-v3-0324": { + "id": "deepseek-v3-0324", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 131072 + }, + "temperature": true, + "family": "deepseek" + }, + "claude-3-5-haiku-20241022": { + "id": "claude-3-5-haiku-20241022", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 8192 + }, + "family": "claude-haiku", + "temperature": true + }, + "doubao-seed-1-6-250615": { + "id": "doubao-seed-1-6-250615", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "ernie-x1.1-preview": { + "id": "ernie-x1.1-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + } + }, + "ernie-5.0-thinking-preview": { + "id": "ernie-5.0-thinking-preview", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "glm-4-air-0111": { + "id": "glm-4-air-0111", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "fastgpt": { + "id": "fastgpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "doubao-seed-1-6-thinking-250615": { + "id": "doubao-seed-1-6-thinking-250615", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "gemini-2.0-flash-001": { + "id": "gemini-2.0-flash-001", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 8192 + } + }, + "claude-opus-4-1-thinking:32000": { + "id": "claude-opus-4-1-thinking:32000", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "llama-3.3-70b-rawmaw": { + "id": "Llama-3.3-70B-RAWMAW", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4.5-air-derestricted-steam": { + "id": "GLM-4.5-Air-Derestricted-Steam", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 220600, + "input": 220600, + "output": 65536 + } + }, + "claude-3-5-sonnet-20241022": { + "id": "claude-3-5-sonnet-20241022", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 8192 + }, + "family": "claude-sonnet", + "temperature": true + }, + "yi-medium-200k": { + "id": "yi-medium-200k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 4096 + } + }, + "gemma-3-27b-arliai-rpmax-v3": { + "id": "Gemma-3-27B-ArliAI-RPMax-v3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "phi-4-mini-instruct": { + "id": "phi-4-mini-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "llama-3.3+(3v3.3)-70b-tenyxchat-daybreakstorywriter": { + "id": "Llama-3.3+(3v3.3)-70B-TenyxChat-DaybreakStorywriter", "reasoning": false, "toolCall": false, "modalities": { @@ -32800,8 +2945,64 @@ "output": 16384 } }, - "llama-3.3-70b-magnum-v4-se": { - "id": "Llama-3.3-70B-Magnum-v4-SE", + "glm-z1-air": { + "id": "glm-z1-air", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "claude-3-7-sonnet-thinking:128000": { + "id": "claude-3-7-sonnet-thinking:128000", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "glm-4-air": { + "id": "glm-4-air", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "llama-3.3-70b-miraifanfare": { + "id": "Llama-3.3-70B-MiraiFanfare", "reasoning": false, "toolCall": false, "modalities": { @@ -32818,44 +3019,119 @@ "output": 16384 } }, - "kat-coder-pro-v1": { - "id": "KAT-Coder-Pro-V1", - "reasoning": false, + "gemini-2.0-flash-thinking-exp-01-21": { + "id": "gemini-2.0-flash-thinking-exp-01-21", + "reasoning": true, "toolCall": false, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 256000, - "input": 256000, - "output": 32768 - } - }, - "hunyuan-turbos-20250226": { - "id": "hunyuan-turbos-20250226", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 24000, - "input": 24000, + "context": 1000000, + "input": 1000000, "output": 8192 } }, - "jamba-large-1.7": { - "id": "jamba-large-1.7", + "magistral-small-2506": { + "id": "Magistral-Small-2506", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "doubao-1.5-pro-32k": { + "id": "doubao-1.5-pro-32k", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 32000, + "output": 12000 + }, + "temperature": true + }, + "venice-uncensored:web": { + "id": "venice-uncensored:web", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 80000, + "input": 80000, + "output": 16384 + } + }, + "glm-4": { + "id": "glm-4", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "qwen3-vl-235b-a22b-instruct-original": { + "id": "qwen3-vl-235b-a22b-instruct-original", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "jamba-large-1.6": { + "id": "jamba-large-1.6", "reasoning": false, "toolCall": false, "modalities": { @@ -32872,8 +3148,857 @@ "output": 4096 } }, - "mercury-coder-small": { - "id": "mercury-coder-small", + "qwen25-vl-72b-instruct": { + "id": "qwen25-vl-72b-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 32768 + } + }, + "claude-sonnet-4-thinking:64000": { + "id": "claude-sonnet-4-thinking:64000", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "llama-3.3+(3.1v3.3)-70b-new-dawn-v1.1": { + "id": "Llama-3.3+(3.1v3.3)-70B-New-Dawn-v1.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4.5-air-derestricted-iceblink-reextract": { + "id": "GLM-4.5-Air-Derestricted-Iceblink-ReExtract", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 98304 + } + }, + "universal-summarizer": { + "id": "universal-summarizer", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "claude-sonnet-4-thinking:32768": { + "id": "claude-sonnet-4-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "sarvan-medium": { + "id": "sarvan-medium", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "claude-3-7-sonnet-thinking:8192": { + "id": "claude-3-7-sonnet-thinking:8192", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "gemini-2.5-flash-preview-05-20": { + "id": "gemini-2.5-flash-preview-05-20", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048000, + "output": 65536 + }, + "family": "gemini-flash", + "temperature": true + }, + "glm-4.5-air-derestricted-iceblink-v2-reextract": { + "id": "GLM-4.5-Air-Derestricted-Iceblink-v2-ReExtract", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 65536 + } + }, + "llama-3.3-70b-fallen-v1": { + "id": "Llama-3.3-70B-Fallen-v1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "qwen3-vl-235b-a22b-thinking": { + "id": "qwen3-vl-235b-a22b-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 32768, + "output": 32768 + }, + "family": "qwen", + "temperature": true + }, + "claude-3-7-sonnet-thinking:32768": { + "id": "claude-3-7-sonnet-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "claude-3-7-sonnet-thinking:1024": { + "id": "claude-3-7-sonnet-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "llama-3.3-70b-vulpecula-r1": { + "id": "Llama-3.3-70B-Vulpecula-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-sonnet-4-thinking:8192": { + "id": "claude-sonnet-4-thinking:8192", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "llama-3.3-70b-ignition-v0.1": { + "id": "Llama-3.3-70B-Ignition-v0.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4-plus-0111": { + "id": "glm-4-plus-0111", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "kat-coder-air-v1": { + "id": "KAT-Coder-Air-V1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "deepseek-r1-sambanova": { + "id": "deepseek-r1-sambanova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "deepseek-r1": { + "id": "deepseek-r1", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 128000, + "output": 163840 + }, + "family": "deepseek-thinking", + "temperature": true + }, + "doubao-1-5-thinking-pro-250415": { + "id": "doubao-1-5-thinking-pro-250415", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "sonar-pro": { + "id": "sonar-pro", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 16384 + }, + "family": "sonar", + "temperature": true + }, + "gemma-3-27b-it-abliterated": { + "id": "Gemma-3-27B-it-Abliterated", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 96000 + } + }, + "deepseek-chat-cheaper": { + "id": "deepseek-chat-cheaper", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "gemini-2.0-pro-exp-02-05": { + "id": "gemini-2.0-pro-exp-02-05", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2097152, + "input": 2097152, + "output": 8192 + } + }, + "azure-gpt-4o-mini": { + "id": "azure-gpt-4o-mini", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "llama-3.3-70b-ms-nevoria": { + "id": "Llama-3.3-70B-MS-Nevoria", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-opus-4-thinking": { + "id": "claude-opus-4-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "llama-3.3-70b-sapphira-0.1": { + "id": "Llama-3.3-70B-Sapphira-0.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "doubao-seed-code-preview-latest": { + "id": "doubao-seed-code-preview-latest", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "llama-3.3-70b-arliai-rpmax-v1.4": { + "id": "Llama-3.3-70B-ArliAI-RPMax-v1.4", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "mistral-small-31-24b-instruct": { + "id": "mistral-small-31-24b-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + } + }, + "glm-4.1v-thinking-flashx": { + "id": "glm-4.1v-thinking-flashx", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + } + }, + "hunyuan-t1-latest": { + "id": "hunyuan-t1-latest", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "doubao-1-5-thinking-vision-pro-250428": { + "id": "doubao-1-5-thinking-vision-pro-250428", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "asi1-mini": { + "id": "asi1-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "ernie-5.0-thinking-latest": { + "id": "ernie-5.0-thinking-latest", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "llama-3.3-70b-incandescent-malevolence": { + "id": "Llama-3.3-70B-Incandescent-Malevolence", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-damascus-r1": { + "id": "Llama-3.3-70B-Damascus-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemma-3-27b-nidum-uncensored": { + "id": "Gemma-3-27B-Nidum-Uncensored", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 96000 + } + }, + "gemini-2.5-flash-lite-preview-09-2025-thinking": { + "id": "gemini-2.5-flash-lite-preview-09-2025-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "doubao-seed-2-0-pro-260215": { + "id": "doubao-seed-2-0-pro-260215", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 128000 + } + }, + "gemma-3-27b-cardprojector-v4": { + "id": "Gemma-3-27B-CardProjector-v4", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "jamba-mini-1.7": { + "id": "jamba-mini-1.7", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "llama-3.3-70b-forgotten-safeword-3.6": { + "id": "Llama-3.3-70B-Forgotten-Safeword-3.6", "reasoning": false, "toolCall": false, "modalities": { @@ -32909,234 +4034,16 @@ "output": 16384 } }, - "yi-medium-200k": { - "id": "yi-medium-200k", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 4096 - } - }, - "deepseek-chat-cheaper": { - "id": "deepseek-chat-cheaper", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 8192 - } - }, - "step-r1-v-mini": { - "id": "step-r1-v-mini", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 65536 - } - }, - "yi-lightning": { - "id": "yi-lightning", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 12000, - "input": 12000, - "output": 4096 - } - }, - "deepseek-reasoner-cheaper": { - "id": "deepseek-reasoner-cheaper", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 65536 - } - }, - "ernie-4.5-turbo-vl-32k": { - "id": "ernie-4.5-turbo-vl-32k", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 16384 - } - }, - "llama-3.3-70b-ignition-v0.1": { - "id": "Llama-3.3-70B-Ignition-v0.1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "glm-z1-air": { - "id": "glm-z1-air", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 16384 - } - }, - "llama-3.3-70b-rawmaw": { - "id": "Llama-3.3-70B-RAWMAW", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "magistral-small-2506": { - "id": "Magistral-Small-2506", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "ernie-x1-turbo-32k": { - "id": "ernie-x1-turbo-32k", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 16384 - } - }, - "deepseek-r1-sambanova": { - "id": "deepseek-r1-sambanova", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "claude-3-7-sonnet-thinking:1024": { - "id": "claude-3-7-sonnet-thinking:1024", + "gemini-2.5-pro-preview-06-05": { + "id": "gemini-2.5-pro-preview-06-05", "reasoning": true, "toolCall": true, "modalities": { "input": [ "text", "image", + "audio", + "video", "pdf" ], "output": [ @@ -33144,474 +4051,13 @@ ] }, "limit": { - "context": 200000, - "input": 200000, - "output": 64000 - } - }, - "llama-3.3-70b-magnum-v4-se-cirrus-x1-slerp": { - "id": "Llama-3.3-70B-Magnum-v4-SE-Cirrus-x1-SLERP", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] + "context": 1048576, + "input": 1048756, + "output": 65536 }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "llama-3.3-70b-arliai-rpmax-v3": { - "id": "Llama-3.3-70B-ArliAI-RPMax-v3", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "qwen-long": { - "id": "qwen-long", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 10000000, - "input": 10000000, - "output": 8192 - }, - "family": "qwen", + "family": "gemini-pro", "temperature": true }, - "llama-3.3-70b-progenitor-v3.3": { - "id": "Llama-3.3-70B-Progenitor-V3.3", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "glm-4.5-air-derestricted-iceblink-v2": { - "id": "GLM-4.5-Air-Derestricted-Iceblink-v2", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 158600, - "input": 158600, - "output": 65536 - } - }, - "study_gpt-chatgpt-4o-latest": { - "id": "study_gpt-chatgpt-4o-latest", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 16384 - } - }, - "qwq-32b": { - "id": "qwq-32b", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 128000, - "output": 8192 - }, - "family": "qwen", - "temperature": true - }, - "llama-3.3-70b-ms-nevoria": { - "id": "Llama-3.3-70B-MS-Nevoria", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "doubao-seed-1-6-250615": { - "id": "doubao-seed-1-6-250615", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 16384 - } - }, - "glm-4": { - "id": "glm-4", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "azure-gpt-4-turbo": { - "id": "azure-gpt-4-turbo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "llama-3.3-70b-legion-v2.1": { - "id": "Llama-3.3-70B-Legion-V2.1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "claude-3-7-sonnet-thinking:32768": { - "id": "claude-3-7-sonnet-thinking:32768", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 64000 - } - }, - "asi1-mini": { - "id": "asi1-mini", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "gemini-exp-1206": { - "id": "gemini-exp-1206", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 2097152, - "input": 2097152, - "output": 8192 - } - }, - "brave": { - "id": "brave", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 8192, - "output": 8192 - } - }, - "doubao-1-5-thinking-pro-250415": { - "id": "doubao-1-5-thinking-pro-250415", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "claude-sonnet-4-thinking:64000": { - "id": "claude-sonnet-4-thinking:64000", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 64000 - } - }, - "glm-4.5-air-derestricted-steam-reextract": { - "id": "GLM-4.5-Air-Derestricted-Steam-ReExtract", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 65536 - } - }, - "kimi-k2-instruct-fast": { - "id": "kimi-k2-instruct-fast", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 16384 - } - }, - "llama-3.3-70b-geneticlemonade-opus": { - "id": "Llama-3.3-70B-GeneticLemonade-Opus", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "gemma-3-27b-big-tiger-v3": { - "id": "Gemma-3-27B-Big-Tiger-v3", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "doubao-seed-2-0-mini-260215": { - "id": "doubao-seed-2-0-mini-260215", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 32000 - } - }, - "glm-4-air": { - "id": "glm-4-air", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "glm-4.5-air-derestricted-iceblink-reextract": { - "id": "GLM-4.5-Air-Derestricted-Iceblink-ReExtract", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 98304 - } - }, "gemini-2.0-pro-reasoner": { "id": "gemini-2.0-pro-reasoner", "reasoning": false, @@ -33630,429 +4076,6 @@ "output": 65536 } }, - "gemini-2.0-flash-001": { - "id": "gemini-2.0-flash-001", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 8192 - } - }, - "glm-4-plus": { - "id": "glm-4-plus", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "gemini-2.0-flash-exp-image-generation": { - "id": "gemini-2.0-flash-exp-image-generation", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32767, - "input": 32767, - "output": 8192 - } - }, - "glm-4.5-air-derestricted": { - "id": "GLM-4.5-Air-Derestricted", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202600, - "input": 202600, - "output": 98304 - } - }, - "gemini-2.0-flash-thinking-exp-1219": { - "id": "gemini-2.0-flash-thinking-exp-1219", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32767, - "input": 32767, - "output": 8192 - } - }, - "glm-4.1v-thinking-flashx": { - "id": "glm-4.1v-thinking-flashx", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "input": 64000, - "output": 8192 - } - }, - "llama-3.3-70b-strawberrylemonade-v1.0": { - "id": "Llama-3.3-70B-StrawberryLemonade-v1.0", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "llama-3.3-70b-fallen-v1": { - "id": "Llama-3.3-70B-Fallen-v1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "gemma-3-27b-nidum-uncensored": { - "id": "Gemma-3-27B-Nidum-Uncensored", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 96000 - } - }, - "llama-3.3-70b-electranova-v1.0": { - "id": "Llama-3.3-70B-Electranova-v1.0", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "grok-3-fast-beta": { - "id": "grok-3-fast-beta", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 131072 - } - }, - "llama-3.3-70b-sapphira-0.1": { - "id": "Llama-3.3-70B-Sapphira-0.1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "gemini-2.5-pro-preview-03-25": { - "id": "gemini-2.5-pro-preview-03-25", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "input": 1048756, - "output": 65536 - } - }, - "step-2-16k-exp": { - "id": "step-2-16k-exp", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16000, - "input": 16000, - "output": 8192 - } - }, - "chroma": { - "id": "chroma", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "fastgpt": { - "id": "fastgpt", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "claude-sonnet-4-thinking:8192": { - "id": "claude-sonnet-4-thinking:8192", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 64000 - } - }, - "llama-3.3-70b-electra-r1": { - "id": "Llama-3.3-70B-Electra-R1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "llama-3.3-70b-fallen-r1-v1": { - "id": "Llama-3.3-70B-Fallen-R1-v1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "gemma-3-27b-it-abliterated": { - "id": "Gemma-3-27B-it-Abliterated", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 96000 - } - }, - "doubao-1.5-pro-256k": { - "id": "doubao-1.5-pro-256k", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 16384 - } - }, - "claude-opus-4-thinking": { - "id": "claude-opus-4-thinking", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32000 - } - }, - "doubao-1-5-thinking-vision-pro-250428": { - "id": "doubao-1-5-thinking-vision-pro-250428", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, "doubao-seed-2-0-lite-260215": { "id": "doubao-seed-2-0-lite-260215", "reasoning": false, @@ -34071,181 +4094,33 @@ "output": 32000 } }, - "qwen25-vl-72b-instruct": { - "id": "qwen25-vl-72b-instruct", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 32768 - } - }, - "azure-gpt-4o": { - "id": "azure-gpt-4o", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "ernie-4.5-turbo-128k": { - "id": "ernie-4.5-turbo-128k", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "azure-o1": { - "id": "azure-o1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 100000 - } - }, - "gemini-3-pro-preview-thinking": { - "id": "gemini-3-pro-preview-thinking", + "gemini-2.5-flash-lite-preview-06-17": { + "id": "gemini-2.5-flash-lite-preview-06-17", "reasoning": true, "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "audio", + "video", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 1048756, + "context": 1048576, "input": 1048756, "output": 65536 - } - }, - "grok-3-mini-beta": { - "id": "grok-3-mini-beta", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 131072, - "input": 131072, - "output": 131072 - } + "family": "gemini-flash-lite", + "temperature": true }, - "claude-opus-4-1-thinking": { - "id": "claude-opus-4-1-thinking", + "sonar-deep-research": { + "id": "sonar-deep-research", "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32000 - } - }, - "gemini-2.5-flash-nothinking": { - "id": "gemini-2.5-flash-nothinking", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "input": 1048756, - "output": 65536 - } - }, - "claude-3-7-sonnet-thinking:8192": { - "id": "claude-3-7-sonnet-thinking:8192", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 64000 - } - }, - "auto-model-basic": { - "id": "auto-model-basic", - "reasoning": false, "toolCall": false, "modalities": { "input": [ @@ -34256,13 +4131,15 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 1000000 - } + "context": 127000, + "input": 60000, + "output": 4096 + }, + "temperature": true, + "family": "sonar-deep-research" }, - "llama-3.3-70b-the-omega-directive-unslop-v2.1": { - "id": "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.1", + "llama-3.3-70b-geneticlemonade-unleashed-v3": { + "id": "Llama-3.3-70B-GeneticLemonade-Unleashed-v3", "reasoning": false, "toolCall": false, "modalities": { @@ -34279,281 +4156,6 @@ "output": 16384 } }, - "glm-4-plus-0111": { - "id": "glm-4-plus-0111", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "llama-3.3-70b-bigger-body": { - "id": "Llama-3.3-70B-Bigger-Body", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "kat-coder-air-v1": { - "id": "KAT-Coder-Air-V1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 32768 - } - }, - "doubao-seed-1-6-flash-250615": { - "id": "doubao-seed-1-6-flash-250615", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 16384 - } - }, - "glm-4-air-0111": { - "id": "glm-4-air-0111", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "phi-4-mini-instruct": { - "id": "phi-4-mini-instruct", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "jamba-mini-1.6": { - "id": "jamba-mini-1.6", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 4096 - } - }, - "kimi-thinking-preview": { - "id": "kimi-thinking-preview", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "claude-sonnet-4-thinking:1024": { - "id": "claude-sonnet-4-thinking:1024", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 64000 - } - }, - "llama-3.3-70b-incandescent-malevolence": { - "id": "Llama-3.3-70B-Incandescent-Malevolence", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "llama-3.3-70b-forgotten-safeword-3.6": { - "id": "Llama-3.3-70B-Forgotten-Safeword-3.6", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "step-2-mini": { - "id": "step-2-mini", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "input": 8000, - "output": 4096 - } - }, - "mistral-nemo-12b-instruct-2407": { - "id": "Mistral-Nemo-12B-Instruct-2407", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "baichuan4-turbo": { - "id": "Baichuan4-Turbo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 32768 - } - }, - "ernie-5.0-thinking-latest": { - "id": "ernie-5.0-thinking-latest", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, "gemma-3-27b-glitter": { "id": "Gemma-3-27B-Glitter", "reasoning": false, @@ -34572,28 +4174,8 @@ "output": 16384 } }, - "claude-opus-4-thinking:32000": { - "id": "claude-opus-4-thinking:32000", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32000 - } - }, - "auto-model-premium": { - "id": "auto-model-premium", + "llama-3.3-70b-the-omega-directive-unslop-v2.1": { + "id": "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.1", "reasoning": false, "toolCall": false, "modalities": { @@ -34605,74 +4187,15 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 1000000 + "context": 32768, + "input": 32768, + "output": 16384 } }, - "gemini-2.0-flash-thinking-exp-01-21": { - "id": "gemini-2.0-flash-thinking-exp-01-21", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 8192 - } - }, - "claude-sonnet-4-thinking:32768": { - "id": "claude-sonnet-4-thinking:32768", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 64000 - } - }, - "claude-opus-4-1-thinking:32768": { - "id": "claude-opus-4-1-thinking:32768", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32000 - } - }, - "jamba-large": { - "id": "jamba-large", + "qwen3-30b-a3b-instruct-2507": { + "id": "qwen3-30b-a3b-instruct-2507", "reasoning": false, - "toolCall": false, + "toolCall": true, "modalities": { "input": [ "text" @@ -34682,616 +4205,12 @@ ] }, "limit": { - "context": 256000, + "context": 262000, "input": 256000, - "output": 4096 - } - }, - "llama-3.3-70b-miraifanfare": { - "id": "Llama-3.3-70B-MiraiFanfare", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "venice-uncensored:web": { - "id": "venice-uncensored:web", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 80000, - "input": 80000, - "output": 16384 - } - }, - "gemini-2.5-flash-lite-preview-09-2025-thinking": { - "id": "gemini-2.5-flash-lite-preview-09-2025-thinking", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1048756, - "input": 1048756, - "output": 65536 - } - }, - "ernie-x1-32k-preview": { - "id": "ernie-x1-32k-preview", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 16384 - } - }, - "glm-z1-airx": { - "id": "glm-z1-airx", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 16384 - } - }, - "ernie-x1.1-preview": { - "id": "ernie-x1.1-preview", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "input": 64000, "output": 8192 - } - }, - "exa-research": { - "id": "exa-research", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] }, - "limit": { - "context": 8192, - "input": 8192, - "output": 8192 - } - }, - "llama-3.3-70b-mokume-gane-r1": { - "id": "Llama-3.3-70B-Mokume-Gane-R1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "glm-4.1v-thinking-flash": { - "id": "glm-4.1v-thinking-flash", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "input": 64000, - "output": 8192 - } - }, - "llama-3.3-70b-geneticlemonade-unleashed-v3": { - "id": "Llama-3.3-70B-GeneticLemonade-Unleashed-v3", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "llama-3.3-70b-predatorial-extasy": { - "id": "Llama-3.3-70B-Predatorial-Extasy", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "glm-4-airx": { - "id": "glm-4-airx", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8000, - "input": 8000, - "output": 4096 - } - }, - "doubao-seed-1-6-thinking-250615": { - "id": "doubao-seed-1-6-thinking-250615", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 16384 - } - }, - "claude-3-7-sonnet-thinking": { - "id": "claude-3-7-sonnet-thinking", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 16000 - } - }, - "glm-4.5-air-derestricted-steam": { - "id": "GLM-4.5-Air-Derestricted-Steam", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 220600, - "input": 220600, - "output": 65536 - } - }, - "ernie-5.0-thinking-preview": { - "id": "ernie-5.0-thinking-preview", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "claude-opus-4-thinking:1024": { - "id": "claude-opus-4-thinking:1024", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32000 - } - }, - "llama-3.3-70b-strawberrylemonade-v1.2": { - "id": "Llama-3.3-70B-Strawberrylemonade-v1.2", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "llama-3.3-70b-vulpecula-r1": { - "id": "Llama-3.3-70B-Vulpecula-R1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "glm-4.6-derestricted-v5": { - "id": "GLM-4.6-Derestricted-v5", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 8192 - } - }, - "llama-3.3-70b-cirrus-x1": { - "id": "Llama-3.3-70B-Cirrus-x1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "llama-3.3-70b-arliai-rpmax-v2": { - "id": "Llama-3.3-70B-ArliAI-RPMax-v2", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "doubao-seed-code-preview-latest": { - "id": "doubao-seed-code-preview-latest", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 16384 - } - }, - "llama-3.3+(3.1v3.3)-70b-new-dawn-v1.1": { - "id": "Llama-3.3+(3.1v3.3)-70B-New-Dawn-v1.1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "qwen3-vl-235b-a22b-thinking": { - "id": "qwen3-vl-235b-a22b-thinking", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "claude-sonnet-4-thinking": { - "id": "claude-sonnet-4-thinking", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 64000 - } - }, - "qwen2.5-32b-eva-v0.2": { - "id": "Qwen2.5-32B-EVA-v0.2", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 24576, - "input": 24576, - "output": 8192 - } - }, - "llama-3.3-70b-cu-mai-r1": { - "id": "Llama-3.3-70B-Cu-Mai-R1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "hidream": { - "id": "hidream", - "reasoning": false, "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "image" - ] - }, - "limit": { - "context": 0, - "output": 0 - } - }, - "auto-model": { - "id": "auto-model", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 1000000 - } - }, - "jamba-mini-1.7": { - "id": "jamba-mini-1.7", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 4096 - } - }, - "doubao-seed-2-0-pro-260215": { - "id": "doubao-seed-2-0-pro-260215", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 128000 - } - }, - "llama-3.3-70b-nova": { - "id": "Llama-3.3-70B-Nova", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } + "family": "qwen" }, "gemini-2.5-flash-preview-09-2025-thinking": { "id": "gemini-2.5-flash-preview-09-2025-thinking", @@ -35313,115 +4232,6 @@ "output": 65536 } }, - "llama-3.3-70b-sapphira-0.2": { - "id": "Llama-3.3-70B-Sapphira-0.2", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "auto-model-standard": { - "id": "auto-model-standard", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 1000000 - } - }, - "grok-3-mini-fast-beta": { - "id": "grok-3-mini-fast-beta", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 131072 - } - }, - "meta-llama-3-1-8b-instruct-fp8": { - "id": "Meta-Llama-3-1-8B-Instruct-FP8", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "step-3": { - "id": "step-3", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "input": 65536, - "output": 8192 - } - }, - "universal-summarizer": { - "id": "universal-summarizer", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, "deepclaude": { "id": "deepclaude", "reasoning": false, @@ -35441,85 +4251,8 @@ "output": 8192 } }, - "brave-pro": { - "id": "brave-pro", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 8192, - "output": 8192 - } - }, - "claude-3-7-sonnet-reasoner": { - "id": "claude-3-7-sonnet-reasoner", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 8192 - } - }, - "claude-opus-4-thinking:8192": { - "id": "claude-opus-4-thinking:8192", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32000 - } - }, - "claude-opus-4-thinking:32768": { - "id": "claude-opus-4-thinking:32768", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 32000 - } - }, - "glm-zero-preview": { - "id": "glm-zero-preview", + "ernie-4.5-8k-preview": { + "id": "ernie-4.5-8k-preview", "reasoning": false, "toolCall": false, "modalities": { @@ -35533,12 +4266,30 @@ "limit": { "context": 8000, "input": 8000, - "output": 4096 + "output": 16384 } }, - "azure-gpt-4o-mini": { - "id": "azure-gpt-4o-mini", + "doubao-seed-2-0-mini-260215": { + "id": "doubao-seed-2-0-mini-260215", "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32000 + } + }, + "gemini-3-pro-preview-thinking": { + "id": "gemini-3-pro-preview-thinking", + "reasoning": true, "toolCall": true, "modalities": { "input": [ @@ -35549,14 +4300,72 @@ "text" ] }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "llama-3.3-70b-geneticlemonade-opus": { + "id": "Llama-3.3-70B-GeneticLemonade-Opus", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "v0-1.5-lg": { + "id": "v0-1.5-lg", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512000, + "input": 1000000, + "output": 32000 + }, + "family": "v0", + "temperature": true + }, + "ernie-4.5-turbo-128k": { + "id": "ernie-4.5-turbo-128k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, "limit": { "context": 128000, "input": 128000, "output": 16384 } }, - "deepseek-math-v2": { - "id": "deepseek-math-v2", + "kat-coder-pro-v1": { + "id": "KAT-Coder-Pro-V1", "reasoning": false, "toolCall": false, "modalities": { @@ -35568,50 +4377,14 @@ ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 65536 + "context": 256000, + "input": 256000, + "output": 32768 } }, - "glm-4-long": { - "id": "glm-4-long", + "claude-3-5-sonnet-20240620": { + "id": "claude-3-5-sonnet-20240620", "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 4096 - } - }, - "glm-4.5-air-derestricted-iceblink": { - "id": "GLM-4.5-Air-Derestricted-Iceblink", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 98304 - } - }, - "claude-opus-4-1-thinking:1024": { - "id": "claude-opus-4-1-thinking:1024", - "reasoning": true, "toolCall": true, "modalities": { "input": [ @@ -35626,45 +4399,10 @@ "limit": { "context": 200000, "input": 200000, - "output": 32000 - } - }, - "qwen3-vl-235b-a22b-instruct-original": { - "id": "qwen3-vl-235b-a22b-instruct-original", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] + "output": 8192 }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "llama-3.3+(3.1v3.3)-70b-hanami-x1": { - "id": "Llama-3.3+(3.1v3.3)-70B-Hanami-x1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } + "family": "claude-sonnet", + "temperature": true }, "claude-opus-4-1-thinking:8192": { "id": "claude-opus-4-1-thinking:8192", @@ -35686,8 +4424,26 @@ "output": 32000 } }, - "llama-3.3-70b-damascus-r1": { - "id": "Llama-3.3-70B-Damascus-R1", + "gemini-2.0-flash-exp-image-generation": { + "id": "gemini-2.0-flash-exp-image-generation", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + } + }, + "llama-3.3-70b-magnum-v4-se": { + "id": "Llama-3.3-70B-Magnum-v4-SE", "reasoning": false, "toolCall": false, "modalities": { @@ -35704,8 +4460,8 @@ "output": 16384 } }, - "gemma-3-27b-arliai-rpmax-v3": { - "id": "Gemma-3-27B-ArliAI-RPMax-v3", + "glm-zero-preview": { + "id": "glm-zero-preview", "reasoning": false, "toolCall": false, "modalities": { @@ -35717,14 +4473,14 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 16384 + "context": 8000, + "input": 8000, + "output": 4096 } }, - "gemini-2.5-flash-preview-05-20:thinking": { - "id": "gemini-2.5-flash-preview-05-20:thinking", - "reasoning": true, + "study_gpt-chatgpt-4o-latest": { + "id": "study_gpt-chatgpt-4o-latest", + "reasoning": false, "toolCall": false, "modalities": { "input": [ @@ -35735,52 +4491,14 @@ "text" ] }, - "limit": { - "context": 1048000, - "input": 1048000, - "output": 65536 - } - }, - "claude-opus-4-1-thinking:32000": { - "id": "claude-opus-4-1-thinking:32000", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, "limit": { "context": 200000, "input": 200000, - "output": 32000 - } - }, - "sarvan-medium": { - "id": "sarvan-medium", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, "output": 16384 } }, - "llama-3.3-70b-anthrobomination": { - "id": "Llama-3.3-70B-Anthrobomination", + "glm-4-airx": { + "id": "glm-4-airx", "reasoning": false, "toolCall": false, "modalities": { @@ -35792,49 +4510,13 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "baichuan4-air": { - "id": "Baichuan4-Air", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "jamba-mini": { - "id": "jamba-mini", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, + "context": 8000, + "input": 8000, "output": 4096 } }, - "kat-coder-exp-72b-1010": { - "id": "KAT-Coder-Exp-72B-1010", + "step-2-mini": { + "id": "step-2-mini", "reasoning": false, "toolCall": false, "modalities": { @@ -35846,9 +4528,9 @@ ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 32768 + "context": 8000, + "input": 8000, + "output": 4096 } }, "gemini-2.5-flash-preview-04-17:thinking": { @@ -35870,26 +4552,8 @@ "output": 65536 } }, - "brave-research": { - "id": "brave-research", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "llama-3.3-70b-argunaut-1-sft": { - "id": "Llama-3.3-70B-Argunaut-1-SFT", + "llama-3.3-70b-mokume-gane-r1": { + "id": "Llama-3.3-70B-Mokume-Gane-R1", "reasoning": false, "toolCall": false, "modalities": { @@ -35906,8 +4570,44 @@ "output": 16384 } }, - "claude-opus-4-5-20251101:thinking": { - "id": "claude-opus-4-5-20251101:thinking", + "glm-z1-airx": { + "id": "glm-z1-airx", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "jamba-mini-1.6": { + "id": "jamba-mini-1.6", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "claude-opus-4-1-thinking": { + "id": "claude-opus-4-1-thinking", "reasoning": true, "toolCall": true, "modalities": { @@ -35944,8 +4644,8 @@ "output": 131072 } }, - "azure-o3-mini": { - "id": "azure-o3-mini", + "llama-3.3-70b-legion-v2.1": { + "id": "Llama-3.3-70B-Legion-V2.1", "reasoning": false, "toolCall": false, "modalities": { @@ -35957,49 +4657,69 @@ ] }, "limit": { - "context": 200000, - "input": 200000, + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "sonar": { + "id": "sonar", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 130000, + "input": 127000, + "output": 16384 + }, + "family": "sonar", + "temperature": true + }, + "z-image-turbo": { + "id": "z-image-turbo", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "glm-4.5-air-derestricted-iceblink-v2": { + "id": "GLM-4.5-Air-Derestricted-Iceblink-v2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 158600, + "input": 158600, "output": 65536 } }, - "qwq-32b-arliai-rpr-v1": { - "id": "QwQ-32B-ArliAI-RpR-v1", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "llama-3.3-70b-forgotten-abomination-v5.0": { - "id": "Llama-3.3-70B-Forgotten-Abomination-v5.0", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 16384 - } - }, - "doubao-seed-2-0-code-preview-260215": { - "id": "doubao-seed-2-0-code-preview-260215", + "jamba-large": { + "id": "jamba-large", "reasoning": false, "toolCall": false, "modalities": { @@ -36013,29 +4733,68 @@ "limit": { "context": 256000, "input": 256000, - "output": 128000 + "output": 4096 } }, - "llama-3.3-70b-mhnnn-x1": { - "id": "Llama-3.3-70B-Mhnnn-x1", + "claude-3-7-sonnet-reasoner": { + "id": "claude-3-7-sonnet-reasoner", "reasoning": false, "toolCall": false, "modalities": { "input": [ - "text" + "text", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 32768, - "input": 32768, + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "ernie-4.5-turbo-vl-32k": { + "id": "ernie-4.5-turbo-vl-32k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, "output": 16384 } }, - "hunyuan-t1-latest": { - "id": "hunyuan-t1-latest", + "mistral-nemo-12b-instruct-2407": { + "id": "Mistral-Nemo-12B-Instruct-2407", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "doubao-seed-1-6-flash-250615": { + "id": "doubao-seed-1-6-flash-250615", "reasoning": false, "toolCall": false, "modalities": { @@ -36052,8 +4811,28 @@ "output": 16384 } }, - "gemma-3-27b-cardprojector-v4": { - "id": "Gemma-3-27B-CardProjector-v4", + "qwq-32b": { + "id": "qwq-32b", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 8192 + }, + "family": "qwen", + "temperature": true + }, + "llama-3.3-70b-strawberrylemonade-v1.2": { + "id": "Llama-3.3-70B-Strawberrylemonade-v1.2", "reasoning": false, "toolCall": false, "modalities": { @@ -36070,8 +4849,234 @@ "output": 16384 } }, - "glm-4-flash": { - "id": "glm-4-flash", + "gemini-2.5-flash-preview-04-17": { + "id": "gemini-2.5-flash-preview-04-17", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048756, + "output": 65536 + }, + "family": "gemini-flash", + "temperature": true + }, + "ernie-x1-turbo-32k": { + "id": "ernie-x1-turbo-32k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "deepseek-math-v2": { + "id": "deepseek-math-v2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "llama-3.3-70b-electranova-v1.0": { + "id": "Llama-3.3-70B-Electranova-v1.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-arliai-rpmax-v2": { + "id": "Llama-3.3-70B-ArliAI-RPMax-v2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "qwen-image": { + "id": "qwen-image", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + }, + "family": "qwen" + }, + "llama-3.3-70b-cu-mai-r1": { + "id": "Llama-3.3-70B-Cu-Mai-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4.5-air-derestricted-iceblink": { + "id": "GLM-4.5-Air-Derestricted-Iceblink", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 98304 + } + }, + "llama-3.3-70b-bigger-body": { + "id": "Llama-3.3-70B-Bigger-Body", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3+(3.1v3.3)-70b-hanami-x1": { + "id": "Llama-3.3+(3.1v3.3)-70B-Hanami-x1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "hunyuan-turbos-20250226": { + "id": "hunyuan-turbos-20250226", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 24000, + "input": 24000, + "output": 8192 + } + }, + "glm-4.6-derestricted-v5": { + "id": "GLM-4.6-Derestricted-v5", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + } + }, + "glm-4-plus": { + "id": "glm-4-plus", "reasoning": false, "toolCall": false, "modalities": { @@ -36088,26 +5093,8 @@ "output": 4096 } }, - "learnlm-1.5-pro-experimental": { - "id": "learnlm-1.5-pro-experimental", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32767, - "input": 32767, - "output": 8192 - } - }, - "llama-3.3-70b-dark-ages-v0.1": { - "id": "Llama-3.3-70B-Dark-Ages-v0.1", + "gemma-3-27b-big-tiger-v3": { + "id": "Gemma-3-27B-Big-Tiger-v3", "reasoning": false, "toolCall": false, "modalities": { @@ -36124,8 +5111,8 @@ "output": 16384 } }, - "yi-large": { - "id": "yi-large", + "brave-research": { + "id": "brave-research", "reasoning": false, "toolCall": false, "modalities": { @@ -36137,13 +5124,72 @@ ] }, "limit": { - "context": 32000, - "input": 32000, - "output": 4096 + "context": 16384, + "input": 16384, + "output": 16384 } }, - "exa-answer": { - "id": "exa-answer", + "hidream": { + "id": "hidream", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "qwen3-max-2026-01-23": { + "id": "qwen3-max-2026-01-23", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 65536 + }, + "family": "qwen", + "temperature": true + }, + "gemini-2.5-flash-nothinking": { + "id": "gemini-2.5-flash-nothinking", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "exa-research-pro": { + "id": "exa-research-pro", "reasoning": false, "toolCall": false, "modalities": { @@ -36155,9 +5201,48 @@ ] }, "limit": { - "context": 4096, - "input": 4096, - "output": 4096 + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "grok-3-fast-beta": { + "id": "grok-3-fast-beta", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + } + }, + "claude-opus-4-5-20251101:thinking": { + "id": "claude-opus-4-5-20251101:thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 } }, "gemini-2.5-pro-exp-03-25": { @@ -36179,6 +5264,1379 @@ "output": 65536 } }, + "claude-3-7-sonnet-thinking": { + "id": "claude-3-7-sonnet-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 16000 + } + }, + "claude-opus-4-thinking:8192": { + "id": "claude-opus-4-thinking:8192", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "claude-sonnet-4-thinking:1024": { + "id": "claude-sonnet-4-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "llama-3.3-70b-magnum-v4-se-cirrus-x1-slerp": { + "id": "Llama-3.3-70B-Magnum-v4-SE-Cirrus-x1-SLERP", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "step-r1-v-mini": { + "id": "step-r1-v-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "ernie-x1-32k-preview": { + "id": "ernie-x1-32k-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "llama-3.3-70b-strawberrylemonade-v1.0": { + "id": "Llama-3.3-70B-StrawberryLemonade-v1.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "kat-coder-exp-72b-1010": { + "id": "KAT-Coder-Exp-72B-1010", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "gemini-2.5-pro-preview-03-25": { + "id": "gemini-2.5-pro-preview-03-25", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "claude-opus-4-thinking:1024": { + "id": "claude-opus-4-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "claude-sonnet-4-20250514": { + "id": "claude-sonnet-4-20250514", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "family": "claude-sonnet", + "temperature": true + }, + "llama-3.3-70b-progenitor-v3.3": { + "id": "Llama-3.3-70B-Progenitor-V3.3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "qwen2.5-32b-eva-v0.2": { + "id": "Qwen2.5-32B-EVA-v0.2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 24576, + "input": 24576, + "output": 8192 + } + }, + "brave-pro": { + "id": "brave-pro", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "step-2-16k-exp": { + "id": "step-2-16k-exp", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "input": 16000, + "output": 8192 + } + }, + "llama-3.3-70b-fallen-r1-v1": { + "id": "Llama-3.3-70B-Fallen-R1-v1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-sonnet-4-thinking": { + "id": "claude-sonnet-4-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "doubao-1.5-pro-256k": { + "id": "doubao-1.5-pro-256k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "claude-3-7-sonnet-20250219": { + "id": "claude-3-7-sonnet-20250219", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "family": "claude-sonnet", + "temperature": true + }, + "learnlm-1.5-pro-experimental": { + "id": "learnlm-1.5-pro-experimental", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + } + }, + "chroma": { + "id": "chroma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "llama-3.3-70b-predatorial-extasy": { + "id": "Llama-3.3-70B-Predatorial-Extasy", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-aurora-borealis": { + "id": "Llama-3.3-70B-Aurora-Borealis", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-arliai-rpmax-v3": { + "id": "Llama-3.3-70B-ArliAI-RPMax-v3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "venice-uncensored": { + "id": "venice-uncensored", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 128000, + "output": 8192 + }, + "family": "venice", + "temperature": true + }, + "step-3": { + "id": "step-3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + } + }, + "llama-3.3-70b-the-omega-directive-unslop-v2.0": { + "id": "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "auto-model": { + "id": "auto-model", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "claude-opus-4-1-thinking:32768": { + "id": "claude-opus-4-1-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "llama-3.3-70b-shakudo": { + "id": "Llama-3.3-70B-Shakudo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "baichuan4-air": { + "id": "Baichuan4-Air", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "kimi-thinking-preview": { + "id": "kimi-thinking-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "llama-3.3-70b-mhnnn-x1": { + "id": "Llama-3.3-70B-Mhnnn-x1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-opus-4-thinking:32768": { + "id": "claude-opus-4-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "llama-3.3-70b-argunaut-1-sft": { + "id": "Llama-3.3-70B-Argunaut-1-SFT", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-opus-4-1-thinking:1024": { + "id": "claude-opus-4-1-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "gemini-2.5-flash-lite": { + "id": "gemini-2.5-flash-lite", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048756, + "output": 65536 + }, + "family": "gemini-flash-lite", + "temperature": true + }, + "phi-4-multimodal-instruct": { + "id": "phi-4-multimodal-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "doubao-seed-2-0-code-preview-260215": { + "id": "doubao-seed-2-0-code-preview-260215", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 128000 + } + }, + "deepseek-reasoner-cheaper": { + "id": "deepseek-reasoner-cheaper", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "exa-answer": { + "id": "exa-answer", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "input": 4096, + "output": 4096 + } + }, + "v0-1.0-md": { + "id": "v0-1.0-md", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 200000, + "output": 32000 + }, + "family": "v0", + "temperature": true + }, + "glm-4.1v-thinking-flash": { + "id": "glm-4.1v-thinking-flash", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + } + }, + "azure-o1": { + "id": "azure-o1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "glm-4.5-air-derestricted": { + "id": "GLM-4.5-Air-Derestricted", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202600, + "input": 202600, + "output": 98304 + } + }, + "azure-o3-mini": { + "id": "azure-o3-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 65536 + } + }, + "llama-3.3-70b-sapphira-0.2": { + "id": "Llama-3.3-70B-Sapphira-0.2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-anthrobomination": { + "id": "Llama-3.3-70B-Anthrobomination", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "qwq-32b-arliai-rpr-v1": { + "id": "QwQ-32B-ArliAI-RpR-v1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "claude-opus-4-20250514": { + "id": "claude-opus-4-20250514", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "family": "claude-opus", + "temperature": true + }, + "yi-lightning": { + "id": "yi-lightning", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 12000, + "input": 12000, + "output": 4096 + } + }, + "llama-3.3-70b-electra-r1": { + "id": "Llama-3.3-70B-Electra-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-forgotten-abomination-v5.0": { + "id": "Llama-3.3-70B-Forgotten-Abomination-v5.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-cirrus-x1": { + "id": "Llama-3.3-70B-Cirrus-x1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "grok-3-mini-beta": { + "id": "grok-3-mini-beta", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + } + }, + "auto-model-standard": { + "id": "auto-model-standard", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "v0-1.5-md": { + "id": "v0-1.5-md", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 200000, + "output": 32000 + }, + "family": "v0", + "temperature": true + }, + "kimi-k2-instruct-fast": { + "id": "kimi-k2-instruct-fast", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + } + }, + "glm-4-long": { + "id": "glm-4-long", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 4096 + } + }, + "jamba-large-1.7": { + "id": "jamba-large-1.7", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "gemini-2.0-flash-thinking-exp-1219": { + "id": "gemini-2.0-flash-thinking-exp-1219", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + } + }, + "azure-gpt-4-turbo": { + "id": "azure-gpt-4-turbo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "baichuan-m2": { + "id": "Baichuan-M2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "qwen-long": { + "id": "qwen-long", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 10000000, + "input": 10000000, + "output": 8192 + }, + "family": "qwen", + "temperature": true + }, + "sonar-reasoning-pro": { + "id": "sonar-reasoning-pro", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 127000, + "output": 16384 + }, + "family": "sonar", + "temperature": true + }, + "gemini-2.5-flash-preview-05-20:thinking": { + "id": "gemini-2.5-flash-preview-05-20:thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048000, + "input": 1048000, + "output": 65536 + } + }, + "glm-4.5-air-derestricted-steam-reextract": { + "id": "GLM-4.5-Air-Derestricted-Steam-ReExtract", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 65536 + } + }, + "llama-3.3-70b-dark-ages-v0.1": { + "id": "Llama-3.3-70B-Dark-Ages-v0.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "baichuan4-turbo": { + "id": "Baichuan4-Turbo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "doubao-1.5-vision-pro-32k": { + "id": "doubao-1.5-vision-pro-32k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + } + }, + "inflection/inflection-3-pi": { + "id": "inflection/inflection-3-pi", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 1024 + }, + "temperature": true + }, + "inflection/inflection-3-productivity": { + "id": "inflection/inflection-3-productivity", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 1024 + }, + "temperature": true + }, + "essentialai/rnj-1-instruct": { + "id": "essentialai/Rnj-1-Instruct", + "family": "rnj", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 128000, + "output": 32768 + }, + "temperature": true + }, "llm360/k2-think": { "id": "LLM360/K2-Think", "family": "kimi-thinking", @@ -36198,501 +6656,6 @@ "output": 32768 } }, - "abacusai/dracarys-72b-instruct": { - "id": "abacusai/Dracarys-72B-Instruct", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "envoid/llama-3.05-nemotron-tenyxchat-storybreaker-70b": { - "id": "Envoid/Llama-3.05-Nemotron-Tenyxchat-Storybreaker-70B", - "family": "nemotron", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "envoid/llama-3.05-nt-storybreaker-ministral-70b": { - "id": "Envoid/Llama-3.05-NT-Storybreaker-Ministral-70B", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "zai-org/glm-5:thinking": { - "id": "zai-org/glm-5:thinking", - "family": "glm", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 128000 - } - }, - "nvidia/llama-3.1-nemotron-70b-instruct-hf": { - "id": "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF", - "family": "nemotron", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "nvidia/llama-3_3-nemotron-super-49b-v1_5": { - "id": "nvidia/Llama-3_3-Nemotron-Super-49B-v1_5", - "family": "nemotron", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "doctor-shotgun/ms3.2-24b-magnum-diamond": { - "id": "Doctor-Shotgun/MS3.2-24B-Magnum-Diamond", - "family": "mistral", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 32768 - } - }, - "arcee-ai/trinity-large": { - "id": "arcee-ai/trinity-large", - "family": "trinity", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 8192 - } - }, - "meganova-ai/manta-flash-1.0": { - "id": "meganova-ai/manta-flash-1.0", - "family": "nova", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "meganova-ai/manta-pro-1.0": { - "id": "meganova-ai/manta-pro-1.0", - "family": "nova", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "meganova-ai/manta-mini-1.0": { - "id": "meganova-ai/manta-mini-1.0", - "family": "nova", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 8192, - "output": 8192 - } - }, - "xiaomi/mimo-v2-flash-original": { - "id": "xiaomi/mimo-v2-flash-original", - "family": "mimo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 32768 - } - }, - "xiaomi/mimo-v2-flash-thinking": { - "id": "xiaomi/mimo-v2-flash-thinking", - "family": "mimo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 32768 - } - }, - "xiaomi/mimo-v2-flash-thinking-original": { - "id": "xiaomi/mimo-v2-flash-thinking-original", - "family": "mimo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 256000, - "input": 256000, - "output": 32768 - } - }, - "microsoft/mai-ds-r1-fp8": { - "id": "microsoft/MAI-DS-R1-FP8", - "family": "deepseek", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 8192 - } - }, - "failspy/meta-llama-3-70b-instruct-abliterated-v3.5": { - "id": "failspy/Meta-Llama-3-70B-Instruct-abliterated-v3.5", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 8192, - "output": 8192 - } - }, - "featherless-ai/qwerky-72b": { - "id": "featherless-ai/Qwerky-72B", - "family": "qwerky", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 8192 - } - }, - "tee/glm-5": { - "id": "TEE/glm-5", - "family": "glm", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 203000, - "input": 203000, - "output": 65535 - } - }, - "tee/deepseek-v3.1": { - "id": "TEE/deepseek-v3.1", - "family": "deepseek", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 164000, - "input": 164000, - "output": 8192 - } - }, - "tee/glm-4.7-flash": { - "id": "TEE/glm-4.7-flash", - "family": "glm-flash", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 203000, - "input": 203000, - "output": 65535 - } - }, - "tee/qwen3-coder": { - "id": "TEE/qwen3-coder", - "family": "qwen", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 32768 - } - }, - "tee/glm-4.6": { - "id": "TEE/glm-4.6", - "family": "glm", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 203000, - "input": 203000, - "output": 65535 - } - }, - "tee/deepseek-r1-0528": { - "id": "TEE/deepseek-r1-0528", - "family": "deepseek", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 65536 - } - }, - "tee/minimax-m2.1": { - "id": "TEE/minimax-m2.1", - "family": "minimax", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 131072 - } - }, - "tee/qwen3.5-397b-a17b": { - "id": "TEE/qwen3.5-397b-a17b", - "family": "qwen", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 258048, - "input": 258048, - "output": 65536 - } - }, - "tee/gpt-oss-120b": { - "id": "TEE/gpt-oss-120b", - "family": "gpt-oss", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 16384 - } - }, "tee/kimi-k2.5": { "id": "TEE/kimi-k2.5", "family": "kimi", @@ -36712,8 +6675,27 @@ "output": 65535 } }, - "tee/qwen3-30b-a3b-instruct-2507": { - "id": "TEE/qwen3-30b-a3b-instruct-2507", + "tee/glm-4.7": { + "id": "TEE/glm-4.7", + "family": "glm", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 131000, + "output": 65535 + } + }, + "tee/qwen3.5-397b-a17b": { + "id": "TEE/qwen3.5-397b-a17b", "family": "qwen", "reasoning": false, "toolCall": false, @@ -36726,15 +6708,15 @@ ] }, "limit": { - "context": 262000, - "input": 262000, - "output": 32768 + "context": 258048, + "input": 258048, + "output": 65536 } }, - "tee/kimi-k2.5-thinking": { - "id": "TEE/kimi-k2.5-thinking", - "family": "kimi-thinking", - "reasoning": true, + "tee/glm-5": { + "id": "TEE/glm-5", + "family": "glm", + "reasoning": false, "toolCall": false, "modalities": { "input": [ @@ -36745,8 +6727,8 @@ ] }, "limit": { - "context": 128000, - "input": 128000, + "context": 203000, + "input": 203000, "output": 65535 } }, @@ -36770,8 +6752,46 @@ "output": 8192 } }, - "tee/deepseek-v3.2": { - "id": "TEE/deepseek-v3.2", + "tee/minimax-m2.1": { + "id": "TEE/minimax-m2.1", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + } + }, + "tee/qwen3-30b-a3b-instruct-2507": { + "id": "TEE/qwen3-30b-a3b-instruct-2507", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "input": 262000, + "output": 32768 + } + }, + "tee/deepseek-v3.1": { + "id": "TEE/deepseek-v3.1", "family": "deepseek", "reasoning": false, "toolCall": false, @@ -36786,45 +6806,7 @@ "limit": { "context": 164000, "input": 164000, - "output": 65536 - } - }, - "tee/glm-4.7": { - "id": "TEE/glm-4.7", - "family": "glm", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "input": 131000, - "output": 65535 - } - }, - "tee/kimi-k2-thinking": { - "id": "TEE/kimi-k2-thinking", - "family": "kimi-thinking", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 65535 + "output": 8192 } }, "tee/llama3-3-70b": { @@ -36846,6 +6828,44 @@ "output": 16384 } }, + "tee/glm-4.6": { + "id": "TEE/glm-4.6", + "family": "glm", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + } + }, + "tee/kimi-k2.5-thinking": { + "id": "TEE/kimi-k2.5-thinking", + "family": "kimi-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + } + }, "tee/gemma-3-27b-it": { "id": "TEE/gemma-3-27b-it", "family": "gemma", @@ -36865,6 +6885,25 @@ "output": 8192 } }, + "tee/deepseek-v3.2": { + "id": "TEE/deepseek-v3.2", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 164000, + "output": 65536 + } + }, "tee/gpt-oss-20b": { "id": "TEE/gpt-oss-20b", "family": "gpt-oss", @@ -36884,8 +6923,103 @@ "output": 8192 } }, - "anthracite-org/magnum-v2-72b": { - "id": "anthracite-org/magnum-v2-72b", + "tee/qwen3-coder": { + "id": "TEE/qwen3-coder", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "tee/glm-4.7-flash": { + "id": "TEE/glm-4.7-flash", + "family": "glm-flash", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + } + }, + "tee/gpt-oss-120b": { + "id": "TEE/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + } + }, + "tee/deepseek-r1-0528": { + "id": "TEE/deepseek-r1-0528", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "tee/kimi-k2-thinking": { + "id": "TEE/kimi-k2-thinking", + "family": "kimi-thinking", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + } + }, + "cruciblelab/l3.3-70b-loki-v2.0": { + "id": "CrucibleLab/L3.3-70B-Loki-V2.0", "family": "llama", "reasoning": false, "toolCall": false, @@ -36900,6 +7034,470 @@ "limit": { "context": 16384, "input": 16384, + "output": 16384 + } + }, + "deepseek/deepseek-v3.2:thinking": { + "id": "deepseek/deepseek-v3.2:thinking", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163000, + "input": 163000, + "output": 65536 + } + }, + "deepseek/deepseek-prover-v2-671b": { + "id": "deepseek/deepseek-prover-v2-671b", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "input": 160000, + "output": 160000 + }, + "temperature": true + }, + "deepseek/deepseek-v3.2-speciale": { + "id": "deepseek/deepseek-v3.2-speciale", + "family": "deepseek", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 163000, + "output": 163840 + }, + "temperature": true + }, + "deepseek/deepseek-v3.2": { + "id": "deepseek/deepseek-v3.2", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163842, + "input": 163000, + "output": 8000 + }, + "temperature": true + }, + "doctor-shotgun/ms3.2-24b-magnum-diamond": { + "id": "Doctor-Shotgun/MS3.2-24B-Magnum-Diamond", + "family": "mistral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "neversleep/llama-3-lumimaid-70b-v0.1": { + "id": "NeverSleep/Llama-3-Lumimaid-70B-v0.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "neversleep/lumimaid-v0.2-70b": { + "id": "NeverSleep/Lumimaid-v0.2-70B", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "steelskull/l3.3-cu-mai-r1-70b": { + "id": "Steelskull/L3.3-Cu-Mai-R1-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-nevoria-r1-70b": { + "id": "Steelskull/L3.3-Nevoria-R1-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-ms-evayale-70b": { + "id": "Steelskull/L3.3-MS-Evayale-70B", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-electra-r1-70b": { + "id": "Steelskull/L3.3-Electra-R1-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-ms-nevoria-70b": { + "id": "Steelskull/L3.3-MS-Nevoria-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-ms-evalebis-70b": { + "id": "Steelskull/L3.3-MS-Evalebis-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "miromind-ai/mirothinker-v1.5-235b": { + "id": "miromind-ai/MiroThinker-v1.5-235B", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 32768, + "output": 8192 + }, + "temperature": true + }, + "pamanseau/openreasoning-nemotron-32b": { + "id": "pamanseau/OpenReasoning-Nemotron-32B", + "family": "nemotron", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 65536 + } + }, + "arcee-ai/trinity-mini": { + "id": "arcee-ai/trinity-mini", + "family": "trinity", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + }, + "temperature": true + }, + "arcee-ai/trinity-large": { + "id": "arcee-ai/trinity-large", + "family": "trinity", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + } + }, + "cognitivecomputations/dolphin-2.9.2-qwen2-72b": { + "id": "cognitivecomputations/dolphin-2.9.2-qwen2-72b", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 4096 + } + }, + "deepcogito/cogito-v1-preview-qwen-32b": { + "id": "deepcogito/cogito-v1-preview-qwen-32B", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "deepcogito/cogito-v2.1-671b": { + "id": "deepcogito/cogito-v2.1-671b", + "family": "cogito", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "temperature": true + }, + "salesforce/llama-xlam-2-70b-fc-r": { + "id": "Salesforce/Llama-xLAM-2-70b-fc-r", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "nousresearch 2/hermes-4-405b:thinking": { + "id": "NousResearch 2/hermes-4-405b:thinking", + "family": "nousresearch", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "nousresearch 2/deephermes-3-mistral-24b-preview": { + "id": "NousResearch 2/DeepHermes-3-Mistral-24B-Preview", + "family": "nousresearch", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "nousresearch 2/hermes-4-70b:thinking": { + "id": "NousResearch 2/Hermes-4-70B:thinking", + "family": "nousresearch", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, "output": 8192 } }, @@ -36941,25 +7539,6 @@ "output": 8192 } }, - "nousresearch 2/deephermes-3-mistral-24b-preview": { - "id": "NousResearch 2/DeepHermes-3-Mistral-24B-Preview", - "family": "nousresearch", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 32768 - } - }, "nousresearch 2/hermes-4-70b": { "id": "NousResearch 2/hermes-4-70b", "family": "nousresearch", @@ -36979,48 +7558,10 @@ "output": 8192 } }, - "nousresearch 2/hermes-4-405b:thinking": { - "id": "NousResearch 2/hermes-4-405b:thinking", - "family": "nousresearch", + "soob3123/veiled-calla-12b": { + "id": "soob3123/Veiled-Calla-12B", + "family": "llama", "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 8192 - } - }, - "nousresearch 2/hermes-4-70b:thinking": { - "id": "NousResearch 2/Hermes-4-70B:thinking", - "family": "nousresearch", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 8192 - } - }, - "pamanseau/openreasoning-nemotron-32b": { - "id": "pamanseau/OpenReasoning-Nemotron-32B", - "family": "nemotron", - "reasoning": true, "toolCall": false, "modalities": { "input": [ @@ -37033,31 +7574,12 @@ "limit": { "context": 32768, "input": 32768, - "output": 65536 + "output": 8192 } }, - "deepseek-ai/deepseek-v3.2-exp-thinking": { - "id": "deepseek-ai/deepseek-v3.2-exp-thinking", - "family": "deepseek-thinking", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "input": 163840, - "output": 65536 - } - }, - "deepseek-ai/deepseek-v3.1:thinking": { - "id": "deepseek-ai/DeepSeek-V3.1:thinking", - "family": "deepseek-thinking", + "soob3123/grayline-qwen3-8b": { + "id": "soob3123/GrayLine-Qwen3-8B", + "family": "qwen", "reasoning": false, "toolCall": false, "modalities": { @@ -37069,14 +7591,227 @@ ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 65536 + "context": 16384, + "input": 16384, + "output": 32768 } }, - "deepseek-ai/deepseek-v3.1-terminus:thinking": { - "id": "deepseek-ai/DeepSeek-V3.1-Terminus:thinking", - "family": "deepseek-thinking", + "soob3123/amoral-gemma3-27b-v2": { + "id": "soob3123/amoral-gemma3-27B-v2", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "nex-agi/deepseek-v3.1-nex-n1": { + "id": "nex-agi/DeepSeek-V3.1-Nex-N1", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 128000, + "output": 131000 + }, + "temperature": true + }, + "envoid/llama-3.05-nt-storybreaker-ministral-70b": { + "id": "Envoid/Llama-3.05-NT-Storybreaker-Ministral-70B", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "envoid/llama-3.05-nemotron-tenyxchat-storybreaker-70b": { + "id": "Envoid/Llama-3.05-Nemotron-Tenyxchat-Storybreaker-70B", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "anthracite-org/magnum-v4-72b": { + "id": "anthracite-org/magnum-v4-72b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 2048 + }, + "temperature": true + }, + "anthracite-org/magnum-v2-72b": { + "id": "anthracite-org/magnum-v2-72b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "readyart/ms3.2-the-omega-directive-24b-unslop-v2.0": { + "id": "ReadyArt/MS3.2-The-Omega-Directive-24B-Unslop-v2.0", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "readyart/the-omega-abomination-l-70b-v1.0": { + "id": "ReadyArt/The-Omega-Abomination-L-70B-v1.0", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "undi95/remm-slerp-l2-13b": { + "id": "undi95/remm-slerp-l2-13b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 6144, + "input": 6144, + "output": 4096 + }, + "temperature": true + }, + "marinaraspaghetti/nemomix-unleashed-12b": { + "id": "MarinaraSpaghetti/NemoMix-Unleashed-12B", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "allenai/molmo-2-8b": { + "id": "allenai/molmo-2-8b", + "family": "allenai", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 36864, + "input": 36864, + "output": 36864 + } + }, + "allenai/olmo-3.1-32b-instruct": { + "id": "allenai/olmo-3.1-32b-instruct", + "family": "allenai", "reasoning": false, "toolCall": true, "modalities": { @@ -37088,9 +7823,244 @@ ] }, "limit": { - "context": 128000, + "context": 65536, + "input": 65536, + "output": 32768 + }, + "temperature": true + }, + "allenai/olmo-3.1-32b-think": { + "id": "allenai/olmo-3.1-32b-think", + "family": "allenai", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + } + }, + "allenai/olmo-3-32b-think": { + "id": "allenai/olmo-3-32b-think", + "family": "allenai", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, "input": 128000, "output": 65536 + }, + "temperature": true + }, + "stepfun-ai/step-3.5-flash:thinking": { + "id": "stepfun-ai/step-3.5-flash:thinking", + "family": "step", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + } + }, + "stepfun-ai/step-3.5-flash": { + "id": "stepfun-ai/Step-3.5-Flash", + "family": "step", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "input": 256000, + "output": 262000 + }, + "temperature": true + }, + "zai-org/glm-4.7": { + "id": "zai-org/GLM-4.7", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 200000, + "output": 8192 + }, + "temperature": true + }, + "zai-org/glm-5": { + "id": "zai-org/GLM-5", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "input": 200000, + "output": 205000 + }, + "temperature": true + }, + "zai-org/glm-5.1": { + "id": "zai-org/glm-5.1", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202000, + "input": 200000, + "output": 202000 + }, + "temperature": true + }, + "zai-org/glm-5.1:thinking": { + "id": "zai-org/glm-5.1:thinking", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + } + }, + "zai-org/glm-5:thinking": { + "id": "zai-org/glm-5:thinking", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 128000 + } + }, + "zai-org/glm-4.7-flash": { + "id": "zai-org/GLM-4.7-Flash", + "family": "glm-flash", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "input": 200000, + "output": 16384 + }, + "temperature": true + }, + "featherless-ai/qwerky-72b": { + "id": "featherless-ai/Qwerky-72B", + "family": "qwerky", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + } + }, + "mlabonne/neuraldaredevil-8b-abliterated": { + "id": "mlabonne/NeuralDaredevil-8B-abliterated", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 } }, "raifle/sorcererlm-8x22b": { @@ -37113,8 +8083,371 @@ "output": 8192 } }, - "mlabonne/neuraldaredevil-8b-abliterated": { - "id": "mlabonne/NeuralDaredevil-8B-abliterated", + "mistralai/mixtral-8x7b-instruct-v0.1": { + "id": "mistralai/mixtral-8x7b-instruct-v0.1", + "family": "mixtral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "mistralai/mistral-saba": { + "id": "mistralai/mistral-saba", + "family": "mistral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32000, + "output": 32768 + }, + "temperature": true + }, + "mistralai/mistral-large-3-675b-instruct-2512": { + "id": "mistralai/mistral-large-3-675b-instruct-2512", + "family": "mistral-large", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 262144 + }, + "temperature": true + }, + "mistralai/devstral-2-123b-instruct-2512": { + "id": "mistralai/devstral-2-123b-instruct-2512", + "family": "devstral", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 262144 + }, + "temperature": true + }, + "mistralai/codestral-2508": { + "id": "mistralai/codestral-2508", + "family": "codestral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 51200 + }, + "temperature": true + }, + "mistralai/ministral-14b-instruct-2512": { + "id": "mistralai/ministral-14b-instruct-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 262144 + }, + "temperature": true + }, + "mistralai/mistral-tiny": { + "id": "mistralai/mistral-tiny", + "family": "mistral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + } + }, + "mistralai/ministral-8b-2512": { + "id": "mistralai/ministral-8b-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 32768 + }, + "temperature": true + }, + "mistralai/mixtral-8x22b-instruct-v0.1": { + "id": "mistralai/mixtral-8x22b-instruct-v0.1", + "family": "mixtral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 32768 + } + }, + "mistralai/mistral-medium-3.1": { + "id": "mistralai/mistral-medium-3.1", + "family": "mistral-medium", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 26215 + }, + "temperature": true + }, + "mistralai/ministral-3b-2512": { + "id": "mistralai/ministral-3b-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "temperature": true + }, + "mistralai/mistral-nemo-instruct-2407": { + "id": "mistralai/Mistral-Nemo-Instruct-2407", + "family": "mistral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 16384, + "output": 65536 + }, + "temperature": true + }, + "mistralai/mistral-medium-3": { + "id": "mistralai/mistral-medium-3", + "family": "mistral-medium", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 26215 + }, + "temperature": true + }, + "mistralai/mistral-7b-instruct": { + "id": "mistralai/mistral-7b-instruct", + "family": "mistral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "mistralai/devstral-small-2505": { + "id": "mistralai/Devstral-Small-2505", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 32768, + "output": 4096 + }, + "temperature": true + }, + "mistralai/mistral-small-creative": { + "id": "mistralai/mistral-small-creative", + "family": "mistral-small", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "mistralai/mistral-large": { + "id": "mistralai/mistral-large", + "family": "mistral-large", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 25600 + }, + "temperature": true + }, + "mistralai/ministral-14b-2512": { + "id": "mistralai/ministral-14b-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 52429 + }, + "temperature": true + }, + "shisa-ai/shisa-v2.1-llama3.3-70b": { + "id": "shisa-ai/shisa-v2.1-llama3.3-70b", "family": "llama", "reasoning": false, "toolCall": false, @@ -37126,12 +8459,2423 @@ "text" ] }, + "limit": { + "context": 32768, + "input": 32768, + "output": 4096 + } + }, + "shisa-ai/shisa-v2-llama3.3-70b": { + "id": "shisa-ai/shisa-v2-llama3.3-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "meta-llama/llama-3.3-70b-instruct": { + "id": "meta-llama/Llama-3.3-70B-Instruct", + "family": "llama", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "temperature": true + }, + "meta-llama/llama-4-scout": { + "id": "meta-llama/llama-4-scout", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 327680, + "input": 328000, + "output": 16384 + }, + "temperature": true + }, + "meta-llama/llama-4-maverick": { + "id": "meta-llama/llama-4-maverick", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048576, + "output": 16384 + }, + "temperature": true + }, + "meta-llama/llama-3.2-90b-vision-instruct": { + "id": "meta-llama/Llama-3.2-90B-Vision-Instruct", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "input": 131072, + "output": 4096 + }, + "temperature": true + }, + "meta-llama/llama-3.2-3b-instruct": { + "id": "meta-llama/llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 80000, + "input": 131072, + "output": 16384 + }, + "temperature": true + }, + "meta-llama/llama-3.1-8b-instruct": { + "id": "meta-llama/Llama-3.1-8B-Instruct", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8000 + }, + "temperature": true + }, + "galrionsoftworks/mn-loosecannon-12b-v1": { + "id": "GalrionSoftworks/MN-LooseCannon-12B-v1", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "baseten/kimi-k2-instruct-fp4": { + "id": "baseten/Kimi-K2-Instruct-FP4", + "family": "kimi", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + } + }, + "gryphe/mythomax-l2-13b": { + "id": "gryphe/mythomax-l2-13b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "input": 4000, + "output": 4096 + }, + "temperature": true + }, + "x-ai/grok-4-fast:thinking": { + "id": "x-ai/grok-4-fast:thinking", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 131072 + } + }, + "x-ai/grok-4-07-09": { + "id": "x-ai/grok-4-07-09", + "family": "grok", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 131072 + } + }, + "x-ai/grok-4-fast": { + "id": "x-ai/grok-4-fast", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 30000 + }, + "temperature": true + }, + "x-ai/grok-code-fast-1": { + "id": "x-ai/grok-code-fast-1", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 10000 + }, + "temperature": true + }, + "x-ai/grok-4.1-fast": { + "id": "x-ai/grok-4.1-fast", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 30000 + }, + "temperature": true + }, + "x-ai/grok-4.1-fast-reasoning": { + "id": "x-ai/grok-4.1-fast-reasoning", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 20000000, + "input": 2000000, + "output": 2000000 + }, + "temperature": true + }, + "tencent/hunyuan-mt-7b": { + "id": "tencent/Hunyuan-MT-7B", + "family": "hunyuan", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "input": 8192, + "output": 33000 + }, + "temperature": true + }, + "microsoft/wizardlm-2-8x22b": { + "id": "microsoft/wizardlm-2-8x22b", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65535, + "input": 65536, + "output": 8000 + }, + "temperature": true + }, + "microsoft/mai-ds-r1-fp8": { + "id": "microsoft/MAI-DS-R1-FP8", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "cohere/command-r": { + "id": "cohere/command-r", + "family": "command-r", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "cohere/command-r-plus-08-2024": { + "id": "cohere/command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4000 + }, + "temperature": true + }, + "chutesai/mistral-small-3.2-24b-instruct-2506": { + "id": "chutesai/Mistral-Small-3.2-24B-Instruct-2506", + "family": "chutesai", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 131072 + }, + "temperature": true + }, + "nvidia/llama-3.1-nemotron-ultra-253b-v1": { + "id": "nvidia/llama-3.1-nemotron-ultra-253b-v1", + "family": "llama", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 8192 + }, + "temperature": true + }, + "nvidia/nemotron-3-nano-30b-a3b": { + "id": "nvidia/nemotron-3-nano-30b-a3b", + "family": "nemotron", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 262144 + }, + "temperature": true + }, + "nvidia/nvidia-nemotron-nano-9b-v2": { + "id": "nvidia/nvidia-nemotron-nano-9b-v2", + "family": "nemotron", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 131072 + }, + "temperature": true + }, + "nvidia/llama-3.1-nemotron-70b-instruct-hf": { + "id": "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "nvidia/llama-3.3-nemotron-super-49b-v1": { + "id": "nvidia/llama-3.3-nemotron-super-49b-v1", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "temperature": true + }, + "nvidia/llama-3_3-nemotron-super-49b-v1_5": { + "id": "nvidia/Llama-3_3-Nemotron-Super-49B-v1_5", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "thedrummer 2/anubis-70b-v1": { + "id": "TheDrummer 2/Anubis-70B-v1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 16384 + } + }, + "thedrummer 2/cydonia-24b-v4.3": { + "id": "TheDrummer 2/Cydonia-24B-v4.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "thedrummer 2/magidonia-24b-v4.3": { + "id": "TheDrummer 2/Magidonia-24B-v4.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "thedrummer 2/cydonia-24b-v4": { + "id": "TheDrummer 2/Cydonia-24B-v4", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "thedrummer 2/anubis-70b-v1.1": { + "id": "TheDrummer 2/Anubis-70B-v1.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + } + }, + "thedrummer 2/rocinante-12b-v1.1": { + "id": "TheDrummer 2/Rocinante-12B-v1.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "thedrummer 2/cydonia-24b-v4.1": { + "id": "TheDrummer 2/Cydonia-24B-v4.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "thedrummer 2/unslopnemo-12b-v4.1": { + "id": "TheDrummer 2/UnslopNemo-12B-v4.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "thedrummer 2/cydonia-24b-v2": { + "id": "TheDrummer 2/Cydonia-24B-v2", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "thedrummer 2/skyfall-36b-v2": { + "id": "TheDrummer 2/skyfall-36b-v2", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 32768 + } + }, + "deepseek-ai/deepseek-v3.1:thinking": { + "id": "deepseek-ai/DeepSeek-V3.1:thinking", + "family": "deepseek-thinking", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.1": { + "id": "deepseek-ai/DeepSeek-V3.1", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 128000, + "output": 164000 + }, + "temperature": true + }, + "deepseek-ai/deepseek-v3.1-terminus:thinking": { + "id": "deepseek-ai/DeepSeek-V3.1-Terminus:thinking", + "family": "deepseek-thinking", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.2-exp-thinking": { + "id": "deepseek-ai/deepseek-v3.2-exp-thinking", + "family": "deepseek-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.2-exp": { + "id": "deepseek-ai/DeepSeek-V3.2-Exp", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 163840, + "output": 164000 + }, + "temperature": true + }, + "deepseek-ai/deepseek-r1-0528": { + "id": "deepseek-ai/deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + }, + "temperature": true + }, + "deepseek-ai/deepseek-v3.1-terminus": { + "id": "deepseek-ai/DeepSeek-V3.1-Terminus", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 128000, + "output": 164000 + }, + "temperature": true + }, + "openai/gpt-5.1-codex-max": { + "id": "openai/gpt-5.1-codex-max", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5.2-chat": { + "id": "openai/gpt-5.2-chat", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-4o-mini-search-preview": { + "id": "openai/gpt-4o-mini-search-preview", + "family": "gpt-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "temperature": true + }, + "openai/chatgpt-4o-latest": { + "id": "openai/chatgpt-4o-latest", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "temperature": false + }, + "openai/gpt-5.2-pro": { + "id": "openai/gpt-5.2-pro", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5-mini": { + "id": "openai/gpt-5-mini", + "family": "gpt-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5-nano": { + "id": "openai/gpt-5-nano", + "family": "gpt-nano", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-4-turbo": { + "id": "openai/gpt-4-turbo", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "temperature": true + }, + "openai/gpt-5.2": { + "id": "openai/gpt-5.2", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/o3-mini-high": { + "id": "openai/o3-mini-high", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-4o-mini": { + "id": "openai/gpt-4o-mini", + "family": "gpt-mini", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "openai/o4-mini-deep-research": { + "id": "openai/o4-mini-deep-research", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-5.1-chat": { + "id": "openai/gpt-5.1-chat", + "family": "gpt-codex", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 400000, + "output": 16384 + }, + "temperature": true + }, + "openai/o4-mini": { + "id": "openai/o4-mini", + "family": "o-mini", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-5.2-codex": { + "id": "openai/gpt-5.2-codex", + "family": "gpt-codex", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5.1-codex-mini": { + "id": "openai/gpt-5.1-codex-mini", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/o1-preview": { + "id": "openai/o1-preview", + "family": "o", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "temperature": false + }, + "openai/gpt-4o-2024-08-06": { + "id": "openai/gpt-4o-2024-08-06", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-5.1": { + "id": "openai/gpt-5.1", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/o1": { + "id": "openai/o1", + "family": "o", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-3.5-turbo": { + "id": "openai/gpt-3.5-turbo", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "input": 12289, + "output": 4096 + }, + "temperature": true + }, + "openai/o3-deep-research": { + "id": "openai/o3-deep-research", + "family": "o", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 100000, + "output": 100000 + }, + "temperature": false + }, + "openai/o3-mini": { + "id": "openai/o3-mini", + "family": "o-mini", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-4-turbo-preview": { + "id": "openai/gpt-4-turbo-preview", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "temperature": true + }, + "openai/o1-pro": { + "id": "openai/o1-pro", + "family": "o-pro", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-5-codex": { + "id": "openai/gpt-5-codex", + "family": "gpt-codex", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": false + }, + "openai/gpt-5.1-chat-latest": { + "id": "openai/gpt-5.1-chat-latest", + "family": "gpt", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 400000, + "output": 16384 + } + }, + "openai/gpt-4o-search-preview": { + "id": "openai/gpt-4o-search-preview", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "openai/gpt-4.1-nano": { + "id": "openai/gpt-4.1-nano", + "family": "gpt-nano", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 1047576, + "output": 16384 + }, + "temperature": true + }, + "openai/o4-mini-high": { + "id": "openai/o4-mini-high", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "openai/o3": { + "id": "openai/o3", + "family": "o", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-oss-20b": { + "id": "openai/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 98304, + "output": 65536 + }, + "temperature": true + }, + "openai/gpt-5-pro": { + "id": "openai/gpt-5-pro", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 400000, + "input": 128000, + "output": 272000 + }, + "temperature": true + }, + "openai/gpt-5.1-2025-11-13": { + "id": "openai/gpt-5.1-2025-11-13", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 32768 + } + }, + "openai/gpt-4o": { + "id": "openai/gpt-4o", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "openai/o3-mini-low": { + "id": "openai/o3-mini-low", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "openai/gpt-5": { + "id": "openai/gpt-5", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-oss-safeguard-20b": { + "id": "openai/gpt-oss-safeguard-20b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 65536, + "output": 65536 + }, + "temperature": true + }, + "openai/o3-pro-2025-06-10": { + "id": "openai/o3-pro-2025-06-10", + "family": "o-pro", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "openai/gpt-oss-120b": { + "id": "openai/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 124000, + "output": 131072 + }, + "temperature": true + }, + "openai/gpt-5-chat-latest": { + "id": "openai/gpt-5-chat-latest", + "family": "gpt", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + } + }, + "openai/gpt-4.1": { + "id": "openai/gpt-4.1", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 1047576, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-4.1-mini": { + "id": "openai/gpt-4.1-mini", + "family": "gpt-mini", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 1047576, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-5.1-codex": { + "id": "openai/gpt-5.1-codex", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-4o-2024-11-20": { + "id": "openai/gpt-4o-2024-11-20", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "vongolachouko/starcannon-unleashed-12b-v1.0": { + "id": "VongolaChouko/Starcannon-Unleashed-12B-v1.0", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "amazon/nova-lite-v1": { + "id": "amazon/nova-lite-v1", + "family": "nova-lite", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "input": 300000, + "output": 5120 + }, + "temperature": true + }, + "amazon/nova-pro-v1": { + "id": "amazon/nova-pro-v1", + "family": "nova-pro", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "input": 300000, + "output": 5120 + }, + "temperature": true + }, + "amazon/nova-2-lite-v1": { + "id": "amazon/nova-2-lite-v1", + "family": "nova", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 65535 + }, + "temperature": true + }, + "amazon/nova-micro-v1": { + "id": "amazon/nova-micro-v1", + "family": "nova-micro", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 5120 + }, + "temperature": true + }, + "sao10k/l3.3-70b-euryale-v2.3": { + "id": "Sao10K/L3.3-70B-Euryale-v2.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 20480, + "input": 20480, + "output": 16384 + } + }, + "sao10k/l3.1-70b-euryale-v2.2": { + "id": "Sao10K/L3.1-70B-Euryale-v2.2", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 20480, + "input": 20480, + "output": 16384 + } + }, + "sao10k/l3.1-70b-hanami-x1": { + "id": "sao10k/l3.1-70b-hanami-x1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "input": 16384, + "output": 16000 + }, + "temperature": true + }, + "sao10k/l3-8b-stheno-v3.2": { + "id": "sao10k/L3-8B-Stheno-v3.2", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 16384, + "output": 32000 + }, + "temperature": true + }, + "latitudegames/wayfarer-large-70b-llama-3.3": { + "id": "LatitudeGames/Wayfarer-Large-70B-Llama-3.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "z-ai/glm-4.6:thinking": { + "id": "z-ai/glm-4.6:thinking", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 65535 + } + }, + "z-ai/glm-4.5v": { + "id": "z-ai/glm-4.5v", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 64000, + "output": 16384 + }, + "temperature": true + }, + "z-ai/glm-4.6": { + "id": "z-ai/glm-4.6", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "input": 200000, + "output": 204800 + }, + "temperature": true + }, + "z-ai/glm-4.5v:thinking": { + "id": "z-ai/glm-4.5v:thinking", + "family": "glmv", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 96000 + } + }, + "baidu/ernie-4.5-vl-28b-a3b": { + "id": "baidu/ernie-4.5-vl-28b-a3b", + "family": "ernie", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 30000, + "input": 32768, + "output": 8000 + }, + "temperature": true + }, + "baidu/ernie-4.5-300b-a47b": { + "id": "baidu/ERNIE-4.5-300B-A47B", + "family": "ernie", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 131072, + "output": 131000 + }, + "temperature": true + }, + "dmind/dmind-1": { + "id": "dmind/dmind-1", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "dmind/dmind-1-mini": { + "id": "dmind/dmind-1-mini", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "infermatic/mn-12b-inferor-v0.0": { + "id": "Infermatic/MN-12B-Inferor-v0.0", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "meituan-longcat/longcat-flash-chat-fp8": { + "id": "meituan-longcat/LongCat-Flash-Chat-FP8", + "family": "longcat", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "meganova-ai/manta-mini-1.0": { + "id": "meganova-ai/manta-mini-1.0", + "family": "nova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, "limit": { "context": 8192, "input": 8192, "output": 8192 } }, + "meganova-ai/manta-pro-1.0": { + "id": "meganova-ai/manta-pro-1.0", + "family": "nova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "meganova-ai/manta-flash-1.0": { + "id": "meganova-ai/manta-flash-1.0", + "family": "nova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "minimax/minimax-m2.7": { + "id": "minimax/minimax-m2.7", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "input": 204800, + "output": 131000 + }, + "temperature": true + }, + "minimax/minimax-01": { + "id": "minimax/minimax-01", + "family": "minimax", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000192, + "input": 1000192, + "output": 1000192 + }, + "temperature": true + }, + "minimax/minimax-m2.1": { + "id": "minimax/minimax-m2.1", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "input": 200000, + "output": 131072 + }, + "temperature": true + }, + "minimax/minimax-m2-her": { + "id": "minimax/minimax-m2-her", + "family": "minimax", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65532, + "output": 2048 + }, + "temperature": true + }, + "minimax/minimax-m2.5": { + "id": "minimax/minimax-m2.5", + "family": "minimax-m2.5", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 204800, + "output": 131072 + }, + "temperature": true + }, + "qwen/qwen3.5-397b-a17b": { + "id": "Qwen/Qwen3.5-397B-A17B", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 258048, + "output": 130000 + }, + "temperature": true + }, "unsloth/gemma-3-1b-it": { "id": "unsloth/gemma-3-1b-it", "family": "unsloth", @@ -37214,201 +10958,132 @@ }, "temperature": true }, - "meituan-longcat/longcat-flash-chat-fp8": { - "id": "meituan-longcat/LongCat-Flash-Chat-FP8", - "family": "longcat", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 32768 - } - }, - "cognitivecomputations/dolphin-2.9.2-qwen2-72b": { - "id": "cognitivecomputations/dolphin-2.9.2-qwen2-72b", - "family": "qwen", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "input": 8192, - "output": 4096 - } - }, - "infermatic/mn-12b-inferor-v0.0": { - "id": "Infermatic/MN-12B-Inferor-v0.0", - "family": "mistral-nemo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "cruciblelab/l3.3-70b-loki-v2.0": { - "id": "CrucibleLab/L3.3-70B-Loki-V2.0", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "soob3123/veiled-calla-12b": { - "id": "soob3123/Veiled-Calla-12B", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 8192 - } - }, - "soob3123/amoral-gemma3-27b-v2": { - "id": "soob3123/amoral-gemma3-27B-v2", - "family": "gemma", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 8192 - } - }, - "soob3123/grayline-qwen3-8b": { - "id": "soob3123/GrayLine-Qwen3-8B", - "family": "qwen", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 32768 - } - }, - "neversleep/llama-3-lumimaid-70b-v0.1": { - "id": "NeverSleep/Llama-3-Lumimaid-70B-v0.1", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "neversleep/lumimaid-v0.2-70b": { - "id": "NeverSleep/Lumimaid-v0.2-70B", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "deepseek/deepseek-v3.2:thinking": { - "id": "deepseek/deepseek-v3.2:thinking", - "family": "deepseek", + "thudm/glm-z1-9b-0414": { + "id": "THUDM/GLM-Z1-9B-0414", + "family": "glm-z", "reasoning": true, "toolCall": true, "modalities": { "input": [ - "text", - "pdf" + "text" ], "output": [ "text" ] }, "limit": { - "context": 163000, - "input": 163000, + "context": 131000, + "input": 32000, + "output": 131000 + }, + "temperature": true + }, + "thudm/glm-4-9b-0414": { + "id": "THUDM/GLM-4-9B-0414", + "family": "glm", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "input": 32000, + "output": 33000 + }, + "temperature": true + }, + "thudm/glm-z1-rumination-32b-0414": { + "id": "THUDM/GLM-Z1-Rumination-32B-0414", + "family": "glm-z", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, "output": 65536 } }, - "marinaraspaghetti/nemomix-unleashed-12b": { - "id": "MarinaraSpaghetti/NemoMix-Unleashed-12B", - "family": "mistral-nemo", + "thudm/glm-4-32b-0414": { + "id": "THUDM/GLM-4-32B-0414", + "family": "glm", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "input": 128000, + "output": 33000 + }, + "temperature": true + }, + "thudm/glm-z1-32b-0414": { + "id": "THUDM/GLM-Z1-32B-0414", + "family": "glm-z", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 128000, + "output": 131000 + }, + "temperature": true + }, + "google/gemini-3-flash-preview": { + "id": "google/gemini-3-flash-preview", + "family": "gemini-flash", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048756, + "output": 65536 + }, + "temperature": true + }, + "google/gemini-flash-1.5": { + "id": "google/gemini-flash-1.5", + "family": "gemini-flash", "reasoning": false, "toolCall": false, "modalities": { @@ -37420,16 +11095,16 @@ ] }, "limit": { - "context": 32768, - "input": 32768, + "context": 2000000, + "input": 2000000, "output": 8192 } }, - "moonshotai/kimi-k2.5:thinking": { - "id": "moonshotai/kimi-k2.5:thinking", - "family": "kimi-thinking", + "google/gemini-3-flash-preview-thinking": { + "id": "google/gemini-3-flash-preview-thinking", + "family": "gemini-flash", "reasoning": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text", @@ -37440,13 +11115,55 @@ ] }, "limit": { - "context": 256000, - "input": 256000, + "context": 1048756, + "input": 1048756, "output": 65536 } }, - "moonshotai/kimi-k2-thinking-turbo-original": { - "id": "moonshotai/kimi-k2-thinking-turbo-original", + "moonshotai/kimi-k2.5": { + "id": "moonshotai/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 262144 + }, + "temperature": false + }, + "moonshotai/kimi-k2-instruct": { + "id": "moonshotai/kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 190000, + "output": 16384 + }, + "temperature": true + }, + "moonshotai/kimi-k2-thinking-original": { + "id": "moonshotai/kimi-k2-thinking-original", "family": "kimi-thinking", "reasoning": true, "toolCall": false, @@ -37503,8 +11220,8 @@ "output": 131072 } }, - "moonshotai/kimi-k2-thinking-original": { - "id": "moonshotai/kimi-k2-thinking-original", + "moonshotai/kimi-k2-thinking-turbo-original": { + "id": "moonshotai/kimi-k2-thinking-turbo-original", "family": "kimi-thinking", "reasoning": true, "toolCall": false, @@ -37522,11 +11239,11 @@ "output": 16384 } }, - "google/gemini-flash-1.5": { - "id": "google/gemini-flash-1.5", - "family": "gemini-flash", + "moonshotai/kimi-k2-instruct-0905": { + "id": "moonshotai/kimi-k2-instruct-0905", + "family": "kimi", "reasoning": false, - "toolCall": false, + "toolCall": true, "modalities": { "input": [ "text" @@ -37536,34 +11253,15 @@ ] }, "limit": { - "context": 2000000, - "input": 2000000, - "output": 8192 - } - }, - "google/gemini-3-flash-preview-thinking": { - "id": "google/gemini-3-flash-preview-thinking", - "family": "gemini-flash", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] + "context": 262144, + "input": 256000, + "output": 16384 }, - "limit": { - "context": 1048756, - "input": 1048756, - "output": 65536 - } + "temperature": true }, - "z-ai/glm-4.6:thinking": { - "id": "z-ai/glm-4.6:thinking", - "family": "glm", + "moonshotai/kimi-k2-thinking": { + "id": "moonshotai/kimi-k2-thinking", + "family": "kimi-thinking", "reasoning": true, "toolCall": true, "modalities": { @@ -37575,16 +11273,17 @@ ] }, "limit": { - "context": 200000, - "input": 200000, - "output": 65535 - } + "context": 216144, + "input": 120000, + "output": 216144 + }, + "temperature": true }, - "z-ai/glm-4.5v:thinking": { - "id": "z-ai/glm-4.5v:thinking", - "family": "glmv", + "moonshotai/kimi-k2.5:thinking": { + "id": "moonshotai/kimi-k2.5:thinking", + "family": "kimi-thinking", "reasoning": true, - "toolCall": false, + "toolCall": true, "modalities": { "input": [ "text", @@ -37594,33 +11293,14 @@ "text" ] }, - "limit": { - "context": 64000, - "input": 64000, - "output": 96000 - } - }, - "stepfun-ai/step-3.5-flash:thinking": { - "id": "stepfun-ai/step-3.5-flash:thinking", - "family": "step", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, "limit": { "context": 256000, "input": 256000, - "output": 256000 + "output": 65536 } }, - "deepcogito/cogito-v1-preview-qwen-32b": { - "id": "deepcogito/cogito-v1-preview-qwen-32B", + "tongyi-zhiwen/qwenlong-l1-32b": { + "id": "Tongyi-Zhiwen/QwenLong-L1-32B", "family": "qwen", "reasoning": false, "toolCall": false, @@ -37635,26 +11315,7 @@ "limit": { "context": 128000, "input": 128000, - "output": 32768 - } - }, - "inflatebot/mn-12b-mag-mell-r1": { - "id": "inflatebot/MN-12B-Mag-Mell-R1", - "family": "mistral-nemo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "output": 40960 } }, "nothingiisreal/l3.1-70b-celeste-v0.1-bf16": { @@ -37676,35 +11337,452 @@ "output": 16384 } }, - "x-ai/grok-4-fast:thinking": { - "id": "x-ai/grok-4-fast:thinking", - "family": "grok", + "aion-labs/aion-1.0": { + "id": "aion-labs/aion-1.0", + "family": "llama", "reasoning": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ - "text", - "image" + "text" ], "output": [ "text" ] }, "limit": { - "context": 2000000, - "input": 2000000, - "output": 131072 - } + "context": 131072, + "input": 65536, + "output": 32768 + }, + "temperature": true }, - "x-ai/grok-4-07-09": { - "id": "x-ai/grok-4-07-09", - "family": "grok", + "aion-labs/aion-rp-llama-3.1-8b": { + "id": "aion-labs/aion-rp-llama-3.1-8b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "temperature": true + }, + "aion-labs/aion-1.0-mini": { + "id": "aion-labs/aion-1.0-mini", + "family": "deepseek", "reasoning": true, "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "temperature": true + }, + "alibaba-nlp/tongyi-deepresearch-30b-a3b": { + "id": "Alibaba-NLP/Tongyi-DeepResearch-30B-A3B", + "family": "yi", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "minimaxai/minimax-m1-80k": { + "id": "minimaxai/minimax-m1-80k", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 40000 + }, + "temperature": true + }, + "anthropic/claude-opus-4.6:thinking:low": { + "id": "anthropic/claude-opus-4.6:thinking:low", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6": { + "id": "anthropic/claude-opus-4.6", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "temperature": true + }, + "anthropic/claude-sonnet-4.6:thinking": { + "id": "anthropic/claude-sonnet-4.6:thinking", + "family": "claude-sonnet", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6:thinking:max": { + "id": "anthropic/claude-opus-4.6:thinking:max", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6:thinking:medium": { + "id": "anthropic/claude-opus-4.6:thinking:medium", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-sonnet-4.6": { + "id": "anthropic/claude-sonnet-4.6", + "family": "claude-sonnet", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "temperature": true + }, + "anthropic/claude-opus-4.6:thinking": { + "id": "anthropic/claude-opus-4.6:thinking", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "abacusai/dracarys-72b-instruct": { + "id": "abacusai/Dracarys-72B-Instruct", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "eva-unit-01/eva-llama-3.33-70b-v0.0": { + "id": "EVA-UNIT-01/EVA-LLaMA-3.33-70B-v0.0", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "eva-unit-01/eva-qwen2.5-72b-v0.2": { + "id": "EVA-UNIT-01/EVA-Qwen2.5-72B-v0.2", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "eva-unit-01/eva-llama-3.33-70b-v0.1": { + "id": "EVA-UNIT-01/EVA-LLaMA-3.33-70B-v0.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "eva-unit-01/eva-qwen2.5-32b-v0.2": { + "id": "EVA-UNIT-01/EVA-Qwen2.5-32B-v0.2", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "huihui-ai/deepseek-r1-distill-qwen-32b-abliterated": { + "id": "huihui-ai/DeepSeek-R1-Distill-Qwen-32B-abliterated", + "family": "qwen", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "huihui-ai/deepseek-r1-distill-llama-70b-abliterated": { + "id": "huihui-ai/DeepSeek-R1-Distill-Llama-70B-abliterated", + "family": "deepseek", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "huihui-ai/llama-3.3-70b-instruct-abliterated": { + "id": "huihui-ai/Llama-3.3-70B-Instruct-abliterated", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "huihui-ai/qwen2.5-32b-instruct-abliterated": { + "id": "huihui-ai/Qwen2.5-32B-Instruct-abliterated", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "huihui-ai/llama-3.1-nemotron-70b-instruct-hf-abliterated": { + "id": "huihui-ai/Llama-3.1-Nemotron-70B-Instruct-HF-abliterated", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "xiaomi/mimo-v2-flash-thinking-original": { + "id": "xiaomi/mimo-v2-flash-thinking-original", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" ], "output": [ "text" @@ -37713,7 +11791,65 @@ "limit": { "context": 256000, "input": 256000, - "output": 131072 + "output": 32768 + } + }, + "xiaomi/mimo-v2-flash-thinking": { + "id": "xiaomi/mimo-v2-flash-thinking", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + } + }, + "xiaomi/mimo-v2-flash": { + "id": "xiaomi/mimo-v2-flash", + "family": "mimo", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 32000 + }, + "temperature": true + }, + "xiaomi/mimo-v2-flash-original": { + "id": "xiaomi/mimo-v2-flash-original", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 } }, "tngtech/deepseek-tng-r1t2-chimera": { @@ -37755,105 +11891,9 @@ "output": 65536 } }, - "mistralai/mixtral-8x22b-instruct-v0.1": { - "id": "mistralai/mixtral-8x22b-instruct-v0.1", - "family": "mixtral", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "input": 65536, - "output": 32768 - } - }, - "mistralai/mistral-tiny": { - "id": "mistralai/mistral-tiny", - "family": "mistral", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 8192 - } - }, - "mistralai/mistral-7b-instruct": { - "id": "mistralai/mistral-7b-instruct", - "family": "mistral", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 8192 - } - }, - "mistralai/mixtral-8x7b-instruct-v0.1": { - "id": "mistralai/mixtral-8x7b-instruct-v0.1", - "family": "mixtral", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "tongyi-zhiwen/qwenlong-l1-32b": { - "id": "Tongyi-Zhiwen/QwenLong-L1-32B", - "family": "qwen", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 40960 - } - }, - "readyart/the-omega-abomination-l-70b-v1.0": { - "id": "ReadyArt/The-Omega-Abomination-L-70B-v1.0", - "family": "llama", + "inflatebot/mn-12b-mag-mell-r1": { + "id": "inflatebot/MN-12B-Mag-Mell-R1", + "family": "mistral-nemo", "reasoning": false, "toolCall": false, "modalities": { @@ -37867,11 +11907,11 @@ "limit": { "context": 16384, "input": 16384, - "output": 16384 + "output": 8192 } }, - "readyart/ms3.2-the-omega-directive-24b-unslop-v2.0": { - "id": "ReadyArt/MS3.2-The-Omega-Directive-24B-Unslop-v2.0", + "failspy/meta-llama-3-70b-instruct-abliterated-v3.5": { + "id": "failspy/Meta-Llama-3-70B-Instruct-abliterated-v3.5", "family": "llama", "reasoning": false, "toolCall": false, @@ -37884,35 +11924,17 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 32768 + "context": 8192, + "input": 8192, + "output": 8192 } }, - "openai/gpt-5.1-2025-11-13": { - "id": "openai/gpt-5.1-2025-11-13", - "family": "gpt", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "input": 1000000, - "output": 32768 - } - }, - "openai/gpt-5-chat-latest": { - "id": "openai/gpt-5-chat-latest", - "family": "gpt", + "gpt-5.1-codex-max": { + "id": "gpt-5.1-codex-max", + "family": "gpt-codex", "reasoning": true, - "toolCall": false, + "temperature": false, + "toolCall": true, "modalities": { "input": [ "text", @@ -37924,589 +11946,59 @@ }, "limit": { "context": 400000, - "input": 400000, + "input": 272000, "output": 128000 } }, - "openai/o3-mini-low": { - "id": "openai/o3-mini-low", - "family": "o-mini", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 100000 - } - }, - "openai/o3-pro-2025-06-10": { - "id": "openai/o3-pro-2025-06-10", - "family": "o-pro", - "reasoning": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 200000, - "input": 200000, - "output": 100000 - } - }, - "openai/gpt-5.1-chat-latest": { - "id": "openai/gpt-5.1-chat-latest", - "family": "gpt", - "reasoning": true, - "toolCall": false, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 400000, - "input": 400000, - "output": 16384 - } - }, - "vongolachouko/starcannon-unleashed-12b-v1.0": { - "id": "VongolaChouko/Starcannon-Unleashed-12B-v1.0", - "family": "mistral-nemo", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "cohere/command-r": { - "id": "cohere/command-r", - "family": "command-r", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 4096 - } - }, - "thudm/glm-z1-rumination-32b-0414": { - "id": "THUDM/GLM-Z1-Rumination-32B-0414", - "family": "glm-z", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32000, - "input": 32000, - "output": 65536 - } - }, - "chutesai/mistral-small-3.2-24b-instruct-2506": { - "id": "chutesai/Mistral-Small-3.2-24B-Instruct-2506", - "family": "chutesai", - "reasoning": false, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 128000, - "output": 131072 - }, - "temperature": true - }, - "baseten/kimi-k2-instruct-fp4": { - "id": "baseten/Kimi-K2-Instruct-FP4", + "kimi-k2.5": { + "id": "kimi-k2.5", "family": "kimi", - "reasoning": false, - "toolCall": false, + "reasoning": true, + "temperature": false, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image", + "video" ], "output": [ "text" ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 131072 + "context": 262144, + "output": 262144 } }, - "galrionsoftworks/mn-loosecannon-12b-v1": { - "id": "GalrionSoftworks/MN-LooseCannon-12B-v1", - "family": "mistral-nemo", - "reasoning": false, - "toolCall": false, + "gemini-3.1-flash-lite-preview": { + "id": "gemini-3.1-flash-lite-preview", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image", + "video", + "audio", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "alibaba-nlp/tongyi-deepresearch-30b-a3b": { - "id": "Alibaba-NLP/Tongyi-DeepResearch-30B-A3B", - "family": "yi", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, + "context": 1048576, "output": 65536 } }, - "steelskull/l3.3-electra-r1-70b": { - "id": "Steelskull/L3.3-Electra-R1-70b", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "steelskull/l3.3-ms-evalebis-70b": { - "id": "Steelskull/L3.3-MS-Evalebis-70b", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "steelskull/l3.3-cu-mai-r1-70b": { - "id": "Steelskull/L3.3-Cu-Mai-R1-70b", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "steelskull/l3.3-nevoria-r1-70b": { - "id": "Steelskull/L3.3-Nevoria-R1-70b", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "steelskull/l3.3-ms-nevoria-70b": { - "id": "Steelskull/L3.3-MS-Nevoria-70b", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "steelskull/l3.3-ms-evayale-70b": { - "id": "Steelskull/L3.3-MS-Evayale-70B", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "salesforce/llama-xlam-2-70b-fc-r": { - "id": "Salesforce/Llama-xLAM-2-70b-fc-r", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "latitudegames/wayfarer-large-70b-llama-3.3": { - "id": "LatitudeGames/Wayfarer-Large-70B-Llama-3.3", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "thedrummer 2/cydonia-24b-v4.3": { - "id": "TheDrummer 2/Cydonia-24B-v4.3", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "thedrummer 2/anubis-70b-v1": { - "id": "TheDrummer 2/Anubis-70B-v1", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 65536, - "input": 65536, - "output": 16384 - } - }, - "thedrummer 2/cydonia-24b-v4": { - "id": "TheDrummer 2/Cydonia-24B-v4", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 32768 - } - }, - "thedrummer 2/magidonia-24b-v4.3": { - "id": "TheDrummer 2/Magidonia-24B-v4.3", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 32768 - } - }, - "thedrummer 2/anubis-70b-v1.1": { - "id": "TheDrummer 2/Anubis-70B-v1.1", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "input": 131072, - "output": 16384 - } - }, - "thedrummer 2/rocinante-12b-v1.1": { - "id": "TheDrummer 2/Rocinante-12B-v1.1", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 8192 - } - }, - "thedrummer 2/cydonia-24b-v2": { - "id": "TheDrummer 2/Cydonia-24B-v2", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 32768 - } - }, - "thedrummer 2/skyfall-36b-v2": { - "id": "TheDrummer 2/skyfall-36b-v2", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 64000, - "input": 64000, - "output": 32768 - } - }, - "thedrummer 2/unslopnemo-12b-v4.1": { - "id": "TheDrummer 2/UnslopNemo-12B-v4.1", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 8192 - } - }, - "thedrummer 2/cydonia-24b-v4.1": { - "id": "TheDrummer 2/Cydonia-24B-v4.1", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 32768 - } - }, - "shisa-ai/shisa-v2.1-llama3.3-70b": { - "id": "shisa-ai/shisa-v2.1-llama3.3-70b", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 4096 - } - }, - "shisa-ai/shisa-v2-llama3.3-70b": { - "id": "shisa-ai/shisa-v2-llama3.3-70b", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "input": 128000, - "output": 16384 - } - }, - "anthropic/claude-sonnet-4.6:thinking": { - "id": "anthropic/claude-sonnet-4.6:thinking", + "claude-sonnet-4-6": { + "id": "claude-sonnet-4-6", "family": "claude-sonnet", "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ @@ -38520,19 +12012,21 @@ }, "limit": { "context": 1000000, - "input": 1000000, - "output": 128000 + "output": 64000 } }, - "anthropic/claude-opus-4.6:thinking:low": { - "id": "anthropic/claude-opus-4.6:thinking:low", - "family": "claude-opus", + "gemini-3.1-pro-preview": { + "id": "gemini-3.1-pro-preview", + "family": "gemini-pro", "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ "text", "image", + "video", + "audio", "pdf" ], "output": [ @@ -38540,57 +12034,178 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 128000 + "context": 1048576, + "output": 65536, + "input": 128000 } }, - "anthropic/claude-opus-4.6:thinking": { - "id": "anthropic/claude-opus-4.6:thinking", - "family": "claude-opus", + "gpt-5.3-chat-latest": { + "id": "gpt-5.3-chat-latest", + "family": "gpt", "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image", - "pdf" + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 128000 + "context": 128000, + "output": 16384 } }, - "anthropic/claude-opus-4.6:thinking:medium": { - "id": "anthropic/claude-opus-4.6:thinking:medium", - "family": "claude-opus", + "llama-3.3-70b-versatile": { + "id": "llama-3.3-70b-versatile", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "gpt-5-nano": { + "id": "gpt-5-nano", + "family": "gpt-nano", "reasoning": true, + "temperature": false, "toolCall": true, "modalities": { "input": [ "text", - "image", - "pdf" + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 128000 + "context": 272000, + "output": 128000, + "input": 272000 } }, - "anthropic/claude-opus-4.6:thinking:max": { - "id": "anthropic/claude-opus-4.6:thinking:max", - "family": "claude-opus", + "gpt-5.3-codex": { + "id": "gpt-5.3-codex", + "family": "gpt-codex", "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "o3-pro": { + "id": "o3-pro", + "family": "o-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gpt-4o-mini": { + "id": "gpt-4o-mini", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "o4-mini": { + "id": "o4-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gpt-5.2-codex": { + "id": "gpt-5.2-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5.3-codex-xhigh": { + "id": "gpt-5.3-codex-xhigh", + "family": "gpt", + "reasoning": true, + "temperature": false, "toolCall": true, "modalities": { "input": [ @@ -38603,16 +12218,157 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, + "context": 400000, + "input": 272000, "output": 128000 } }, - "miromind-ai/mirothinker-v1.5-235b": { - "id": "miromind-ai/MiroThinker-v1.5-235B", + "grok-code-fast-1": { + "id": "grok-code-fast-1", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 10000, + "input": 128000 + } + }, + "o3-mini": { + "id": "o3-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "grok-4-0709": { + "id": "grok-4-0709", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "route-llm": { + "id": "route-llm", "family": "gpt", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen-2.5-coder-32b": { + "id": "qwen-2.5-coder-32b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "gpt-5-codex": { + "id": "gpt-5-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5.4": { + "id": "gpt-5.4", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "kimi-k2-turbo-preview": { + "id": "kimi-k2-turbo-preview", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38623,54 +12379,100 @@ }, "limit": { "context": 262144, - "input": 32768, - "output": 8192 - }, - "temperature": true + "output": 262144 + } }, - "sao10k/l3.3-70b-euryale-v2.3": { - "id": "Sao10K/L3.3-70B-Euryale-v2.3", - "family": "llama", - "reasoning": false, - "toolCall": false, + "claude-opus-4-6": { + "id": "claude-opus-4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 20480, - "input": 20480, - "output": 16384 + "context": 1000000, + "output": 128000 } }, - "sao10k/l3.1-70b-euryale-v2.2": { - "id": "Sao10K/L3.1-70B-Euryale-v2.2", - "family": "llama", - "reasoning": false, - "toolCall": false, + "o3": { + "id": "o3", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 20480, - "input": 20480, + "context": 200000, + "output": 100000 + } + }, + "gpt-5.1-codex": { + "id": "gpt-5.1-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "image", + "audio" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-4o-2024-11-20": { + "id": "gpt-4o-2024-11-20", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, "output": 16384 } }, - "huihui-ai/deepseek-r1-distill-llama-70b-abliterated": { - "id": "huihui-ai/DeepSeek-R1-Distill-Llama-70B-abliterated", + "deepseek/deepseek-v3.1": { + "id": "deepseek/deepseek-v3.1", "family": "deepseek", "reasoning": true, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38680,35 +12482,16 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 163840, + "output": 128000 } }, - "huihui-ai/qwen2.5-32b-instruct-abliterated": { - "id": "huihui-ai/Qwen2.5-32B-Instruct-abliterated", - "family": "qwen", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "input": 32768, - "output": 8192 - } - }, - "huihui-ai/deepseek-r1-distill-qwen-32b-abliterated": { - "id": "huihui-ai/DeepSeek-R1-Distill-Qwen-32B-abliterated", + "qwen/qwq-32b": { + "id": "Qwen/QwQ-32B", "family": "qwen", "reasoning": true, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38718,16 +12501,16 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 131000, + "output": 131000 } }, - "huihui-ai/llama-3.3-70b-instruct-abliterated": { - "id": "huihui-ai/Llama-3.3-70B-Instruct-abliterated", - "family": "llama", + "qwen/qwen3-235b-a22b-instruct-2507": { + "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", + "family": "qwen", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38737,15 +12520,250 @@ ] }, "limit": { - "context": 16384, - "input": 16384, + "context": 262144, + "output": 131072 + } + }, + "qwen/qwen3-32b": { + "id": "qwen/qwen3-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 40960, + "input": 120000 + } + }, + "qwen/qwen3-coder-480b-a35b-instruct": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen2.5-72b-instruct": { + "id": "Qwen/Qwen2.5-72B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "zai-org/glm-4.5": { + "id": "zai-org/GLM-4.5", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000, + "input": 124000 + } + }, + "zai-org/glm-4.6": { + "id": "zai-org/GLM-4.6", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 205000 + } + }, + "meta-llama/meta-llama-3.1-405b-instruct-turbo": { + "id": "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { + "id": "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, "output": 16384 } }, - "huihui-ai/llama-3.1-nemotron-70b-instruct-hf-abliterated": { - "id": "huihui-ai/Llama-3.1-Nemotron-70B-Instruct-HF-abliterated", + "meta-llama/meta-llama-3.1-8b-instruct": { + "id": "meta-llama/Meta-Llama-3.1-8B-Instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000, + "input": 120000 + } + }, + "deepseek-ai/deepseek-r1": { + "id": "deepseek-ai/DeepSeek-R1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163839, + "output": 163839 + } + }, + "deepseek-ai/deepseek-v3.2": { + "id": "deepseek-ai/DeepSeek-V3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000, + "input": 160000 + } + }, + "perplexity/sonar": { + "id": "perplexity/sonar", + "family": "sonar", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 8000 + } + }, + "xai/grok-4-1-fast-non-reasoning": { + "id": "xai/grok-4-1-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "nvidia/nemotron-3-super-120b-a12b": { + "id": "nvidia/nemotron-3-super-120b-a12b", "family": "nemotron", "reasoning": false, + "temperature": true, "toolCall": false, "modalities": { "input": [ @@ -38756,16 +12774,206 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 16384 + "context": 256000, + "output": 32000, + "input": 256000 } }, - "dmind/dmind-1-mini": { - "id": "dmind/dmind-1-mini", + "openai/gpt-5.4": { + "id": "openai/gpt-5.4", "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + } + }, + "google/gemini-3.1-pro-preview": { + "id": "google/gemini-3.1-pro-preview", + "family": "gemini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "google/gemini-2.5-pro": { + "id": "google/gemini-2.5-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.5-flash": { + "id": "google/gemini-2.5-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "anthropic/claude-haiku-4-5": { + "id": "anthropic/claude-haiku-4-5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 62000 + } + }, + "anthropic/claude-sonnet-4-6": { + "id": "anthropic/claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4-5": { + "id": "anthropic/claude-opus-4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-opus-4-6": { + "id": "anthropic/claude-opus-4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-sonnet-4-5": { + "id": "anthropic/claude-sonnet-4-5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "kwaipilot/kat-dev": { + "id": "Kwaipilot/KAT-Dev", + "family": "kat-coder", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38775,16 +12983,16 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 8192 + "context": 128000, + "output": 128000 } }, - "dmind/dmind-1": { - "id": "dmind/dmind-1", - "family": "gpt", - "reasoning": false, - "toolCall": false, + "qwen/qwen3.5-35b-a3b": { + "id": "qwen/qwen3.5-35b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38794,73 +13002,154 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 8192 + "context": 262144, + "output": 262144 } }, - "eva-unit-01/eva-qwen2.5-72b-v0.2": { - "id": "EVA-UNIT-01/EVA-Qwen2.5-72B-v0.2", + "qwen/qwen3.5-122b-a10b": { + "id": "qwen/qwen3.5-122b-a10b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3.5-9b": { + "id": "qwen/qwen3.5-9b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3.5-27b": { + "id": "qwen/qwen3.5-27b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3.5-4b": { + "id": "Qwen/Qwen3.5-4B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3-vl-8b-instruct": { + "id": "Qwen/Qwen3-VL-8B-Instruct", "family": "qwen", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 262000, + "output": 262000 } }, - "eva-unit-01/eva-llama-3.33-70b-v0.0": { - "id": "EVA-UNIT-01/EVA-LLaMA-3.33-70B-v0.0", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "eva-unit-01/eva-llama-3.33-70b-v0.1": { - "id": "EVA-UNIT-01/EVA-LLaMA-3.33-70B-v0.1", - "family": "llama", - "reasoning": false, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 16384, - "input": 16384, - "output": 16384 - } - }, - "eva-unit-01/eva-qwen2.5-32b-v0.2": { - "id": "EVA-UNIT-01/EVA-Qwen2.5-32B-v0.2", + "qwen/qwen3-vl-32b-instruct": { + "id": "Qwen/Qwen3-VL-32B-Instruct", "family": "qwen", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-vl-30b-a3b-thinking": { + "id": "Qwen/Qwen3-VL-30B-A3B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen2.5-14b-instruct": { + "id": "Qwen/Qwen2.5-14B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38870,13 +13159,131 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 33000, + "output": 4000 } }, - "qwen-3-235b-a22b-instruct-2507": { - "id": "qwen-3-235b-a22b-instruct-2507", + "qwen/qwen3-vl-235b-a22b-instruct": { + "id": "Qwen/Qwen3-VL-235B-A22B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-next-80b-a3b-thinking": { + "id": "Qwen/Qwen3-Next-80B-A3B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000, + "input": 120000 + } + }, + "qwen/qwen2.5-vl-32b-instruct": { + "id": "Qwen/Qwen2.5-VL-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "qwen/qwen3-omni-30b-a3b-thinking": { + "id": "Qwen/Qwen3-Omni-30B-A3B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "qwen/qwen3-235b-a22b-thinking-2507": { + "id": "Qwen/Qwen3-235B-A22B-Thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "qwen/qwen2.5-32b-instruct": { + "id": "Qwen/Qwen2.5-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen2.5-72b-instruct-128k": { + "id": "Qwen/Qwen2.5-72B-Instruct-128K", "family": "qwen", "reasoning": false, "temperature": true, @@ -38891,9 +13298,18207 @@ }, "limit": { "context": 131000, + "output": 4000 + } + }, + "qwen/qwen3-14b": { + "id": "Qwen/Qwen3-14B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "qwen/qwen3-omni-30b-a3b-instruct": { + "id": "Qwen/Qwen3-Omni-30B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "qwen/qwen3-coder-30b-a3b-instruct": { + "id": "Qwen/Qwen3-Coder-30B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536, + "input": 120000 + } + }, + "qwen/qwen3-30b-a3b-instruct-2507": { + "id": "Qwen/Qwen3-30B-A3B-Instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384, + "input": 120000 + } + }, + "qwen/qwen3-8b": { + "id": "Qwen/Qwen3-8B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "qwen/qwen3-next-80b-a3b-instruct": { + "id": "Qwen/Qwen3-Next-80B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-vl-8b-thinking": { + "id": "Qwen/Qwen3-VL-8B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-omni-30b-a3b-captioner": { + "id": "Qwen/Qwen3-Omni-30B-A3B-Captioner", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "qwen/qwen3-vl-30b-a3b-instruct": { + "id": "Qwen/Qwen3-VL-30B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen2.5-coder-32b-instruct": { + "id": "Qwen/Qwen2.5-Coder-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen2.5-7b-instruct": { + "id": "Qwen/Qwen2.5-7B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen3-vl-235b-a22b-thinking": { + "id": "Qwen/Qwen3-VL-235B-A22B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-30b-a3b-thinking-2507": { + "id": "Qwen/Qwen3-30B-A3B-Thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768, + "input": 120000 + } + }, + "qwen/qwen3-vl-32b-thinking": { + "id": "Qwen/Qwen3-VL-32B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen2.5-vl-72b-instruct": { + "id": "Qwen/Qwen2.5-VL-72B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 4000, + "input": 120000 + } + }, + "zai-org/glm-4.5v": { + "id": "zai-org/GLM-4.5V", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "zai-org/glm-4.6v": { + "id": "zai-org/GLM-4.6V", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "zai-org/glm-4.5-air": { + "id": "zai-org/GLM-4.5-Air", + "family": "glm-air", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000, + "input": 124000 + } + }, + "inclusionai/ling-flash-2.0": { + "id": "inclusionAI/Ling-flash-2.0", + "family": "ling", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "inclusionai/ling-mini-2.0": { + "id": "inclusionAI/Ling-mini-2.0", + "family": "ling", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "inclusionai/ring-flash-2.0": { + "id": "inclusionAI/Ring-flash-2.0", + "family": "ring", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "ascend-tribe/pangu-pro-moe": { + "id": "ascend-tribe/pangu-pro-moe", + "family": "pangu", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "tencent/hunyuan-a13b-instruct": { + "id": "tencent/Hunyuan-A13B-Instruct", + "family": "hunyuan", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "pro/zai-org/glm-4.7": { + "id": "Pro/zai-org/GLM-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 205000 + } + }, + "pro/zai-org/glm-5.1": { + "id": "Pro/zai-org/GLM-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 205000 + } + }, + "pro/zai-org/glm-5": { + "id": "Pro/zai-org/GLM-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 205000 + } + }, + "pro/deepseek-ai/deepseek-v3": { + "id": "Pro/deepseek-ai/DeepSeek-V3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/deepseek-ai/deepseek-r1": { + "id": "Pro/deepseek-ai/DeepSeek-R1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/deepseek-ai/deepseek-v3.2": { + "id": "Pro/deepseek-ai/DeepSeek-V3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/deepseek-ai/deepseek-v3.1-terminus": { + "id": "Pro/deepseek-ai/DeepSeek-V3.1-Terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/moonshotai/kimi-k2-thinking": { + "id": "Pro/moonshotai/Kimi-K2-Thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "pro/moonshotai/kimi-k2-instruct-0905": { + "id": "Pro/moonshotai/Kimi-K2-Instruct-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "pro/moonshotai/kimi-k2.5": { + "id": "Pro/moonshotai/Kimi-K2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "pro/minimaxai/minimax-m2.5": { + "id": "Pro/MiniMaxAI/MiniMax-M2.5", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 192000, + "output": 131000 + } + }, + "pro/minimaxai/minimax-m2.1": { + "id": "Pro/MiniMaxAI/MiniMax-M2.1", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 197000, + "output": 131000 + } + }, + "paddlepaddle/paddleocr-vl": { + "id": "paddlepaddle/paddleocr-vl", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "paddlepaddle/paddleocr-vl-1.5": { + "id": "PaddlePaddle/PaddleOCR-VL-1.5", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "deepseek-ai/deepseek-ocr": { + "id": "deepseek-ai/DeepSeek-OCR", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "deepseek-ai/deepseek-r1-distill-qwen-14b": { + "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "deepseek-ai/deepseek-r1-distill-qwen-32b": { + "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "deepseek-ai/deepseek-v3": { + "id": "deepseek-ai/DeepSeek-V3", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "deepseek-ai/deepseek-vl2": { + "id": "deepseek-ai/deepseek-vl2", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4000, + "output": 4000 + } + }, + "bytedance-seed/seed-oss-36b-instruct": { + "id": "ByteDance-Seed/Seed-OSS-36B-Instruct", + "family": "seed", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-coder-480b-a35b-instruct-fp8": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "zai-org/glm-4.5-fp8": { + "id": "zai-org/GLM-4.5-FP8", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3-0324": { + "id": "deepseek-ai/DeepSeek-V3-0324", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840, + "input": 120000 + } + }, + "minimax-m2.5": { + "id": "MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072, + "input": 196601 + } + }, + "minimax-m2.7": { + "id": "MiniMax-M2.7", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "minimax-m2.7-highspeed": { + "id": "MiniMax-M2.7-highspeed", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "minimax-m2.5-highspeed": { + "id": "MiniMax-M2.5-highspeed", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "cerebras-llama-4-maverick-17b-128e-instruct": { + "id": "cerebras-llama-4-maverick-17b-128e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "llama-3.3-8b-instruct": { + "id": "llama-3.3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cerebras-llama-4-scout-17b-16e-instruct": { + "id": "cerebras-llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "groq-llama-4-maverick-17b-128e-instruct": { + "id": "groq-llama-4-maverick-17b-128e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "llama-4-scout-17b-16e-instruct-fp8": { + "id": "llama-4-scout-17b-16e-instruct-fp8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "llama-4-maverick-17b-128e-instruct-fp8": { + "id": "llama-4-maverick-17b-128e-instruct-fp8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "liquid/lfm-2.5-1.2b-instruct:free": { + "id": "liquid/lfm-2.5-1.2b-instruct:free", + "family": "liquid", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "liquid/lfm-2.5-1.2b-thinking:free": { + "id": "liquid/lfm-2.5-1.2b-thinking:free", + "family": "liquid", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "deepseek/deepseek-chat-v3.1": { + "id": "deepseek/deepseek-chat-v3.1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 7168 + } + }, + "deepseek/deepseek-r1-distill-llama-70b": { + "id": "deepseek/deepseek-r1-distill-llama-70b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "deepseek/deepseek-r1": { + "id": "deepseek/deepseek-r1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "deepseek/deepseek-v3.1-terminus:exacto": { + "id": "deepseek/deepseek-v3.1-terminus:exacto", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "deepseek/deepseek-chat-v3-0324": { + "id": "deepseek/deepseek-chat-v3-0324", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek/deepseek-v3.1-terminus": { + "id": "deepseek/deepseek-v3.1-terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "openrouter/elephant-alpha": { + "id": "openrouter/elephant-alpha", + "family": "elephant", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "openrouter/free": { + "id": "openrouter/free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32768 + } + }, + "arcee-ai/trinity-large-thinking": { + "id": "arcee-ai/trinity-large-thinking", + "family": "trinity", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262100, + "output": 80000 + } + }, + "arcee-ai/trinity-large-preview:free": { + "id": "arcee-ai/trinity-large-preview:free", + "family": "trinity", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "cognitivecomputations/dolphin-mistral-24b-venice-edition:free": { + "id": "cognitivecomputations/dolphin-mistral-24b-venice-edition:free", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "bytedance-seed/seedream-4.5": { + "id": "bytedance-seed/seedream-4.5", + "family": "seed", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "black-forest-labs/flux.2-max": { + "id": "black-forest-labs/flux.2-max", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 46864, + "output": 46864 + } + }, + "black-forest-labs/flux.2-flex": { + "id": "black-forest-labs/flux.2-flex", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 67344, + "output": 67344 + } + }, + "black-forest-labs/flux.2-pro": { + "id": "black-forest-labs/flux.2-pro", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 46864, + "output": 46864 + } + }, + "black-forest-labs/flux.2-klein-4b": { + "id": "black-forest-labs/flux.2-klein-4b", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "nousresearch/hermes-3-llama-3.1-405b:free": { + "id": "nousresearch/hermes-3-llama-3.1-405b:free", + "family": "hermes", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nousresearch/hermes-4-405b": { + "id": "NousResearch/Hermes-4-405B", + "family": "hermes", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 120000 + } + }, + "nousresearch/hermes-4-70b": { + "id": "NousResearch/Hermes-4-70B", + "family": "nousresearch", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 120000 + } + }, + "stepfun/step-3.5-flash": { + "id": "stepfun/step-3.5-flash", + "family": "step", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistralai/mistral-small-3.1-24b-instruct": { + "id": "mistralai/mistral-small-3.1-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 131072 + } + }, + "mistralai/devstral-2512": { + "id": "mistralai/devstral-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "mistralai/mistral-small-2603": { + "id": "mistralai/mistral-small-2603", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "mistralai/mistral-small-3.2-24b-instruct": { + "id": "mistralai/mistral-small-3.2-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/devstral-medium-2507": { + "id": "mistralai/devstral-medium-2507", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/devstral-small-2507": { + "id": "mistralai/devstral-small-2507", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "meta-llama/llama-3.2-11b-vision-instruct": { + "id": "meta-llama/llama-3.2-11b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta-llama/llama-3.2-3b-instruct:free": { + "id": "meta-llama/llama-3.2-3b-instruct:free", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "meta-llama/llama-3.3-70b-instruct:free": { + "id": "meta-llama/llama-3.3-70b-instruct:free", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "x-ai/grok-4.20-multi-agent-beta": { + "id": "x-ai/grok-4.20-multi-agent-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "x-ai/grok-3-beta": { + "id": "x-ai/grok-3-beta", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "x-ai/grok-4": { + "id": "x-ai/grok-4", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "x-ai/grok-3-mini": { + "id": "x-ai/grok-3-mini", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "x-ai/grok-4.20-beta": { + "id": "x-ai/grok-4.20-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "x-ai/grok-3-mini-beta": { + "id": "x-ai/grok-3-mini-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "x-ai/grok-3": { + "id": "x-ai/grok-3", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "prime-intellect/intellect-3": { + "id": "prime-intellect/intellect-3", + "family": "intellect", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nvidia/nemotron-3-nano-30b-a3b:free": { + "id": "nvidia/nemotron-3-nano-30b-a3b:free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "nvidia/nemotron-nano-9b-v2:free": { + "id": "nvidia/nemotron-nano-9b-v2:free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "nvidia/nemotron-3-super-120b-a12b:free": { + "id": "nvidia/nemotron-3-super-120b-a12b:free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "nvidia/nemotron-nano-9b-v2": { + "id": "nvidia/nemotron-nano-9b-v2", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nvidia/nemotron-nano-12b-v2-vl:free": { + "id": "nvidia/nemotron-nano-12b-v2-vl:free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "inception/mercury-edit-2": { + "id": "inception/mercury-edit-2", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "inception/mercury-2": { + "id": "inception/mercury-2", + "family": "mercury", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "openai/gpt-oss-120b:exacto": { + "id": "openai/gpt-oss-120b:exacto", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "openai/gpt-5-chat": { + "id": "openai/gpt-5-chat", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + } + }, + "openai/gpt-5.3-codex": { + "id": "openai/gpt-5.3-codex", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "openai/gpt-oss-20b:free": { + "id": "openai/gpt-oss-20b:free", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "openai/gpt-5.4-mini": { + "id": "openai/gpt-5.4-mini", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "openai/gpt-5.4-nano": { + "id": "openai/gpt-5.4-nano", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "openai/gpt-5-image": { + "id": "openai/gpt-5-image", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "openai/gpt-5.4-pro": { + "id": "openai/gpt-5.4-pro", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + } + }, + "openai/gpt-oss-120b:free": { + "id": "openai/gpt-oss-120b:free", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "z-ai/glm-4.7": { + "id": "z-ai/glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "z-ai/glm-4.5-air:free": { + "id": "z-ai/glm-4.5-air:free", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 96000 + } + }, + "z-ai/glm-5": { + "id": "z-ai/glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "z-ai/glm-5.1": { + "id": "z-ai/glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "z-ai/glm-4.5": { + "id": "z-ai/glm-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "z-ai/glm-4.6:exacto": { + "id": "z-ai/glm-4.6:exacto", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "z-ai/glm-4.5-air": { + "id": "z-ai/glm-4.5-air", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "z-ai/glm-5-turbo": { + "id": "z-ai/glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "z-ai/glm-4.7-flash": { + "id": "z-ai/glm-4.7-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 40551 + } + }, + "sourceful/riverflow-v2-standard-preview": { + "id": "sourceful/riverflow-v2-standard-preview", + "family": "sourceful", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sourceful/riverflow-v2-fast-preview": { + "id": "sourceful/riverflow-v2-fast-preview", + "family": "sourceful", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sourceful/riverflow-v2-max-preview": { + "id": "sourceful/riverflow-v2-max-preview", + "family": "sourceful", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "minimax/minimax-m2": { + "id": "minimax/minimax-m2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262114, + "output": 262114 + } + }, + "minimax/minimax-m2.5:free": { + "id": "minimax/minimax-m2.5:free", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "minimax/minimax-m1": { + "id": "minimax/minimax-m1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 40000 + } + }, + "qwen/qwen3.5-flash-02-23": { + "id": "qwen/qwen3.5-flash-02-23", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3.6-plus": { + "id": "qwen/qwen3.6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3-max": { + "id": "qwen/qwen3-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "qwen/qwen3-coder:exacto": { + "id": "qwen/qwen3-coder:exacto", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen/qwen3-coder-flash": { + "id": "qwen/qwen3-coder-flash", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen-2.5-coder-32b-instruct": { + "id": "qwen/qwen-2.5-coder-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen/qwen3-coder": { + "id": "qwen/qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "qwen/qwen3.5-plus-02-15": { + "id": "qwen/qwen3.5-plus-02-15", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3-235b-a22b-07-25": { + "id": "qwen/qwen3-235b-a22b-07-25", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "google/gemini-2.5-pro-preview-05-06": { + "id": "google/gemini-2.5-pro-preview-05-06", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65535 + } + }, + "google/gemini-3.1-pro-preview-customtools": { + "id": "google/gemini-3.1-pro-preview-customtools", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemma-3-4b-it:free": { + "id": "google/gemma-3-4b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "google/gemini-2.5-flash-lite-preview-09-2025": { + "id": "google/gemini-2.5-flash-lite-preview-09-2025", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.0-flash-001": { + "id": "google/gemini-2.0-flash-001", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/gemma-3n-e4b-it": { + "id": "google/gemma-3n-e4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemini-3.1-flash-lite-preview": { + "id": "google/gemini-3.1-flash-lite-preview", + "family": "gemini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65000 + } + }, + "google/gemma-3n-e4b-it:free": { + "id": "google/gemma-3n-e4b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2000 + } + }, + "google/gemini-3-pro-preview": { + "id": "google/gemini-3-pro-preview", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "google/gemma-3n-e2b-it:free": { + "id": "google/gemma-3n-e2b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2000 + } + }, + "google/gemma-2-9b-it": { + "id": "google/gemma-2-9b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1639 + } + }, + "google/gemma-4-31b-it": { + "id": "google/gemma-4-31B-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "google/gemini-2.5-pro-preview-06-05": { + "id": "google/gemini-2.5-pro-preview-06-05", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemma-3-12b-it": { + "id": "google/gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemma-3-27b-it:free": { + "id": "google/gemma-3-27b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "google/gemma-4-31b-it:free": { + "id": "google/gemma-4-31b-it:free", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "google/gemma-3-12b-it:free": { + "id": "google/gemma-3-12b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "google/gemma-3-4b-it": { + "id": "google/gemma-3-4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 19200 + } + }, + "google/gemini-2.5-flash-preview-09-2025": { + "id": "google/gemini-2.5-flash-preview-09-2025", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemma-3-27b-it": { + "id": "google/gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 37000, + "output": 8192, + "input": 100000 + } + }, + "google/gemma-4-26b-a4b-it": { + "id": "google/gemma-4-26b-a4b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "google/gemma-4-26b-a4b-it:free": { + "id": "google/gemma-4-26b-a4b-it:free", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "google/gemini-2.5-flash-lite": { + "id": "google/gemini-2.5-flash-lite", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "moonshotai/kimi-k2-0905": { + "id": "moonshotai/kimi-k2-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "moonshotai/kimi-k2-0905:exacto": { + "id": "moonshotai/kimi-k2-0905:exacto", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "moonshotai/kimi-k2": { + "id": "moonshotai/kimi-k2", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "anthropic/claude-opus-4.1": { + "id": "anthropic/claude-opus-4.1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, "output": 32000 } }, + "anthropic/claude-3.7-sonnet": { + "id": "anthropic/claude-3.7-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-opus-4.7": { + "id": "anthropic/claude-opus-4.7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-sonnet-4": { + "id": "anthropic/claude-sonnet-4", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-sonnet-4.5": { + "id": "anthropic/claude-sonnet-4.5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-opus-4.5": { + "id": "anthropic/claude-opus-4.5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-opus-4": { + "id": "anthropic/claude-opus-4", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "anthropic/claude-3.5-haiku": { + "id": "anthropic/claude-3.5-haiku", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "anthropic/claude-haiku-4.5": { + "id": "anthropic/claude-haiku-4.5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "xiaomi/mimo-v2-omni": { + "id": "xiaomi/mimo-v2-omni", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "xiaomi/mimo-v2-pro": { + "id": "xiaomi/mimo-v2-pro", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "accounts/fireworks/models/glm-5p1": { + "id": "accounts/fireworks/models/glm-5p1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202800, + "output": 131072 + } + }, + "accounts/fireworks/models/deepseek-v3p2": { + "id": "accounts/fireworks/models/deepseek-v3p2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 160000 + } + }, + "accounts/fireworks/models/minimax-m2p5": { + "id": "accounts/fireworks/models/minimax-m2p5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 196608 + } + }, + "accounts/fireworks/models/glm-4p5-air": { + "id": "accounts/fireworks/models/glm-4p5-air", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "accounts/fireworks/models/glm-5": { + "id": "accounts/fireworks/models/glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "accounts/fireworks/models/deepseek-v3p1": { + "id": "accounts/fireworks/models/deepseek-v3p1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "accounts/fireworks/models/kimi-k2-instruct": { + "id": "accounts/fireworks/models/kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "accounts/fireworks/models/qwen3p6-plus": { + "id": "accounts/fireworks/models/qwen3p6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "accounts/fireworks/models/minimax-m2p1": { + "id": "accounts/fireworks/models/minimax-m2p1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "accounts/fireworks/models/minimax-m2p7": { + "id": "accounts/fireworks/models/minimax-m2p7", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 196608 + } + }, + "accounts/fireworks/models/glm-4p7": { + "id": "accounts/fireworks/models/glm-4p7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 198000 + } + }, + "accounts/fireworks/models/glm-4p5": { + "id": "accounts/fireworks/models/glm-4p5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "accounts/fireworks/models/kimi-k2p5": { + "id": "accounts/fireworks/models/kimi-k2p5", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "accounts/fireworks/models/gpt-oss-20b": { + "id": "accounts/fireworks/models/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "accounts/fireworks/models/gpt-oss-120b": { + "id": "accounts/fireworks/models/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "accounts/fireworks/models/kimi-k2-thinking": { + "id": "accounts/fireworks/models/kimi-k2-thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "accounts/fireworks/routers/kimi-k2p5-turbo": { + "id": "accounts/fireworks/routers/kimi-k2p5-turbo", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "k2p5": { + "id": "k2p5", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "glm-5": { + "id": "glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "mimo-v2-omni": { + "id": "mimo-v2-omni", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "glm-5.1": { + "id": "glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "mimo-v2-pro": { + "id": "mimo-v2-pro", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "intel/qwen3-coder-480b-a35b-instruct-int4-mixed-ar": { + "id": "Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 106000, + "output": 4096 + } + }, + "mistralai/magistral-small-2506": { + "id": "mistralai/Magistral-Small-2506", + "family": "magistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/mistral-large-instruct-2411": { + "id": "mistralai/Mistral-Large-Instruct-2411", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen-plus-character": { + "id": "qwen-plus-character", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "qwen2-5-math-7b-instruct": { + "id": "qwen2-5-math-7b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "qwen-doc-turbo": { + "id": "qwen-doc-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen-math-turbo": { + "id": "qwen-math-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "qwen3.5-flash": { + "id": "qwen3.5-flash", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "deepseek-v3-1": { + "id": "deepseek-v3-1", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "qwen-math-plus": { + "id": "qwen-math-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "qwen2-5-coder-32b-instruct": { + "id": "qwen2-5-coder-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen-deep-research": { + "id": "qwen-deep-research", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "deepseek-r1-distill-qwen-32b": { + "id": "deepseek-r1-distill-qwen-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "deepseek-r1-distill-qwen-7b": { + "id": "deepseek-r1-distill-qwen-7b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "tongyi-intent-detect-v3": { + "id": "tongyi-intent-detect-v3", + "family": "yi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1024 + } + }, + "moonshot-kimi-k2-instruct": { + "id": "moonshot-kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "deepseek-v3-2-exp": { + "id": "deepseek-v3-2-exp", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "deepseek-r1-distill-qwen-1-5b": { + "id": "deepseek-r1-distill-qwen-1-5b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "qwen2-5-coder-7b-instruct": { + "id": "qwen2-5-coder-7b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen2-5-math-72b-instruct": { + "id": "qwen2-5-math-72b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "deepseek-r1-distill-qwen-14b": { + "id": "deepseek-r1-distill-qwen-14b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "deepseek-v3": { + "id": "deepseek-v3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "deepseek-r1-0528": { + "id": "deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "deepseek-r1-distill-llama-8b": { + "id": "deepseek-r1-distill-llama-8b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "kimi/kimi-k2.5": { + "id": "kimi/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "siliconflow/deepseek-v3-0324": { + "id": "siliconflow/deepseek-v3-0324", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "siliconflow/deepseek-v3.2": { + "id": "siliconflow/deepseek-v3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "siliconflow/deepseek-r1-0528": { + "id": "siliconflow/deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32768 + } + }, + "siliconflow/deepseek-v3.1-terminus": { + "id": "siliconflow/deepseek-v3.1-terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "gpt-5.2-pro": { + "id": "gpt-5.2-pro", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 272000, + "input": 272000 + } + }, + "gpt-5.1-codex-mini": { + "id": "gpt-5.1-codex-mini", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "gpt-5-chat-latest": { + "id": "gpt-5-chat-latest", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "deepseek/deepseek-v3-0324": { + "id": "deepseek/deepseek-v3-0324", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "deepseek/deepseek-r1-0528": { + "id": "deepseek/deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "xiaomimimo/mimo-v2-flash": { + "id": "XiaomiMiMo/MiMo-V2-Flash", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32000 + } + }, + "baidu/ernie-4.5-vl-424b-a47b": { + "id": "baidu/ernie-4.5-vl-424b-a47b", + "family": "ernie", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 123000, + "output": 16000 + } + }, + "baidu/ernie-4.5-300b-a47b-paddle": { + "id": "baidu/ernie-4.5-300b-a47b-paddle", + "family": "ernie", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 123000, + "output": 12000 + } + }, + "qwen/qwen3-32b-fp8": { + "id": "qwen/qwen3-32b-fp8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "qwen/qwen3-30b-a3b-fp8": { + "id": "qwen/qwen3-30b-a3b-fp8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "qwen/qwen3-coder-next": { + "id": "qwen/qwen3-coder-next", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3-235b-a22b-fp8": { + "id": "qwen/qwen3-235b-a22b-fp8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "ring-1t": { + "id": "Ring-1T", + "family": "ring", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "ling-1t": { + "id": "Ling-1T", + "family": "ling", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "qwen3-235b-a22b-instruct": { + "id": "qwen3-235b-a22b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "qwen3-235b-a22b-thinking-2507": { + "id": "qwen3-235b-a22b-thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 8192 + } + }, + "kimi-k2-0905": { + "id": "Kimi-K2-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen3-235b": { + "id": "qwen3-235b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "kimi-k2": { + "id": "kimi-k2", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "qwen3-max-preview": { + "id": "qwen3-max-preview", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "qwen/qwen3-embedding-8b": { + "id": "Qwen/Qwen3-Embedding-8B", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960, + "input": 32768 + } + }, + "qwen/qwen3-embedding-4b": { + "id": "qwen/qwen3-embedding-4b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 2048 + } + }, + "minimaxai/minimax-m2.5": { + "id": "MiniMaxAI/MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "minimaxai/minimax-m2.7": { + "id": "MiniMaxAI/MiniMax-M2.7", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "minimaxai/minimax-m2.1": { + "id": "MiniMaxAI/MiniMax-M2.1", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 197000, + "output": 131000, + "input": 120000 + } + }, + "deepseek/deepseek-chat": { + "id": "deepseek/deepseek-chat", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "deepseek/deepseek-v3.2-exp": { + "id": "deepseek/deepseek-v3.2-exp", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + }, + "family": "deepseek" + }, + "inclusionai/ring-1t": { + "id": "inclusionai/ring-1t", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "inclusionai/ling-1t": { + "id": "inclusionai/ling-1t", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "stepfun/step-3.5-flash-free": { + "id": "stepfun/step-3.5-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "stepfun/step-3": { + "id": "stepfun/step-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 64000 + } + }, + "kuaishou/kat-coder-pro-v2": { + "id": "kuaishou/kat-coder-pro-v2", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 80000 + } + }, + "x-ai/grok-4.1-fast-non-reasoning": { + "id": "x-ai/grok-4.1-fast-non-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "x-ai/grok-4.2-fast": { + "id": "x-ai/grok-4.2-fast", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "x-ai/grok-4.2-fast-non-reasoning": { + "id": "x-ai/grok-4.2-fast-non-reasoning", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "openai/gpt-5.3-chat": { + "id": "openai/gpt-5.3-chat", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + }, + "family": "gpt" + }, + "z-ai/glm-4.7-flash-free": { + "id": "z-ai/glm-4.7-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-5v-turbo": { + "id": "z-ai/glm-5v-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "z-ai/glm-4.7-flashx": { + "id": "z-ai/glm-4.7-flashx", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-4.6v-flash-free": { + "id": "z-ai/glm-4.6v-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-4.6v-flash": { + "id": "z-ai/glm-4.6v-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-4.6v": { + "id": "z-ai/glm-4.6v", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "volcengine/doubao-seed-2.0-code": { + "id": "volcengine/doubao-seed-2.0-code", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "volcengine/doubao-seed-code": { + "id": "volcengine/doubao-seed-code", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-2.0-mini": { + "id": "volcengine/doubao-seed-2.0-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-2.0-lite": { + "id": "volcengine/doubao-seed-2.0-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-1.8": { + "id": "volcengine/doubao-seed-1.8", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-2.0-pro": { + "id": "volcengine/doubao-seed-2.0-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "baidu/ernie-5.0-thinking-preview": { + "id": "baidu/ernie-5.0-thinking-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "minimax/minimax-m2.7-highspeed": { + "id": "minimax/minimax-m2.7-highspeed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131100 + }, + "family": "minimax" + }, + "minimax/minimax-m2.5-lightning": { + "id": "minimax/minimax-m2.5-lightning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "qwen/qwen3-coder-plus": { + "id": "qwen/qwen3-coder-plus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3.5-flash": { + "id": "qwen/qwen3.5-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1020000, + "output": 1020000 + } + }, + "qwen/qwen3.5-plus": { + "id": "Qwen/Qwen3.5-Plus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + }, + "family": "qwen" + }, + "sapiens-ai/agnes-1.5-lite": { + "id": "sapiens-ai/agnes-1.5-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "sapiens-ai/agnes-1.5-pro": { + "id": "sapiens-ai/agnes-1.5-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "moonshotai/kimi-k2-thinking-turbo": { + "id": "moonshotai/kimi-k2-thinking-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262114, + "output": 262114 + }, + "family": "kimi-thinking" + }, + "solar-pro2": { + "id": "solar-pro2", + "family": "solar-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "solar-mini": { + "id": "solar-mini", + "family": "solar-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "solar-pro3": { + "id": "solar-pro3", + "family": "solar-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "deepseek/deepseek-r1-turbo": { + "id": "deepseek/deepseek-r1-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16000 + } + }, + "deepseek/deepseek-ocr-2": { + "id": "deepseek/deepseek-ocr-2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "deepseek/deepseek-ocr": { + "id": "deepseek/deepseek-ocr", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "deepseek/deepseek-r1-0528-qwen3-8b": { + "id": "deepseek/deepseek-r1-0528-qwen3-8b", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "deepseek/deepseek-v3-turbo": { + "id": "deepseek/deepseek-v3-turbo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16000 + } + }, + "nousresearch/hermes-2-pro-llama-3-8b": { + "id": "nousresearch/hermes-2-pro-llama-3-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "zai-org/autoglm-phone-9b-multilingual": { + "id": "zai-org/autoglm-phone-9b-multilingual", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "mistralai/mistral-nemo": { + "id": "mistralai/mistral-nemo", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "baichuan/baichuan-m2-32b": { + "id": "baichuan/baichuan-m2-32b", + "family": "baichuan", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "meta-llama/llama-4-scout-17b-16e-instruct": { + "id": "meta-llama/llama-4-scout-17b-16e-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + }, + "family": "llama" + }, + "meta-llama/llama-3-8b-instruct": { + "id": "meta-llama/llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 16384 + } + }, + "meta-llama/llama-3-70b-instruct": { + "id": "meta-llama/llama-3-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8000 + } + }, + "sao10k/l31-70b-euryale-v2.2": { + "id": "sao10k/l31-70b-euryale-v2.2", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3-70b-euryale-v2.1": { + "id": "sao10k/l3-70b-euryale-v2.1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3-8b-lunaris": { + "id": "sao10k/l3-8b-lunaris", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "baidu/ernie-4.5-vl-28b-a3b-thinking": { + "id": "baidu/ernie-4.5-vl-28b-a3b-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "baidu/ernie-4.5-21b-a3b": { + "id": "baidu/ernie-4.5-21b-a3b", + "family": "ernie", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 120000, + "output": 8000 + } + }, + "baidu/ernie-4.5-21b-a3b-thinking": { + "id": "baidu/ernie-4.5-21b-a3b-thinking", + "family": "ernie", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "minimax/minimax-m2.5-highspeed": { + "id": "minimax/minimax-m2.5-highspeed", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "qwen/qwen3-4b-fp8": { + "id": "qwen/qwen3-4b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 20000 + } + }, + "qwen/qwen-mt-plus": { + "id": "qwen/qwen-mt-plus", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192 + } + }, + "qwen/qwen3-8b-fp8": { + "id": "qwen/qwen3-8b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 20000 + } + }, + "qwen/qwen-2.5-72b-instruct": { + "id": "qwen/qwen-2.5-72b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "kwaipilot/kat-coder-pro": { + "id": "kwaipilot/kat-coder-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "mimo-v2-tts": { + "id": "mimo-v2-tts", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 8000, + "output": 16000 + } + }, + "zai-org/glm-5-fp8": { + "id": "zai-org/GLM-5-FP8", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "meta-llama/llama-3.1-70b-instruct": { + "id": "meta-llama/llama-3.1-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "openpipe/qwen3-14b-instruct": { + "id": "OpenPipe/Qwen3-14B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "microsoft/phi-4-mini-instruct": { + "id": "microsoft/phi-4-mini-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/nvidia-nemotron-3-super-120b-a12b-fp8": { + "id": "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "opengvlab/internvl3-78b-tee": { + "id": "OpenGVLab/InternVL3-78B-TEE", + "family": "opengvlab", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "nousresearch/deephermes-3-mistral-24b-preview": { + "id": "NousResearch/DeepHermes-3-Mistral-24B-Preview", + "family": "nousresearch", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "nousresearch/hermes-4-405b-fp8-tee": { + "id": "NousResearch/Hermes-4-405B-FP8-TEE", + "family": "nousresearch", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "nousresearch/hermes-4.3-36b": { + "id": "NousResearch/Hermes-4.3-36B", + "family": "nousresearch", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "nousresearch/hermes-4-14b": { + "id": "NousResearch/Hermes-4-14B", + "family": "nousresearch", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "qwen/qwen3-30b-a3b": { + "id": "qwen/qwen3-30b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "qwen/qwen3-235b-a22b": { + "id": "Qwen/Qwen3-235B-A22B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "qwen/qwen2.5-vl-72b-instruct-tee": { + "id": "Qwen/Qwen2.5-VL-72B-Instruct-TEE", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "qwen/qwen3guard-gen-0.6b": { + "id": "Qwen/Qwen3Guard-Gen-0.6B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen/qwen3-235b-a22b-instruct-2507-tee": { + "id": "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3.5-397b-a17b-tee": { + "id": "Qwen/Qwen3.5-397B-A17B-TEE", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3-coder-480b-a35b-instruct-fp8-tee": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8-TEE", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "zai-org/glm-5.1-tee": { + "id": "zai-org/GLM-5.1-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-4.5-tee": { + "id": "zai-org/GLM-4.5-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "zai-org/glm-4.6-fp8": { + "id": "zai-org/GLM-4.6-FP8", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-4.7-fp8": { + "id": "zai-org/GLM-4.7-FP8", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096, + "input": 124000 + } + }, + "zai-org/glm-5-tee": { + "id": "zai-org/GLM-5-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-4.7-tee": { + "id": "zai-org/GLM-4.7-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-5-turbo": { + "id": "zai-org/GLM-5-Turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-4.6-tee": { + "id": "zai-org/GLM-4.6-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65536 + } + }, + "mistralai/devstral-2-123b-instruct-2512-tee": { + "id": "mistralai/Devstral-2-123B-Instruct-2512-TEE", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "chutesai/mistral-small-3.1-24b-instruct-2503": { + "id": "chutesai/Mistral-Small-3.1-24B-Instruct-2503", + "family": "chutesai", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nvidia/nvidia-nemotron-3-nano-30b-a3b-bf16": { + "id": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "deepseek-ai/deepseek-r1-tee": { + "id": "deepseek-ai/DeepSeek-R1-TEE", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "deepseek-ai/deepseek-r1-distill-llama-70b": { + "id": "deepseek-ai/deepseek-r1-distill-llama-70b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "deepseek-ai/deepseek-v3.1-tee": { + "id": "deepseek-ai/DeepSeek-V3.1-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3-0324-tee": { + "id": "deepseek-ai/DeepSeek-V3-0324-TEE", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.2-speciale-tee": { + "id": "deepseek-ai/DeepSeek-V3.2-Speciale-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.1-terminus-tee": { + "id": "deepseek-ai/DeepSeek-V3.1-Terminus-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-r1-0528-tee": { + "id": "deepseek-ai/DeepSeek-R1-0528-TEE", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.2-tee": { + "id": "deepseek-ai/DeepSeek-V3.2-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "openai/gpt-oss-120b-tee": { + "id": "openai/gpt-oss-120b-TEE", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "unsloth/llama-3.2-3b-instruct": { + "id": "unsloth/Llama-3.2-3B-Instruct", + "family": "unsloth", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "unsloth/llama-3.2-1b-instruct": { + "id": "unsloth/Llama-3.2-1B-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "unsloth/mistral-nemo-instruct-2407": { + "id": "unsloth/Mistral-Nemo-Instruct-2407", + "family": "unsloth", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "unsloth/mistral-small-24b-instruct-2501": { + "id": "unsloth/Mistral-Small-24B-Instruct-2501", + "family": "unsloth", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "moonshotai/kimi-k2-thinking-tee": { + "id": "moonshotai/Kimi-K2-Thinking-TEE", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65535 + } + }, + "moonshotai/kimi-k2.5-tee": { + "id": "moonshotai/Kimi-K2.5-TEE", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65535 + } + }, + "minimaxai/minimax-m2.1-tee": { + "id": "MiniMaxAI/MiniMax-M2.1-TEE", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "minimaxai/minimax-m2.5-tee": { + "id": "MiniMaxAI/MiniMax-M2.5-TEE", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "rednote-hilab/dots.ocr": { + "id": "rednote-hilab/dots.ocr", + "family": "rednote", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "tngtech/tng-r1t-chimera-turbo": { + "id": "tngtech/TNG-R1T-Chimera-Turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "tngtech/deepseek-r1t-chimera": { + "id": "tngtech/DeepSeek-R1T-Chimera", + "family": "tngtech", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "tngtech/tng-r1t-chimera-tee": { + "id": "tngtech/TNG-R1T-Chimera-TEE", + "family": "tngtech", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "gpt-5.4-mini": { + "id": "gpt-5.4-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5.4-nano": { + "id": "gpt-5.4-nano", + "family": "gpt-nano", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "qwen/qwen3-coder-480b-a35b-instruct-turbo": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "meta-llama/llama-3.1-8b-instruct-turbo": { + "id": "meta-llama/Llama-3.1-8B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta-llama/llama-3.3-70b-instruct-turbo": { + "id": "meta-llama/Llama-3.3-70B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "temperature": true + }, + "meta-llama/llama-3.1-70b-instruct-turbo": { + "id": "meta-llama/Llama-3.1-70B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "minimaxai/minimax-m2": { + "id": "MiniMaxAI/MiniMax-M2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "anthropic/claude-3-7-sonnet-latest": { + "id": "anthropic/claude-3-7-sonnet-latest", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-4-opus": { + "id": "anthropic/claude-4-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "doubao-seed-1.6-flash": { + "id": "doubao-seed-1.6-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "doubao-seed-2.0-code": { + "id": "doubao-seed-2.0-code", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "doubao-1.5-thinking-pro": { + "id": "doubao-1.5-thinking-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "claude-3.7-sonnet": { + "id": "claude-3.7-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-sonnet" + }, + "qwen-vl-max-2025-01-25": { + "id": "qwen-vl-max-2025-01-25", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen2.5-vl-72b-instruct": { + "id": "qwen2.5-vl-72b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "gemini-2.0-flash": { + "id": "gemini-2.0-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + }, + "family": "gemini-flash" + }, + "qwen3-vl-30b-a3b-thinking": { + "id": "qwen3-vl-30b-a3b-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "qwen" + }, + "gemini-3.0-pro-image-preview": { + "id": "gemini-3.0-pro-image-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "claude-4.5-opus": { + "id": "claude-4.5-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-opus" + }, + "claude-4.0-opus": { + "id": "claude-4.0-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-4.5-haiku": { + "id": "claude-4.5-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + }, + "family": "claude-haiku" + }, + "gemini-3.0-flash-preview": { + "id": "gemini-3.0-flash-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "claude-3.5-sonnet": { + "id": "claude-3.5-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8200 + } + }, + "claude-4.0-sonnet": { + "id": "claude-4.0-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "doubao-seed-1.6-thinking": { + "id": "doubao-seed-1.6-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "qwen3-30b-a3b-thinking-2507": { + "id": "qwen3-30b-a3b-thinking-2507", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 8192 + }, + "family": "qwen" + }, + "glm-4.5-air": { + "id": "glm-4.5-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + }, + "family": "glm-air" + }, + "deepseek-v3.1": { + "id": "deepseek-v3.1", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "family": "deepseek" + }, + "claude-4.1-opus": { + "id": "claude-4.1-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "doubao-seed-2.0-mini": { + "id": "doubao-seed-2.0-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "doubao-seed-1.6": { + "id": "doubao-seed-1.6", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "qwen2.5-vl-7b-instruct": { + "id": "qwen2.5-vl-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "kling-v2-6": { + "id": "kling-v2-6", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 99999999, + "output": 99999999 + } + }, + "gemini-3.0-pro-preview": { + "id": "gemini-3.0-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "doubao-seed-2.0-lite": { + "id": "doubao-seed-2.0-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "claude-3.5-haiku": { + "id": "claude-3.5-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + }, + "family": "claude-haiku" + }, + "gpt-oss-20b": { + "id": "gpt-oss-20b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32766 + }, + "family": "gpt-oss" + }, + "mimo-v2-flash": { + "id": "mimo-v2-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + }, + "family": "mimo" + }, + "doubao-1.5-vision-pro": { + "id": "doubao-1.5-vision-pro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "claude-4.5-sonnet": { + "id": "claude-4.5-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-sonnet" + }, + "qwen-max-2025-01-25": { + "id": "qwen-max-2025-01-25", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "doubao-seed-2.0-pro": { + "id": "doubao-seed-2.0-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "deepseek/deepseek-v3.2-exp-thinking": { + "id": "deepseek/deepseek-v3.2-exp-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "deepseek/deepseek-v3.1-terminus-thinking": { + "id": "deepseek/deepseek-v3.1-terminus-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "deepseek/deepseek-v3.2-251201": { + "id": "deepseek/deepseek-v3.2-251201", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "deepseek/deepseek-math-v2": { + "id": "deepseek/deepseek-math-v2", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 160000 + } + }, + "stepfun-ai/gelab-zero-4b-preview": { + "id": "stepfun-ai/gelab-zero-4b-preview", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "x-ai/grok-4-fast-reasoning": { + "id": "x-ai/grok-4-fast-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "x-ai/grok-4-fast-non-reasoning": { + "id": "x-ai/grok-4-fast-non-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "z-ai/autoglm-phone-9b": { + "id": "z-ai/autoglm-phone-9b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 12800, + "output": 4096 + } + }, + "meituan/longcat-flash-chat": { + "id": "meituan/longcat-flash-chat", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + }, + "family": "longcat" + }, + "meituan/longcat-flash-lite": { + "id": "meituan/longcat-flash-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 320000 + } + }, + "rekaai/reka-edge": { + "id": "rekaai/reka-edge", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "rekaai/reka-flash-3": { + "id": "rekaai/reka-flash-3", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "ai21/jamba-large-1.7": { + "id": "ai21/jamba-large-1.7", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "alibaba/tongyi-deepresearch-30b-a3b": { + "id": "alibaba/tongyi-deepresearch-30b-a3b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "liquid/lfm-2-24b-a2b": { + "id": "liquid/lfm-2-24b-a2b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "writer/palmyra-x5": { + "id": "writer/palmyra-x5", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1040000, + "output": 8192 + } + }, + "ibm-granite/granite-4.0-h-micro": { + "id": "ibm-granite/granite-4.0-h-micro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 32768 + } + }, + "perplexity/sonar-pro": { + "id": "perplexity/sonar-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8000 + }, + "family": "sonar-pro" + }, + "perplexity/sonar-deep-research": { + "id": "perplexity/sonar-deep-research", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 25600 + } + }, + "perplexity/sonar-pro-search": { + "id": "perplexity/sonar-pro-search", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8000 + } + }, + "perplexity/sonar-reasoning-pro": { + "id": "perplexity/sonar-reasoning-pro", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 8000 + }, + "family": "sonar-reasoning" + }, + "deepseek/deepseek-r1-distill-qwen-32b": { + "id": "deepseek/deepseek-r1-distill-qwen-32b", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "openrouter/auto": { + "id": "openrouter/auto", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 32768 + } + }, + "openrouter/bodybuilder": { + "id": "openrouter/bodybuilder", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "arcee-ai/virtuoso-large": { + "id": "arcee-ai/virtuoso-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 64000 + } + }, + "arcee-ai/spotlight": { + "id": "arcee-ai/spotlight", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65537 + } + }, + "arcee-ai/trinity-large-thinking:free": { + "id": "arcee-ai/trinity-large-thinking:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "arcee-ai/maestro-reasoning": { + "id": "arcee-ai/maestro-reasoning", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "arcee-ai/coder-large": { + "id": "arcee-ai/coder-large", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "upstage/solar-pro-3": { + "id": "upstage/solar-pro-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "bytedance-seed/dola-seed-2.0-pro:free": { + "id": "bytedance-seed/dola-seed-2.0-pro:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "bytedance-seed/seed-1.6": { + "id": "bytedance-seed/seed-1.6", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "bytedance-seed/seed-2.0-lite": { + "id": "bytedance-seed/seed-2.0-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "bytedance-seed/seed-1.6-flash": { + "id": "bytedance-seed/seed-1.6-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "bytedance-seed/seed-2.0-mini": { + "id": "bytedance-seed/seed-2.0-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "mancer/weaver": { + "id": "mancer/weaver", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 2000 + } + }, + "kilo-auto/balanced": { + "id": "kilo-auto/balanced", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "kilo-auto/frontier": { + "id": "kilo-auto/frontier", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "kilo-auto/small": { + "id": "kilo-auto/small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "kilo-auto/free": { + "id": "kilo-auto/free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "allenai/olmo-2-0325-32b-instruct": { + "id": "allenai/olmo-2-0325-32b-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "nousresearch/hermes-3-llama-3.1-70b": { + "id": "nousresearch/hermes-3-llama-3.1-70b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "nousresearch/hermes-3-llama-3.1-405b": { + "id": "nousresearch/hermes-3-llama-3.1-405b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "morph/morph-v3-fast": { + "id": "morph/morph-v3-fast", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 16000 + }, + "family": "morph" + }, + "morph/morph-v3-large": { + "id": "morph/morph-v3-large", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + }, + "family": "morph" + }, + "eleutherai/llemma_7b": { + "id": "eleutherai/llemma_7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "alpindale/goliath-120b": { + "id": "alpindale/goliath-120b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 6144, + "output": 1024 + } + }, + "mistralai/mistral-large-2512": { + "id": "mistralai/mistral-large-2512", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 52429 + } + }, + "mistralai/devstral-medium": { + "id": "mistralai/devstral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "mistralai/pixtral-large-2411": { + "id": "mistralai/pixtral-large-2411", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "mistralai/mistral-small-24b-instruct-2501": { + "id": "mistralai/mistral-small-24b-instruct-2501", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "mistralai/mistral-large-2411": { + "id": "mistralai/mistral-large-2411", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "mistralai/mixtral-8x22b-instruct": { + "id": "mistralai/mixtral-8x22b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 13108 + } + }, + "mistralai/mistral-large-2407": { + "id": "mistralai/mistral-large-2407", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "mistralai/voxtral-small-24b-2507": { + "id": "mistralai/Voxtral-Small-24B-2507", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + }, + "family": "voxtral" + }, + "mistralai/mixtral-8x7b-instruct": { + "id": "mistralai/mixtral-8x7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "mistralai/devstral-small": { + "id": "mistralai/devstral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "mistralai/mistral-7b-instruct-v0.1": { + "id": "mistralai/mistral-7b-instruct-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2824, + "output": 565 + } + }, + "meta-llama/llama-guard-3-8b": { + "id": "meta-llama/Llama-Guard-3-8B", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1024, + "input": 8000 + } + }, + "meta-llama/llama-guard-4-12b": { + "id": "meta-llama/llama-guard-4-12b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 1024 + }, + "family": "llama" + }, + "meta-llama/llama-3.2-1b-instruct": { + "id": "meta-llama/llama-3.2-1b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 60000, + "output": 12000 + } + }, + "x-ai/grok-4.20": { + "id": "x-ai/grok-4.20", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "x-ai/grok-code-fast-1:optimized:free": { + "id": "x-ai/grok-code-fast-1:optimized:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 10000 + } + }, + "x-ai/grok-4.20-multi-agent": { + "id": "x-ai/grok-4.20-multi-agent", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "sao10k/l3-euryale-70b": { + "id": "sao10k/l3-euryale-70b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3-lunaris-8b": { + "id": "sao10k/l3-lunaris-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3.3-euryale-70b": { + "id": "sao10k/l3.3-euryale-70b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "sao10k/l3.1-euryale-70b": { + "id": "sao10k/l3.1-euryale-70b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "microsoft/phi-4": { + "id": "microsoft/phi-4", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + }, + "family": "phi" + }, + "cohere/command-r7b-12-2024": { + "id": "cohere/command-r7b-12-2024", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "cohere/command-a": { + "id": "cohere/command-a", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8000 + }, + "family": "command" + }, + "cohere/command-r-08-2024": { + "id": "cohere/command-r-08-2024", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "nvidia/llama-3.3-nemotron-super-49b-v1.5": { + "id": "nvidia/llama-3.3-nemotron-super-49b-v1.5", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/nemotron-nano-12b-v2-vl": { + "id": "nvidia/nemotron-nano-12b-v2-vl", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "family": "nemotron" + }, + "nvidia/llama-3.1-nemotron-70b-instruct": { + "id": "nvidia/llama-3.1-nemotron-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "openai/gpt-4o-2024-05-13": { + "id": "openai/gpt-4o-2024-05-13", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "openai/gpt-4-1106-preview": { + "id": "openai/gpt-4-1106-preview", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "openai/gpt-4o-audio-preview": { + "id": "openai/gpt-4o-audio-preview", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-3.5-turbo-16k": { + "id": "openai/gpt-3.5-turbo-16k", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "output": 4096 + } + }, + "openai/o3-pro": { + "id": "openai/o3-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 100000 + }, + "family": "o-pro" + }, + "openai/gpt-4o-mini-2024-07-18": { + "id": "openai/gpt-4o-mini-2024-07-18", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-4": { + "id": "openai/gpt-4", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + }, + "family": "gpt" + }, + "openai/gpt-4-0314": { + "id": "openai/gpt-4-0314", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 4096 + } + }, + "openai/gpt-audio": { + "id": "openai/gpt-audio", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-4o:extended": { + "id": "openai/gpt-4o:extended", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "openai/gpt-audio-mini": { + "id": "openai/gpt-audio-mini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-3.5-turbo-0613": { + "id": "openai/gpt-3.5-turbo-0613", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4095, + "output": 4096 + } + }, + "openai/gpt-5-image-mini": { + "id": "openai/gpt-5-image-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "openai/gpt-3.5-turbo-instruct": { + "id": "openai/gpt-3.5-turbo-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096, + "input": 4096 + }, + "family": "gpt" + }, + "amazon/nova-premier-v1": { + "id": "amazon/nova-premier-v1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32000 + } + }, + "z-ai/glm-4-32b": { + "id": "z-ai/glm-4-32b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "relace/relace-apply-3": { + "id": "relace/relace-apply-3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "relace/relace-search": { + "id": "relace/relace-search", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "qwen/qwen2.5-coder-7b-instruct": { + "id": "qwen/qwen2.5-coder-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen/qwen3-235b-a22b-2507": { + "id": "qwen/qwen3-235b-a22b-2507", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 52429 + } + }, + "qwen/qwen-vl-plus": { + "id": "qwen/qwen-vl-plus", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen/qwen-max": { + "id": "qwen/qwen-max", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen/qwen-plus": { + "id": "qwen/qwen-plus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen/qwen-plus-2025-07-28": { + "id": "qwen/qwen-plus-2025-07-28", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen/qwen-2.5-7b-instruct": { + "id": "qwen/qwen-2.5-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 6554 + } + }, + "qwen/qwen-vl-max": { + "id": "qwen/qwen-vl-max", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen/qwen3-max-thinking": { + "id": "qwen/qwen3-max-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "qwen/qwen-turbo": { + "id": "qwen/qwen-turbo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen/qwen-plus-2025-07-28:thinking": { + "id": "qwen/qwen-plus-2025-07-28:thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "alfredpros/codellama-7b-instruct-solidity": { + "id": "alfredpros/codellama-7b-instruct-solidity", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "kwaipilot/kat-coder-pro-v2": { + "id": "kwaipilot/kat-coder-pro-v2", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + }, + "family": "kat-coder" + }, + "google/lyria-3-clip-preview": { + "id": "google/lyria-3-clip-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/lyria-3-pro-preview": { + "id": "google/lyria-3-pro-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-3-pro-image-preview": { + "id": "google/gemini-3-pro-image-preview", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 65536, + "output": 32768 + } + }, + "google/gemini-2.5-flash-image": { + "id": "google/gemini-2.5-flash-image", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + }, + "family": "gemini-flash" + }, + "google/gemini-3.1-flash-image-preview": { + "id": "google/gemini-3.1-flash-image-preview", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "gemini" + }, + "google/gemini-2.5-pro-preview": { + "id": "google/gemini-2.5-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemma-2-27b-it": { + "id": "google/gemma-2-27b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemini-2.0-flash-lite-001": { + "id": "google/gemini-2.0-flash-lite-001", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "aion-labs/aion-2.0": { + "id": "aion-labs/aion-2.0", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "thedrummer/unslopnemo-12b": { + "id": "thedrummer/unslopnemo-12b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "thedrummer/cydonia-24b-v4.1": { + "id": "thedrummer/cydonia-24b-v4.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "thedrummer/skyfall-36b-v2": { + "id": "thedrummer/skyfall-36b-v2", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "thedrummer/rocinante-12b": { + "id": "thedrummer/rocinante-12b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "anthropic/claude-3.7-sonnet:thinking": { + "id": "anthropic/claude-3.7-sonnet:thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-opus-4.6-fast": { + "id": "anthropic/claude-opus-4.6-fast", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-3-haiku": { + "id": "anthropic/claude-3-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + }, + "family": "claude-haiku" + }, + "switchpoint/router": { + "id": "switchpoint/router", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "bytedance/ui-tars-1.5-7b": { + "id": "bytedance/ui-tars-1.5-7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 2048 + } + }, + "tngtech/deepseek-r1t2-chimera": { + "id": "tngtech/deepseek-r1t2-chimera", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "anthropic--claude-4.6-opus": { + "id": "anthropic--claude-4.6-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic--claude-3-haiku": { + "id": "anthropic--claude-3-haiku", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic--claude-3-opus": { + "id": "anthropic--claude-3-opus", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic--claude-3.7-sonnet": { + "id": "anthropic--claude-3.7-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-4.5-sonnet": { + "id": "anthropic--claude-4.5-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-4.6-sonnet": { + "id": "anthropic--claude-4.6-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "anthropic--claude-4.5-opus": { + "id": "anthropic--claude-4.5-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-4-opus": { + "id": "anthropic--claude-4-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "anthropic--claude-3-sonnet": { + "id": "anthropic--claude-3-sonnet", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic--claude-4-sonnet": { + "id": "anthropic--claude-4-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-4.5-haiku": { + "id": "anthropic--claude-4.5-haiku", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-3.5-sonnet": { + "id": "anthropic--claude-3.5-sonnet", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "auto": { + "id": "auto", + "family": "auto", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "morph-v3-fast": { + "id": "morph-v3-fast", + "family": "morph", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 16000 + } + }, + "morph-v3-large": { + "id": "morph-v3-large", + "family": "morph", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "workers-ai/@cf/myshell-ai/melotts": { + "id": "workers-ai/@cf/myshell-ai/melotts", + "family": "melotts", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/ibm-granite/granite-4.0-h-micro": { + "id": "workers-ai/@cf/ibm-granite/granite-4.0-h-micro", + "family": "granite", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/huggingface/distilbert-sst-2-int8": { + "id": "workers-ai/@cf/huggingface/distilbert-sst-2-int8", + "family": "distilbert", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/zai-org/glm-4.7-flash": { + "id": "workers-ai/@cf/zai-org/glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "workers-ai/@cf/pipecat-ai/smart-turn-v2": { + "id": "workers-ai/@cf/pipecat-ai/smart-turn-v2", + "family": "smart-turn", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct": { + "id": "workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/facebook/bart-large-cnn": { + "id": "workers-ai/@cf/facebook/bart-large-cnn", + "family": "bart", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it": { + "id": "workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/nvidia/nemotron-3-120b-a12b": { + "id": "workers-ai/@cf/nvidia/nemotron-3-120b-a12b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b": { + "id": "workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", + "family": "deepseek-thinking", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/openai/gpt-oss-20b": { + "id": "workers-ai/@cf/openai/gpt-oss-20b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/openai/gpt-oss-120b": { + "id": "workers-ai/@cf/openai/gpt-oss-120b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1": { + "id": "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct": { + "id": "workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3-8b-instruct-awq": { + "id": "workers-ai/@cf/meta/llama-3-8b-instruct-awq", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-guard-3-8b": { + "id": "workers-ai/@cf/meta/llama-guard-3-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/m2m100-1.2b": { + "id": "workers-ai/@cf/meta/m2m100-1.2b", + "family": "m2m", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-2-7b-chat-fp16": { + "id": "workers-ai/@cf/meta/llama-2-7b-chat-fp16", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.2-11b-vision-instruct": { + "id": "workers-ai/@cf/meta/llama-3.2-11b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast": { + "id": "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.2-1b-instruct": { + "id": "workers-ai/@cf/meta/llama-3.2-1b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8": { + "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.2-3b-instruct": { + "id": "workers-ai/@cf/meta/llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.1-8b-instruct-awq": { + "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct-awq", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3-8b-instruct": { + "id": "workers-ai/@cf/meta/llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.1-8b-instruct": { + "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct": { + "id": "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwen3-embedding-0.6b": { + "id": "workers-ai/@cf/qwen/qwen3-embedding-0.6b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwq-32b": { + "id": "workers-ai/@cf/qwen/qwq-32b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8": { + "id": "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/google/gemma-3-12b-it": { + "id": "workers-ai/@cf/google/gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/moonshotai/kimi-k2.5": { + "id": "workers-ai/@cf/moonshotai/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1b": { + "id": "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1B", + "family": "indictrans", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/pfnet/plamo-embedding-1b": { + "id": "workers-ai/@cf/pfnet/plamo-embedding-1b", + "family": "plamo", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-small-en-v1.5": { + "id": "workers-ai/@cf/baai/bge-small-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-large-en-v1.5": { + "id": "workers-ai/@cf/baai/bge-large-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-reranker-base": { + "id": "workers-ai/@cf/baai/bge-reranker-base", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-base-en-v1.5": { + "id": "workers-ai/@cf/baai/bge-base-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-m3": { + "id": "workers-ai/@cf/baai/bge-m3", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/deepgram/aura-2-en": { + "id": "workers-ai/@cf/deepgram/aura-2-en", + "family": "aura", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/deepgram/aura-2-es": { + "id": "workers-ai/@cf/deepgram/aura-2-es", + "family": "aura", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/deepgram/nova-3": { + "id": "workers-ai/@cf/deepgram/nova-3", + "family": "nova", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "anthropic/claude-opus-4-7": { + "id": "anthropic/claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4-1": { + "id": "anthropic/claude-opus-4-1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "anthropic/claude-3-5-haiku": { + "id": "anthropic/claude-3-5-haiku", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "anthropic/claude-3.5-sonnet": { + "id": "anthropic/claude-3.5-sonnet", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "anthropic/claude-3-sonnet": { + "id": "anthropic/claude-3-sonnet", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic/claude-3-opus": { + "id": "anthropic/claude-3-opus", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "claude-opus-4.6": { + "id": "claude-opus-4.6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 144000, + "input": 128000, + "output": 64000 + } + }, + "claude-sonnet-4": { + "id": "claude-sonnet-4", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 128000, + "output": 64000 + } + }, + "claude-sonnet-4.5": { + "id": "claude-sonnet-4.5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 144000, + "input": 128000, + "output": 32000 + } + }, + "claude-opus-41": { + "id": "claude-opus-41", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 80000, + "output": 16000 + } + }, + "claude-opus-4.5": { + "id": "claude-opus-4.5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "input": 128000, + "output": 32000 + } + }, + "claude-haiku-4.5": { + "id": "claude-haiku-4.5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 144000, + "input": 128000, + "output": 32000 + } + }, + "claude-sonnet-4.6": { + "id": "claude-sonnet-4.6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 128000, + "output": 32000 + } + }, + "glm-5v-turbo": { + "id": "glm-5v-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "glm-4.7-flashx": { + "id": "glm-4.7-flashx", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "glm-5-turbo": { + "id": "glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "glm-4.5-flash": { + "id": "glm-4.5-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "glm-4.7-flash": { + "id": "glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "claude-haiku-4-5": { + "id": "claude-haiku-4-5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "glm-4.7-free": { + "id": "glm-4.7-free", + "family": "glm-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "gemini-3.1-pro": { + "id": "gemini-3.1-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "kimi-k2.5-free": { + "id": "kimi-k2.5-free", + "family": "kimi-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "claude-opus-4-7": { + "id": "claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "minimax-m2.5-free": { + "id": "minimax-m2.5-free", + "family": "minimax-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "big-pickle": { + "id": "big-pickle", + "family": "big-pickle", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "claude-opus-4-1": { + "id": "claude-opus-4-1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-3-5-haiku": { + "id": "claude-3-5-haiku", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "gemini-3-flash": { + "id": "gemini-3-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "trinity-large-preview-free": { + "id": "trinity-large-preview-free", + "family": "trinity", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "gpt-5.4-pro": { + "id": "gpt-5.4-pro", + "family": "gpt-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "glm-5-free": { + "id": "glm-5-free", + "family": "glm-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "claude-opus-4-5": { + "id": "claude-opus-4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "minimax-m2.1-free": { + "id": "minimax-m2.1-free", + "family": "minimax-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "qwen3.6-plus-free": { + "id": "qwen3.6-plus-free", + "family": "qwen-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 64000 + } + }, + "gemini-3-pro": { + "id": "gemini-3-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "grok-code": { + "id": "grok-code", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mimo-v2-flash-free": { + "id": "mimo-v2-flash-free", + "family": "mimo-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "gpt-5.3-codex-spark": { + "id": "gpt-5.3-codex-spark", + "family": "gpt-codex-spark", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 100000, + "output": 32000 + } + }, + "claude-sonnet-4-5": { + "id": "claude-sonnet-4-5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "qwen3-coder": { + "id": "qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "mimo-v2-pro-free": { + "id": "mimo-v2-pro-free", + "family": "mimo-pro-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 64000 + } + }, + "nemotron-3-super-free": { + "id": "nemotron-3-super-free", + "family": "nemotron-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 128000 + } + }, + "mimo-v2-omni-free": { + "id": "mimo-v2-omni-free", + "family": "mimo-omni-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 64000 + } + }, + "step-3.5-flash-2603": { + "id": "step-3.5-flash-2603", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + } + }, + "step-1-32k": { + "id": "step-1-32k", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "step-3.5-flash": { + "id": "step-3.5-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + } + }, + "step-2-16k": { + "id": "step-2-16k", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "black-forest-labs/flux-schnell": { + "id": "black-forest-labs/flux-schnell", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 77, + "input": 77, + "output": 0 + } + }, + "black-forest-labs/flux-dev": { + "id": "black-forest-labs/flux-dev", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 77, + "input": 77, + "output": 0 + } + }, + "qwen/qwen3-32b-fast": { + "id": "Qwen/Qwen3-32B-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "qwen/qwen2.5-coder-7b-fast": { + "id": "Qwen/Qwen2.5-Coder-7B-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "primeintellect/intellect-3": { + "id": "PrimeIntellect/INTELLECT-3", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "baai/bge-en-icl": { + "id": "BAAI/bge-en-icl", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 0 + } + }, + "baai/bge-multilingual-gemma2": { + "id": "BAAI/bge-multilingual-gemma2", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 0 + } + }, + "meta-llama/meta-llama-3.1-8b-instruct-fast": { + "id": "meta-llama/Meta-Llama-3.1-8B-Instruct-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + } + }, + "meta-llama/llama-3.3-70b-instruct-fast": { + "id": "meta-llama/Llama-3.3-70B-Instruct-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "nvidia/nemotron-nano-v2-12b": { + "id": "nvidia/Nemotron-Nano-V2-12b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 30000, + "output": 4096 + } + }, + "nvidia/llama-3_1-nemotron-ultra-253b-v1": { + "id": "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + } + }, + "nvidia/nvidia-nemotron-3-nano-30b-a3b": { + "id": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 30000, + "output": 4096 + } + }, + "deepseek-ai/deepseek-v3-0324-fast": { + "id": "deepseek-ai/DeepSeek-V3-0324-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "deepseek-ai/deepseek-r1-0528-fast": { + "id": "deepseek-ai/DeepSeek-R1-0528-fast", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "google/gemma-2-2b-it": { + "id": "google/gemma-2-2b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 8000, + "output": 4096 + } + }, + "google/gemma-2-9b-it-fast": { + "id": "google/gemma-2-9b-it-fast", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8000, + "output": 4096 + } + }, + "google/gemma-3-27b-it-fast": { + "id": "google/gemma-3-27b-it-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 110000, + "input": 100000, + "output": 8192 + } + }, + "moonshotai/kimi-k2.5-fast": { + "id": "moonshotai/Kimi-K2.5-fast", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 8192 + } + }, + "intfloat/e5-mistral-7b-instruct": { + "id": "intfloat/e5-mistral-7b-instruct", + "family": "mistral", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "input": 32768, + "output": 4096 + } + }, + "topazlabs-co/topazlabs": { + "id": "topazlabs-co/topazlabs", + "family": "topazlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 204, + "output": 0 + } + }, + "novita/kimi-k2.5": { + "id": "novita/kimi-k2.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 262144 + } + }, + "novita/glm-4.7": { + "id": "novita/glm-4.7", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "novita/glm-5": { + "id": "novita/glm-5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "novita/minimax-m2.1": { + "id": "novita/minimax-m2.1", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "novita/glm-4.6": { + "id": "novita/glm-4.6", + "family": "glm", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "novita/glm-4.6v": { + "id": "novita/glm-4.6v", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 32768 + } + }, + "novita/deepseek-v3.2": { + "id": "novita/deepseek-v3.2", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "novita/glm-4.7-flash": { + "id": "novita/glm-4.7-flash", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 65500 + } + }, + "novita/glm-4.7-n": { + "id": "novita/glm-4.7-n", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "novita/kimi-k2-thinking": { + "id": "novita/kimi-k2-thinking", + "family": "kimi", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 0 + } + }, + "fireworks-ai/kimi-k2.5-fw": { + "id": "fireworks-ai/kimi-k2.5-fw", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 245760, + "output": 16384 + } + }, + "elevenlabs/elevenlabs-v2.5-turbo": { + "id": "elevenlabs/elevenlabs-v2.5-turbo", + "family": "elevenlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "elevenlabs/elevenlabs-v3": { + "id": "elevenlabs/elevenlabs-v3", + "family": "elevenlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "elevenlabs/elevenlabs-music": { + "id": "elevenlabs/elevenlabs-music", + "family": "elevenlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 2000, + "output": 0 + } + }, + "cerebras/gpt-oss-120b-cs": { + "id": "cerebras/gpt-oss-120b-cs", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "cerebras/llama-3.1-8b-cs": { + "id": "cerebras/llama-3.1-8b-cs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "cerebras/qwen3-32b-cs": { + "id": "cerebras/qwen3-32b-cs", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "cerebras/qwen3-235b-2507-cs": { + "id": "cerebras/qwen3-235b-2507-cs", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "cerebras/llama-3.3-70b-cs": { + "id": "cerebras/llama-3.3-70b-cs", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "stabilityai/stablediffusionxl": { + "id": "stabilityai/stablediffusionxl", + "family": "stable-diffusion", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 200, + "output": 0 + } + }, + "xai/grok-code-fast-1": { + "id": "xai/grok-code-fast-1", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 10000 + } + }, + "xai/grok-4-fast-reasoning": { + "id": "xai/grok-4-fast-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 256000 + } + }, + "xai/grok-4.1-fast-non-reasoning": { + "id": "xai/grok-4.1-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "xai/grok-4": { + "id": "xai/grok-4", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "xai/grok-3-mini": { + "id": "xai/grok-3-mini", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "xai/grok-4.20-multi-agent": { + "id": "xai/grok-4.20-multi-agent", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "family": "grok" + }, + "xai/grok-3": { + "id": "xai/grok-3", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "xai/grok-4-fast-non-reasoning": { + "id": "xai/grok-4-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "xai/grok-4.1-fast-reasoning": { + "id": "xai/grok-4.1-fast-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "runwayml/runway": { + "id": "runwayml/runway", + "family": "runway", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 256, + "output": 0 + } + }, + "runwayml/runway-gen-4-turbo": { + "id": "runwayml/runway-gen-4-turbo", + "family": "runway", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 256, + "output": 0 + } + }, + "openai/sora-2-pro": { + "id": "openai/sora-2-pro", + "family": "sora", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-4o-aug": { + "id": "openai/gpt-4o-aug", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/gpt-4-classic-0314": { + "id": "openai/gpt-4-classic-0314", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "openai/dall-e-3": { + "id": "openai/dall-e-3", + "family": "dall-e", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 800, + "output": 0 + } + }, + "openai/gpt-image-1": { + "id": "openai/gpt-image-1", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "openai/gpt-image-1-mini": { + "id": "openai/gpt-image-1-mini", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-4o-search": { + "id": "openai/gpt-4o-search", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/gpt-5.3-codex-spark": { + "id": "openai/gpt-5.3-codex-spark", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-3.5-turbo-raw": { + "id": "openai/gpt-3.5-turbo-raw", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4524, + "output": 2048 + } + }, + "openai/sora-2": { + "id": "openai/sora-2", + "family": "sora", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-5.2-instant": { + "id": "openai/gpt-5.2-instant", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-4o-mini-search": { + "id": "openai/gpt-4o-mini-search", + "family": "gpt-mini", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/gpt-image-1.5": { + "id": "openai/gpt-image-1.5", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "openai/gpt-5.1-instant": { + "id": "openai/gpt-5.1-instant", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + } + }, + "openai/gpt-4-classic": { + "id": "openai/gpt-4-classic", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "openai/gpt-5.3-instant": { + "id": "openai/gpt-5.3-instant", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + } + }, + "google/veo-3-fast": { + "id": "google/veo-3-fast", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/veo-3.1-fast": { + "id": "google/veo-3.1-fast", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-3.1-pro": { + "id": "google/gemini-3.1-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/imagen-3-fast": { + "id": "google/imagen-3-fast", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-2.0-flash": { + "id": "google/gemini-2.0-flash", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/gemini-deep-research": { + "id": "google/gemini-deep-research", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 0 + } + }, + "google/imagen-3": { + "id": "google/imagen-3", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/nano-banana": { + "id": "google/nano-banana", + "family": "nano-banana", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 65536, + "output": 0 + } + }, + "google/gemini-3.1-flash-lite": { + "id": "google/gemini-3.1-flash-lite", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-3-flash": { + "id": "google/gemini-3-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + }, + "family": "gemini-flash" + }, + "google/veo-3.1": { + "id": "google/veo-3.1", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/lyria": { + "id": "google/lyria", + "family": "lyria", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "google/imagen-4-ultra": { + "id": "google/imagen-4-ultra", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/nano-banana-pro": { + "id": "google/nano-banana-pro", + "family": "nano-banana", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 65536, + "output": 0 + } + }, + "google/gemini-3-pro": { + "id": "google/gemini-3-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/imagen-4-fast": { + "id": "google/imagen-4-fast", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/veo-3": { + "id": "google/veo-3", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/imagen-4": { + "id": "google/imagen-4", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemma-4-31b": { + "id": "google/gemma-4-31b", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 8192 + } + }, + "google/gemini-2.0-flash-lite": { + "id": "google/gemini-2.0-flash-lite", + "family": "gemini-flash-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/veo-2": { + "id": "google/veo-2", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "lumalabs/ray2": { + "id": "lumalabs/ray2", + "family": "ray", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 5000, + "output": 0 + } + }, + "anthropic/claude-sonnet-3.5": { + "id": "anthropic/claude-sonnet-3.5", + "family": "claude-sonnet", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "anthropic/claude-haiku-3": { + "id": "anthropic/claude-haiku-3", + "family": "claude-haiku", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "anthropic/claude-sonnet-3.7": { + "id": "anthropic/claude-sonnet-3.7", + "family": "claude-sonnet", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 128000 + } + }, + "anthropic/claude-haiku-3.5": { + "id": "anthropic/claude-haiku-3.5", + "family": "claude-haiku", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "anthropic/claude-sonnet-3.5-june": { + "id": "anthropic/claude-sonnet-3.5-june", + "family": "claude-sonnet", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "ideogramai/ideogram": { + "id": "ideogramai/ideogram", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "ideogramai/ideogram-v2": { + "id": "ideogramai/ideogram-v2", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "ideogramai/ideogram-v2a-turbo": { + "id": "ideogramai/ideogram-v2a-turbo", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "ideogramai/ideogram-v2a": { + "id": "ideogramai/ideogram-v2a", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "trytako/tako": { + "id": "trytako/tako", + "family": "tako", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2048, + "output": 0 + } + }, + "poetools/claude-code": { + "id": "poetools/claude-code", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "mistral-nemo": { + "id": "mistral-nemo", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "gemma2-9b-it": { + "id": "gemma2-9b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "llama-4-scout": { + "id": "llama-4-scout", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "claude-3.5-sonnet-v2": { + "id": "claude-3.5-sonnet-v2", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "hermes-2-pro-llama-3-8b": { + "id": "hermes-2-pro-llama-3-8b", + "family": "nousresearch", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "llama-prompt-guard-2-22m": { + "id": "llama-prompt-guard-2-22m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 2 + } + }, + "o1-mini": { + "id": "o1-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536 + } + }, + "gpt-4.1-mini-2025-04-14": { + "id": "gpt-4.1-mini-2025-04-14", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768 + } + }, + "claude-3-haiku-20240307": { + "id": "claude-3-haiku-20240307", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "llama-4-maverick": { + "id": "llama-4-maverick", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "mistral-large-2411": { + "id": "mistral-large-2411", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "kimi-k2-0711": { + "id": "kimi-k2-0711", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "gemma-3-12b-it": { + "id": "gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "deepseek-tng-r1t2-chimera": { + "id": "deepseek-tng-r1t2-chimera", + "family": "deepseek-thinking", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 130000, + "output": 163840 + } + }, + "o1": { + "id": "o1", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "llama-3.1-8b-instant": { + "id": "llama-3.1-8b-instant", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistral-small": { + "id": "mistral-small", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "codex-mini-latest": { + "id": "codex-mini-latest", + "family": "gpt-codex-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "grok-4": { + "id": "grok-4", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "qwen3-235b-a22b-thinking": { + "id": "qwen3-235b-a22b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 81920 + } + }, + "qwen2.5-coder-7b-fast": { + "id": "qwen2.5-coder-7b-fast", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "llama-3.1-8b-instruct-turbo": { + "id": "llama-3.1-8b-instruct-turbo", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "sonar-reasoning": { + "id": "sonar-reasoning", + "family": "sonar-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 4096 + } + }, + "claude-opus-4": { + "id": "claude-opus-4", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "llama-prompt-guard-2-86m": { + "id": "llama-prompt-guard-2-86m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 2 + } + }, + "grok-3-mini": { + "id": "grok-3-mini", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "llama-guard-4": { + "id": "llama-guard-4", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 1024 + } + }, + "qwen3-vl-235b-a22b-instruct": { + "id": "qwen3-vl-235b-a22b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "ernie-4.5-21b-a3b-thinking": { + "id": "ernie-4.5-21b-a3b-thinking", + "family": "ernie", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8000 + } + }, + "deepseek-v3.1-terminus": { + "id": "deepseek-v3.1-terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "grok-3": { + "id": "grok-3", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "gpt-oss:20b": { + "id": "gpt-oss:20b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "gemma4:31b": { + "id": "gemma4:31b", + "family": "gemma", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 8192 + } + }, + "gpt-oss:120b": { + "id": "gpt-oss:120b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen3.5:397b": { + "id": "qwen3.5:397b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 81920 + } + }, + "deepseek-v3.1:671b": { + "id": "deepseek-v3.1:671b", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "qwen3-vl:235b-instruct": { + "id": "qwen3-vl:235b-instruct", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "gemma3:4b": { + "id": "gemma3:4b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "ministral-3:14b": { + "id": "ministral-3:14b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "qwen3-next:80b": { + "id": "qwen3-next:80b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "qwen3-vl:235b": { + "id": "qwen3-vl:235b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "rnj-1:8b": { + "id": "rnj-1:8b", + "family": "rnj", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "mistral-large-3:675b": { + "id": "mistral-large-3:675b", + "family": "mistral-large", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "ministral-3:8b": { + "id": "ministral-3:8b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "gemma3:12b": { + "id": "gemma3:12b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "qwen3-coder:480b": { + "id": "qwen3-coder:480b", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "nemotron-3-nano:30b": { + "id": "nemotron-3-nano:30b", + "family": "nemotron", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 131072 + } + }, + "ministral-3:3b": { + "id": "ministral-3:3b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "gemma3:27b": { + "id": "gemma3:27b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "devstral-2:123b": { + "id": "devstral-2:123b", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "cogito-2.1:671b": { + "id": "cogito-2.1:671b", + "family": "cogito", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32000 + } + }, + "qwen3-coder-next": { + "id": "qwen3-coder-next", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144, + "input": 262144 + }, + "temperature": true + }, + "nemotron-3-super": { + "id": "nemotron-3-super", + "family": "nemotron", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "devstral-small-2:24b": { + "id": "devstral-small-2:24b", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "kimi-k2:1t": { + "id": "kimi-k2:1t", + "family": "kimi", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "anthropic.claude-opus-4-1-20250805-v1:0": { + "id": "anthropic.claude-opus-4-1-20250805-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "anthropic.claude-3-5-sonnet-20241022-v2:0": { + "id": "anthropic.claude-3-5-sonnet-20241022-v2:0", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "openai.gpt-oss-safeguard-120b": { + "id": "openai.gpt-oss-safeguard-120b", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia.nemotron-nano-3-30b": { + "id": "nvidia.nemotron-nano-3-30b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta.llama3-2-90b-instruct-v1:0": { + "id": "meta.llama3-2-90b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia.nemotron-super-3-120b": { + "id": "nvidia.nemotron-super-3-120b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "writer.palmyra-x5-v1:0": { + "id": "writer.palmyra-x5-v1:0", + "family": "palmyra", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1040000, + "output": 8192 + } + }, + "mistral.ministral-3-8b-instruct": { + "id": "mistral.ministral-3-8b-instruct", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-3-5-sonnet-20240620-v1:0": { + "id": "anthropic.claude-3-5-sonnet-20240620-v1:0", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "mistral.ministral-3-3b-instruct": { + "id": "mistral.ministral-3-3b-instruct", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "eu.anthropic.claude-opus-4-6-v1": { + "id": "eu.anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "amazon.nova-premier-v1:0": { + "id": "amazon.nova-premier-v1:0", + "family": "nova", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 16384 + } + }, + "eu.anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "eu.anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "mistral.devstral-2-123b": { + "id": "mistral.devstral-2-123b", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "us.anthropic.claude-opus-4-20250514-v1:0": { + "id": "us.anthropic.claude-opus-4-20250514-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "global.anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "global.anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "mistral.voxtral-small-24b-2507": { + "id": "mistral.voxtral-small-24b-2507", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "google.gemma-3-12b-it": { + "id": "google.gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "amazon.nova-pro-v1:0": { + "id": "amazon.nova-pro-v1:0", + "family": "nova-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "minimax.minimax-m2": { + "id": "minimax.minimax-m2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204608, + "output": 128000 + } + }, + "global.anthropic.claude-opus-4-7": { + "id": "global.anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "mistral.pixtral-large-2502-v1:0": { + "id": "mistral.pixtral-large-2502-v1:0", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta.llama4-maverick-17b-instruct-v1:0": { + "id": "meta.llama4-maverick-17b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 16384 + } + }, + "us.anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "us.anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "us.anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "us.anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "amazon.nova-micro-v1:0": { + "id": "amazon.nova-micro-v1:0", + "family": "nova-micro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "global.anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "global.anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic.claude-sonnet-4-6": { + "id": "anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "openai.gpt-oss-20b-1:0": { + "id": "openai.gpt-oss-20b-1:0", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "us.anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "us.anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "zai.glm-5": { + "id": "zai.glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 101376 + } + }, + "qwen.qwen3-32b-v1:0": { + "id": "qwen.qwen3-32b-v1:0", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "deepseek.v3.2": { + "id": "deepseek.v3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 81920 + } + }, + "eu.anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "eu.anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "zai.glm-4.7-flash": { + "id": "zai.glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "us.anthropic.claude-opus-4-7": { + "id": "us.anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "amazon.nova-2-lite-v1:0": { + "id": "amazon.nova-2-lite-v1:0", + "family": "nova", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "qwen.qwen3-coder-480b-a35b-v1:0": { + "id": "qwen.qwen3-coder-480b-a35b-v1:0", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "meta.llama3-2-1b-instruct-v1:0": { + "id": "meta.llama3-2-1b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 4096 + } + }, + "amazon.nova-lite-v1:0": { + "id": "amazon.nova-lite-v1:0", + "family": "nova-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "meta.llama3-1-8b-instruct-v1:0": { + "id": "meta.llama3-1-8b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "global.anthropic.claude-sonnet-4-6": { + "id": "global.anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "us.anthropic.claude-sonnet-4-6": { + "id": "us.anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "anthropic.claude-opus-4-7": { + "id": "anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "global.anthropic.claude-opus-4-6-v1": { + "id": "global.anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "google.gemma-3-27b-it": { + "id": "google.gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 8192 + } + }, + "global.anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "global.anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "google.gemma-3-4b-it": { + "id": "google.gemma-3-4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "us.anthropic.claude-opus-4-6-v1": { + "id": "us.anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "meta.llama4-scout-17b-instruct-v1:0": { + "id": "meta.llama4-scout-17b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 3500000, + "output": 16384 + } + }, + "us.anthropic.claude-opus-4-1-20250805-v1:0": { + "id": "us.anthropic.claude-opus-4-1-20250805-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "deepseek.v3-v1:0": { + "id": "deepseek.v3-v1:0", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 81920 + } + }, + "mistral.magistral-small-2509": { + "id": "mistral.magistral-small-2509", + "family": "magistral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 40000 + } + }, + "qwen.qwen3-next-80b-a3b": { + "id": "qwen.qwen3-next-80b-a3b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "zai.glm-4.7": { + "id": "zai.glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "moonshot.kimi-k2-thinking": { + "id": "moonshot.kimi-k2-thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "us.anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "us.anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "mistral.ministral-3-14b-instruct": { + "id": "mistral.ministral-3-14b-instruct", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-3-haiku-20240307-v1:0": { + "id": "anthropic.claude-3-haiku-20240307-v1:0", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "global.anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "global.anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "deepseek.r1-v1:0": { + "id": "deepseek.r1-v1:0", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta.llama3-1-405b-instruct-v1:0": { + "id": "meta.llama3-1-405b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistral.voxtral-mini-3b-2507": { + "id": "mistral.voxtral-mini-3b-2507", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "eu.anthropic.claude-sonnet-4-6": { + "id": "eu.anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "openai.gpt-oss-120b-1:0": { + "id": "openai.gpt-oss-120b-1:0", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia.nemotron-nano-12b-v2": { + "id": "nvidia.nemotron-nano-12b-v2", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "eu.anthropic.claude-opus-4-7": { + "id": "eu.anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "minimax.minimax-m2.5": { + "id": "minimax.minimax-m2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 98304 + } + }, + "meta.llama3-3-70b-instruct-v1:0": { + "id": "meta.llama3-3-70b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta.llama3-1-70b-instruct-v1:0": { + "id": "meta.llama3-1-70b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta.llama3-2-3b-instruct-v1:0": { + "id": "meta.llama3-2-3b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 4096 + } + }, + "eu.anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic.claude-opus-4-20250514-v1:0": { + "id": "anthropic.claude-opus-4-20250514-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "eu.anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "eu.anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "meta.llama3-2-11b-instruct-v1:0": { + "id": "meta.llama3-2-11b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "moonshotai.kimi-k2.5": { + "id": "moonshotai.kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "openai.gpt-oss-safeguard-20b": { + "id": "openai.gpt-oss-safeguard-20b", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-opus-4-6-v1": { + "id": "anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "qwen.qwen3-coder-30b-a3b-v1:0": { + "id": "qwen.qwen3-coder-30b-a3b-v1:0", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "minimax.minimax-m2.1": { + "id": "minimax.minimax-m2.1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "qwen.qwen3-vl-235b-a22b": { + "id": "qwen.qwen3-vl-235b-a22b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen.qwen3-coder-next": { + "id": "qwen.qwen3-coder-next", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "anthropic.claude-3-5-haiku-20241022-v1:0": { + "id": "anthropic.claude-3-5-haiku-20241022-v1:0", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "nvidia.nemotron-nano-9b-v2": { + "id": "nvidia.nemotron-nano-9b-v2", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistral.mistral-large-3-675b-instruct": { + "id": "mistral.mistral-large-3-675b-instruct", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "qwen.qwen3-235b-a22b-2507-v1:0": { + "id": "qwen.qwen3-235b-a22b-2507-v1:0", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "anthropic.claude-3-7-sonnet-20250219-v1:0": { + "id": "anthropic.claude-3-7-sonnet-20250219-v1:0", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "writer.palmyra-x4-v1:0": { + "id": "writer.palmyra-x4-v1:0", + "family": "palmyra", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 122880, + "output": 8192 + } + }, + "text-prime": { + "id": "text-prime", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 30000 + } + }, + "text-standard": { + "id": "text-standard", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "text-max": { + "id": "text-max", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "nvidia/nemotron-120b-a12b": { + "id": "nvidia/Nemotron-120B-A12B", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32678 + } + }, + "glm-4.6v-flash": { + "id": "glm-4.6v-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "openai-gpt-4o-mini-2024-07-18": { + "id": "openai-gpt-4o-mini-2024-07-18", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen3-next-80b": { + "id": "qwen3-next-80b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "grok-4-20-multi-agent": { + "id": "grok-4-20-multi-agent", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 128000 + } + }, + "z-ai-glm-5v-turbo": { + "id": "z-ai-glm-5v-turbo", + "family": "glmv", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32768 + } + }, + "grok-41-fast": { + "id": "grok-41-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 30000 + } + }, + "nvidia-nemotron-cascade-2-30b-a3b": { + "id": "nvidia-nemotron-cascade-2-30b-a3b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768 + } + }, + "grok-4-20": { + "id": "grok-4-20", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 128000 + } + }, + "google-gemma-4-26b-a4b-it": { + "id": "google-gemma-4-26b-a4b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "qwen3-coder-480b-a35b-instruct-turbo": { + "id": "qwen3-coder-480b-a35b-instruct-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "qwen3-5-397b-a17b": { + "id": "qwen3-5-397b-a17b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "zai-org-glm-4.7": { + "id": "zai-org-glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 16384 + } + }, + "openai-gpt-54": { + "id": "openai-gpt-54", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 131072 + } + }, + "zai-org-glm-4.7-flash": { + "id": "zai-org-glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "nvidia-nemotron-3-nano-30b-a3b": { + "id": "nvidia-nemotron-3-nano-30b-a3b", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai-gpt-53-codex": { + "id": "openai-gpt-53-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "openai-gpt-52": { + "id": "openai-gpt-52", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "mistral-small-3-2-24b-instruct": { + "id": "mistral-small-3-2-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "minimax-m27": { + "id": "minimax-m27", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 32768 + } + }, + "qwen3-5-35b-a3b": { + "id": "qwen3-5-35b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "mercury-2": { + "id": "mercury-2", + "family": "mercury", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 50000 + } + }, + "google-gemma-3-27b-it": { + "id": "google-gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 16384 + } + }, + "olafangensan-glm-4.7-flash-heretic": { + "id": "olafangensan-glm-4.7-flash-heretic", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 24000 + } + }, + "openai-gpt-52-codex": { + "id": "openai-gpt-52-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "venice-uncensored-role-play": { + "id": "venice-uncensored-role-play", + "family": "venice", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "zai-org-glm-5": { + "id": "zai-org-glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 32000 + } + }, + "zai-org-glm-4.6": { + "id": "zai-org-glm-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 16384 + } + }, + "mistral-small-2603": { + "id": "mistral-small-2603", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "openai-gpt-oss-120b": { + "id": "openai-gpt-oss-120b", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen3-5-9b": { + "id": "qwen3-5-9b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768 + } + }, + "openai-gpt-54-pro": { + "id": "openai-gpt-54-pro", + "family": "gpt-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "openai-gpt-54-mini": { + "id": "openai-gpt-54-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "minimax-m25": { + "id": "minimax-m25", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 32768 + } + }, + "zai-org-glm-5-1": { + "id": "zai-org-glm-5-1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 24000 + } + }, + "qwen-3-6-plus": { + "id": "qwen-3-6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "aion-labs-aion-2-0": { + "id": "aion-labs-aion-2-0", + "family": "o", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "openai-gpt-4o-2024-11-20": { + "id": "openai-gpt-4o-2024-11-20", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "llama-3.3-70b": { + "id": "llama-3.3-70b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "kimi-k2-5": { + "id": "kimi-k2-5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "llama-3.2-3b": { + "id": "llama-3.2-3b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "arcee-trinity-large-thinking": { + "id": "arcee-trinity-large-thinking", + "family": "trinity", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "hermes-3-llama-3.1-405b": { + "id": "hermes-3-llama-3.1-405b", + "family": "hermes", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "gemini-3-1-pro-preview": { + "id": "gemini-3-1-pro-preview", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "claude-opus-4-6-fast": { + "id": "claude-opus-4-6-fast", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "z-ai-glm-5-turbo": { + "id": "z-ai-glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32768 + } + }, + "google-gemma-4-31b-it": { + "id": "google-gemma-4-31b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "coding-glm-5-free": { + "id": "coding-glm-5-free", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "coding-glm-4.7": { + "id": "coding-glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "gemini-3-pro-preview-search": { + "id": "gemini-3-pro-preview-search", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65000 + } + }, + "coding-glm-5.1": { + "id": "coding-glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "coding-minimax-m2.1-free": { + "id": "coding-minimax-m2.1-free", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "deepseek-v3.2-fast": { + "id": "deepseek-v3.2-fast", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "deepseek-v3.2-think": { + "id": "deepseek-v3.2-think", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 64000 + } + }, + "claude-opus-4-6-think": { + "id": "claude-opus-4-6-think", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "coding-glm-4.7-free": { + "id": "coding-glm-4.7-free", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "claude-sonnet-4-6-think": { + "id": "claude-sonnet-4-6-think", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, "llama3.1-8b": { "id": "llama3.1-8b", "family": "llama", @@ -38913,6 +31518,25 @@ "output": 8000 } }, + "qwen-3-235b-a22b-instruct-2507": { + "id": "qwen-3-235b-a22b-instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 32000 + } + }, "zai-glm-4.7": { "id": "zai-glm-4.7", "reasoning": false, @@ -38931,8 +31555,1184 @@ "output": 40000 } }, - "gpt-5.3-chat": { - "id": "gpt-5.3-chat", + "gpt-5-4": { + "id": "gpt-5-4", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 272000, + "output": 128000 + } + }, + "deepseek-v3-2": { + "id": "deepseek-v3-2", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "zai-glm-5-1": { + "id": "zai-glm-5-1", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 8192 + } + }, + "minimax-m2-5": { + "id": "minimax-m2-5", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 192000, + "output": 8192 + } + }, + "gpt-5-3-codex": { + "id": "gpt-5-3-codex", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "qwen/qwen3-coder-30b": { + "id": "qwen/qwen3-coder-30b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3-30b-a3b-2507": { + "id": "qwen/qwen3-30b-a3b-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "lucidnova-rf1-100b": { + "id": "lucidnova-rf1-100b", + "family": "nova", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 120000, + "output": 8000 + } + }, + "lucidquery-nexus-coder": { + "id": "lucidquery-nexus-coder", + "family": "lucid", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 250000, + "output": 60000 + } + }, + "kimi-k2-0711-preview": { + "id": "kimi-k2-0711-preview", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "mai-ds-r1": { + "id": "mai-ds-r1", + "family": "mai", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "codestral-2501": { + "id": "codestral-2501", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "gpt-3.5-turbo-instruct": { + "id": "gpt-3.5-turbo-instruct", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "mistral-medium-2505": { + "id": "mistral-medium-2505", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "phi-4-reasoning-plus": { + "id": "phi-4-reasoning-plus", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "cohere-embed-v3-english": { + "id": "cohere-embed-v3-english", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + } + }, + "gpt-4-32k": { + "id": "gpt-4-32k", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "phi-4": { + "id": "phi-4", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere-command-r-plus-08-2024": { + "id": "cohere-command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "gpt-3.5-turbo-0613": { + "id": "gpt-3.5-turbo-0613", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "phi-3-medium-128k-instruct": { + "id": "phi-3-medium-128k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "phi-3-small-128k-instruct": { + "id": "phi-3-small-128k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "gpt-3.5-turbo-0301": { + "id": "gpt-3.5-turbo-0301", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "phi-4-mini": { + "id": "phi-4-mini", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta-llama-3-8b-instruct": { + "id": "meta-llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "gpt-4": { + "id": "gpt-4", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "phi-4-mini-reasoning": { + "id": "phi-4-mini-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta-llama-3.1-70b-instruct": { + "id": "meta-llama-3.1-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "phi-3-mini-4k-instruct": { + "id": "phi-3-mini-4k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + } + }, + "text-embedding-3-small": { + "id": "text-embedding-3-small", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 1536 + }, + "temperature": false + }, + "gpt-3.5-turbo-1106": { + "id": "gpt-3.5-turbo-1106", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "model-router": { + "id": "model-router", + "family": "model-router", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mistral-small-2503": { + "id": "mistral-small-2503", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "cohere-embed-v3-multilingual": { + "id": "cohere-embed-v3-multilingual", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + } + }, + "o1-preview": { + "id": "o1-preview", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "gpt-3.5-turbo-0125": { + "id": "gpt-3.5-turbo-0125", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "cohere-embed-v-4-0": { + "id": "cohere-embed-v-4-0", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 1536 + } + }, + "gpt-4-turbo-vision": { + "id": "gpt-4-turbo-vision", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "gpt-5.1-chat": { + "id": "gpt-5.1-chat", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "image", + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "meta-llama-3.1-405b-instruct": { + "id": "meta-llama-3.1-405b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "llama-3.2-11b-vision-instruct": { + "id": "llama-3.2-11b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "cohere-command-a": { + "id": "cohere-command-a", + "family": "command-a", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8000 + } + }, + "cohere-command-r-08-2024": { + "id": "cohere-command-r-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "deepseek-v3.2-speciale": { + "id": "deepseek-v3.2-speciale", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "llama-3.2-90b-vision-instruct": { + "id": "llama-3.2-90b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "text-embedding-ada-002": { + "id": "text-embedding-ada-002", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + }, + "temperature": false + }, + "gpt-4-turbo": { + "id": "gpt-4-turbo", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "phi-3-small-8k-instruct": { + "id": "phi-3-small-8k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "meta-llama-3-70b-instruct": { + "id": "meta-llama-3-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "phi-4-reasoning": { + "id": "phi-4-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "phi-3-mini-128k-instruct": { + "id": "phi-3-mini-128k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "text-embedding-3-large": { + "id": "text-embedding-3-large", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 3072 + }, + "temperature": false + }, + "phi-3.5-moe-instruct": { + "id": "phi-3.5-moe-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "gpt-5-chat": { + "id": "gpt-5-chat", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "meta-llama-3.1-8b-instruct": { + "id": "meta-llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "ministral-3b": { + "id": "ministral-3b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "phi-3-medium-4k-instruct": { + "id": "phi-3-medium-4k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + } + }, + "llama-4-scout-17b-16e-instruct": { + "id": "llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "phi-3.5-mini-instruct": { + "id": "phi-3.5-mini-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "phi-4-multimodal": { + "id": "phi-4-multimodal", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "codex-mini": { + "id": "codex-mini", + "family": "gpt-codex-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gpt-5.2-chat": { + "id": "gpt-5.2-chat", "family": "gpt-codex", "reasoning": true, "temperature": false, @@ -38951,127 +32751,9 @@ "output": 16384 } }, - "kimi-k2-instruct": { - "id": "kimi-k2-instruct", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131000, - "output": 131000 - } - }, - "claude-opus4-6": { - "id": "claude-opus4-6", - "family": "claude-opus", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 1000000 - } - }, - "claude-4-6-sonnet": { - "id": "claude-4-6-sonnet", - "family": "claude-sonnet", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image", - "pdf" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 1000000, - "output": 1000000 - } - }, - "devstral-small-2512": { - "id": "devstral-small-2512", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262000, - "output": 262000 - } - }, - "intellect-3": { - "id": "intellect-3", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 128000, - "output": 128000 - } - }, - "nova-pro-v1": { - "id": "nova-pro-v1", - "family": "nova-pro", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 300000, - "output": 5000 - } - }, - "llama-3.1-405b-instruct": { - "id": "llama-3.1-405b-instruct", - "family": "llama", + "command-r7b-12-2024": { + "id": "command-r7b-12-2024", + "family": "command-r", "reasoning": false, "temperature": true, "toolCall": true, @@ -39085,49 +32767,232 @@ }, "limit": { "context": 128000, - "output": 128000 + "output": 4000 } }, - "claude-opus4-5": { - "id": "claude-opus4-5", - "family": "claude-opus", - "reasoning": true, + "c4ai-aya-vision-8b": { + "id": "c4ai-aya-vision-8b", + "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text", - "image", - "pdf" + "image" ], "output": [ "text" ] }, "limit": { - "context": 200000, - "output": 200000 + "context": 16000, + "output": 4000 } }, - "claude-4-5-sonnet": { - "id": "claude-4-5-sonnet", - "family": "claude-sonnet", - "reasoning": true, + "command-r-plus-08-2024": { + "id": "command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image", - "pdf" + "text" ], "output": [ "text" ] }, "limit": { - "context": 200000, - "output": 200000 + "context": 128000, + "output": 4000 + } + }, + "c4ai-aya-expanse-8b": { + "id": "c4ai-aya-expanse-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 4000 + } + }, + "command-r7b-arabic-02-2025": { + "id": "command-r7b-arabic-02-2025", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "command-a-vision-07-2025": { + "id": "command-a-vision-07-2025", + "family": "command-a", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8000 + } + }, + "c4ai-aya-vision-32b": { + "id": "c4ai-aya-vision-32b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4000 + } + }, + "command-a-translate-08-2025": { + "id": "command-a-translate-08-2025", + "family": "command-a", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 8000 + } + }, + "command-r-08-2024": { + "id": "command-r-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "c4ai-aya-expanse-32b": { + "id": "c4ai-aya-expanse-32b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "command-a-03-2025": { + "id": "command-a-03-2025", + "family": "command-a", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8000 + } + }, + "speakleash/bielik-11b-v3.0-instruct": { + "id": "speakleash/Bielik-11B-v3.0-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "speakleash/bielik-11b-v2.6-instruct": { + "id": "speakleash/Bielik-11B-v2.6-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 } }, "grok-2-1212": { @@ -39149,12 +33014,109 @@ "output": 8192 } }, - "grok-4.20-multi-agent-0309": { - "id": "grok-4.20-multi-agent-0309", + "grok-vision-beta": { + "id": "grok-vision-beta", + "family": "grok-vision", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "grok-3-mini-fast": { + "id": "grok-3-mini-fast", "family": "grok", "reasoning": true, "temperature": true, - "toolCall": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-3-mini-latest": { + "id": "grok-3-mini-latest", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-3-fast": { + "id": "grok-3-fast", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-2-vision-latest": { + "id": "grok-2-vision-latest", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "grok-4.20-0309-reasoning": { + "id": "grok-4.20-0309-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text", @@ -39169,105 +33131,8 @@ "output": 30000 } }, - "grok-2": { - "id": "grok-2", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "grok-3-fast-latest": { - "id": "grok-3-fast-latest", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "grok-2-vision": { - "id": "grok-2-vision", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096 - } - }, - "grok-2-vision-1212": { - "id": "grok-2-vision-1212", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096 - } - }, - "grok-beta": { - "id": "grok-beta", - "family": "grok-beta", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 4096 - } - }, - "grok-3-mini-fast": { - "id": "grok-3-mini-fast", + "grok-3-mini-fast-latest": { + "id": "grok-3-mini-fast-latest", "family": "grok", "reasoning": true, "temperature": true, @@ -39324,10 +33189,29 @@ "output": 8192 } }, - "grok-4-1-fast": { - "id": "grok-4-1-fast", + "grok-2": { + "id": "grok-2", "family": "grok", - "reasoning": true, + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-4.20-0309-non-reasoning": { + "id": "grok-4.20-0309-non-reasoning", + "family": "grok", + "reasoning": false, "temperature": true, "toolCall": true, "modalities": { @@ -39344,32 +33228,12 @@ "output": 30000 } }, - "grok-2-vision-latest": { - "id": "grok-2-vision-latest", + "grok-3-fast-latest": { + "id": "grok-3-fast-latest", "family": "grok", "reasoning": false, "temperature": true, "toolCall": true, - "modalities": { - "input": [ - "text", - "image" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 8192, - "output": 4096 - } - }, - "grok-3-mini-latest": { - "id": "grok-3-mini-latest", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, "modalities": { "input": [ "text" @@ -39383,31 +33247,12 @@ "output": 8192 } }, - "grok-3-mini-fast-latest": { - "id": "grok-3-mini-fast-latest", + "grok-4.20-multi-agent-0309": { + "id": "grok-4.20-multi-agent-0309", "family": "grok", "reasoning": true, "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "grok-4.20-0309-reasoning": { - "id": "grok-4.20-0309-reasoning", - "family": "grok", - "reasoning": true, - "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text", @@ -39441,9 +33286,28 @@ "output": 8192 } }, - "grok-vision-beta": { - "id": "grok-vision-beta", - "family": "grok-vision", + "grok-beta": { + "id": "grok-beta", + "family": "grok-beta", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 4096 + } + }, + "grok-2-vision": { + "id": "grok-2-vision", + "family": "grok", "reasoning": false, "temperature": true, "toolCall": true, @@ -39461,8 +33325,5312 @@ "output": 4096 } }, - "grok-4.20-0309-non-reasoning": { - "id": "grok-4.20-0309-non-reasoning", + "grok-4-1-fast": { + "id": "grok-4-1-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "grok-2-vision-1212": { + "id": "grok-2-vision-1212", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "mistralai/mistral-small-3.2-24b-instruct-2506": { + "id": "mistralai/Mistral-Small-3.2-24B-Instruct-2506", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "claude-haiku-4-5@20251001": { + "id": "claude-haiku-4-5@20251001", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-sonnet-4-6@default": { + "id": "claude-sonnet-4-6@default", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-3-5-haiku@20241022": { + "id": "claude-3-5-haiku@20241022", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "claude-3-5-sonnet@20241022": { + "id": "claude-3-5-sonnet@20241022", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "claude-opus-4-1@20250805": { + "id": "claude-opus-4-1@20250805", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-sonnet-4@20250514": { + "id": "claude-sonnet-4@20250514", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-3-7-sonnet@20250219": { + "id": "claude-3-7-sonnet@20250219", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-opus-4@20250514": { + "id": "claude-opus-4@20250514", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-opus-4-5@20251101": { + "id": "claude-opus-4-5@20251101", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-sonnet-4-5@20250929": { + "id": "claude-sonnet-4-5@20250929", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-opus-4-6@default": { + "id": "claude-opus-4-6@default", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "claude-opus-4-7@default": { + "id": "claude-opus-4-7@default", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "qwen/qwen3-30b-a3b-instruct-2507-fp8": { + "id": "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 64000 + } + }, + "mistralai/devstral-small-2-24b-instruct-2512": { + "id": "mistralai/devstral-small-2-24b-instruct-2512", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "mistralai/magistral-small-2509": { + "id": "mistralai/Magistral-Small-2509", + "family": "magistral-small", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "microsoft/phi-4-multimodal-instruct": { + "id": "microsoft/phi-4-multimodal-instruct", + "family": "phi", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "temperature": true + }, + "kblab/kb-whisper-large": { + "id": "KBLab/kb-whisper-large", + "family": "whisper", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 480000, + "output": 4800 + }, + "temperature": false + }, + "nvidia/llama-3.3-70b-instruct-fp8": { + "id": "nvidia/Llama-3.3-70B-Instruct-FP8", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "openai/whisper-large-v3": { + "id": "openai/whisper-large-v3", + "family": "whisper", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + }, + "temperature": false + }, + "intfloat/multilingual-e5-large-instruct": { + "id": "intfloat/multilingual-e5-large-instruct", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + }, + "temperature": false + }, + "hf:meta-llama/llama-3.1-405b-instruct": { + "id": "hf:meta-llama/Llama-3.1-405B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-4-scout-17b-16e-instruct": { + "id": "hf:meta-llama/Llama-4-Scout-17B-16E-Instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 328000, + "output": 4096 + } + }, + "hf:meta-llama/llama-3.3-70b-instruct": { + "id": "hf:meta-llama/Llama-3.3-70B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-3.1-8b-instruct": { + "id": "hf:meta-llama/Llama-3.1-8B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-3.1-70b-instruct": { + "id": "hf:meta-llama/Llama-3.1-70B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { + "id": "hf:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 524000, + "output": 4096 + } + }, + "hf:minimaxai/minimax-m2": { + "id": "hf:MiniMaxAI/MiniMax-M2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 131000 + } + }, + "hf:minimaxai/minimax-m2.5": { + "id": "hf:MiniMaxAI/MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 191488, + "output": 65536 + } + }, + "hf:minimaxai/minimax-m2.1": { + "id": "hf:MiniMaxAI/MiniMax-M2.1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "hf:qwen/qwen3.5-397b-a17b": { + "id": "hf:Qwen/Qwen3.5-397B-A17B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "hf:qwen/qwen2.5-coder-32b-instruct": { + "id": "hf:Qwen/Qwen2.5-Coder-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "hf:qwen/qwen3-235b-a22b-instruct-2507": { + "id": "hf:Qwen/Qwen3-235B-A22B-Instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "hf:qwen/qwen3-235b-a22b-thinking-2507": { + "id": "hf:Qwen/Qwen3-235B-A22B-Thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "hf:qwen/qwen3-coder-480b-a35b-instruct": { + "id": "hf:Qwen/Qwen3-Coder-480B-A35B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "hf:deepseek-ai/deepseek-v3.1": { + "id": "hf:deepseek-ai/DeepSeek-V3.1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-v3-0324": { + "id": "hf:deepseek-ai/DeepSeek-V3-0324", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-v3": { + "id": "hf:deepseek-ai/DeepSeek-V3", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-r1": { + "id": "hf:deepseek-ai/DeepSeek-R1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-r1-0528": { + "id": "hf:deepseek-ai/DeepSeek-R1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-v3.2": { + "id": "hf:deepseek-ai/DeepSeek-V3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 162816, + "input": 162816, + "output": 8000 + } + }, + "hf:deepseek-ai/deepseek-v3.1-terminus": { + "id": "hf:deepseek-ai/DeepSeek-V3.1-Terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:openai/gpt-oss-120b": { + "id": "hf:openai/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:moonshotai/kimi-k2-thinking": { + "id": "hf:moonshotai/Kimi-K2-Thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "hf:moonshotai/kimi-k2-instruct-0905": { + "id": "hf:moonshotai/Kimi-K2-Instruct-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "hf:moonshotai/kimi-k2.5": { + "id": "hf:moonshotai/Kimi-K2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "hf:nvidia/nvidia-nemotron-3-super-120b-a12b-nvfp4": { + "id": "hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "hf:nvidia/kimi-k2.5-nvfp4": { + "id": "hf:nvidia/Kimi-K2.5-NVFP4", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "hf:zai-org/glm-4.7-flash": { + "id": "hf:zai-org/GLM-4.7-Flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "hf:zai-org/glm-4.7": { + "id": "hf:zai-org/GLM-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "hf:zai-org/glm-5.1": { + "id": "hf:zai-org/GLM-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "hf:zai-org/glm-5": { + "id": "hf:zai-org/GLM-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "hf:zai-org/glm-4.6": { + "id": "hf:zai-org/GLM-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "black-forest-labs/flux.1-dev": { + "id": "black-forest-labs/flux.1-dev", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 4096, + "output": 0 + } + }, + "mistralai/codestral-22b-instruct-v0.1": { + "id": "mistralai/codestral-22b-instruct-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/mistral-small-3.1-24b-instruct-2503": { + "id": "mistralai/mistral-small-3.1-24b-instruct-2503", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/mamba-codestral-7b-v0.1": { + "id": "mistralai/mamba-codestral-7b-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/mistral-large-2-instruct": { + "id": "mistralai/mistral-large-2-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-3-medium-4k-instruct": { + "id": "microsoft/phi-3-medium-4k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + }, + "family": "phi" + }, + "microsoft/phi-3.5-moe-instruct": { + "id": "microsoft/phi-3.5-moe-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "microsoft/phi-3-small-8k-instruct": { + "id": "microsoft/phi-3-small-8k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + }, + "family": "phi" + }, + "microsoft/phi-3-vision-128k-instruct": { + "id": "microsoft/phi-3-vision-128k-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-3.5-vision-instruct": { + "id": "microsoft/phi-3.5-vision-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "microsoft/phi-3-small-128k-instruct": { + "id": "microsoft/phi-3-small-128k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "microsoft/phi-3-medium-128k-instruct": { + "id": "microsoft/phi-3-medium-128k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "nvidia/nemotron-4-340b-instruct": { + "id": "nvidia/nemotron-4-340b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/llama3-chatqa-1.5-70b": { + "id": "nvidia/llama3-chatqa-1.5-70b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/parakeet-tdt-0.6b-v2": { + "id": "nvidia/parakeet-tdt-0.6b-v2", + "family": "parakeet", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + } + }, + "nvidia/cosmos-nemotron-34b": { + "id": "nvidia/cosmos-nemotron-34b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "nvidia/llama-embed-nemotron-8b": { + "id": "nvidia/llama-embed-nemotron-8b", + "family": "llama", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "nvidia/llama-3.1-nemotron-51b-instruct": { + "id": "nvidia/llama-3.1-nemotron-51b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/nemoretriever-ocr-v1": { + "id": "nvidia/nemoretriever-ocr-v1", + "family": "nemoretriever", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + } + }, + "deepseek-ai/deepseek-coder-6.7b-instruct": { + "id": "deepseek-ai/deepseek-coder-6.7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "z-ai/glm4.7": { + "id": "z-ai/glm4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "z-ai/glm5": { + "id": "z-ai/glm5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131000 + } + }, + "meta/llama-4-scout-17b-16e-instruct": { + "id": "meta/llama-4-scout-17b-16e-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + }, + "family": "llama" + }, + "meta/llama-3.3-70b-instruct": { + "id": "meta/llama-3.3-70b-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + }, + "family": "llama" + }, + "meta/llama3-8b-instruct": { + "id": "meta/llama3-8b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama3-70b-instruct": { + "id": "meta/llama3-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/codellama-70b": { + "id": "meta/codellama-70b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-3.2-11b-vision-instruct": { + "id": "meta/llama-3.2-11b-vision-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + }, + "family": "llama" + }, + "meta/llama-3.1-70b-instruct": { + "id": "meta/llama-3.1-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-3.2-1b-instruct": { + "id": "meta/llama-3.2-1b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + }, + "family": "llama" + }, + "meta/llama-4-maverick-17b-128e-instruct": { + "id": "meta/llama-4-maverick-17b-128e-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-3.1-405b-instruct": { + "id": "meta/llama-3.1-405b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemma-3-1b-it": { + "id": "google/gemma-3-1b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/codegemma-7b": { + "id": "google/codegemma-7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/codegemma-1.1-7b": { + "id": "google/codegemma-1.1-7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemma-3n-e2b-it": { + "id": "google/gemma-3n-e2b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistral/mistral-nemo-12b-instruct": { + "id": "mistral/mistral-nemo-12b-instruct", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + } + }, + "meta/llama-3.2-3b-instruct": { + "id": "meta/llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + } + }, + "meta/llama-3.1-8b-instruct": { + "id": "meta/llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + } + }, + "qwen/qwen-2.5-7b-vision-instruct": { + "id": "qwen/qwen-2.5-7b-vision-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 125000, + "output": 4096 + } + }, + "google/gemma-3": { + "id": "google/gemma-3", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 125000, + "output": 4096 + } + }, + "osmosis/osmosis-structure-0.6b": { + "id": "osmosis/osmosis-structure-0.6b", + "family": "osmosis", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4000, + "output": 2048 + } + }, + "mercury-edit-2": { + "id": "mercury-edit-2", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "gpt-4o-2024-05-13": { + "id": "gpt-4o-2024-05-13", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "o4-mini-deep-research": { + "id": "o4-mini-deep-research", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gpt-image-1": { + "id": "gpt-image-1", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "gpt-4o-2024-08-06": { + "id": "gpt-4o-2024-08-06", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "gpt-image-1-mini": { + "id": "gpt-image-1-mini", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "gpt-3.5-turbo": { + "id": "gpt-3.5-turbo", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "output": 16384 + } + }, + "o3-deep-research": { + "id": "o3-deep-research", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "o1-pro": { + "id": "o1-pro", + "family": "o-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "chatgpt-image-latest": { + "id": "chatgpt-image-latest", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "gpt-image-1.5": { + "id": "gpt-image-1.5", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "xai/grok-4-fast": { + "id": "xai/grok-4-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 64000 + } + }, + "anthropic/claude-3-7-sonnet": { + "id": "anthropic/claude-3-7-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "glm-5-fp8": { + "id": "GLM-5-FP8", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "mistral-small-latest": { + "id": "mistral-small-latest", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "labs-devstral-small-2512": { + "id": "labs-devstral-small-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "devstral-2512": { + "id": "devstral-2512", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "magistral-medium-latest": { + "id": "magistral-medium-latest", + "family": "magistral-medium", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "open-mixtral-8x7b": { + "id": "open-mixtral-8x7b", + "family": "mixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "pixtral-large-latest": { + "id": "pixtral-large-latest", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "codestral-latest": { + "id": "codestral-latest", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "mistral-large-latest": { + "id": "mistral-large-latest", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mistral-small-2506": { + "id": "mistral-small-2506", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "pixtral-12b": { + "id": "pixtral-12b", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "ministral-8b-latest": { + "id": "ministral-8b-latest", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral-embed": { + "id": "mistral-embed", + "family": "mistral-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 3072 + } + }, + "magistral-small": { + "id": "magistral-small", + "family": "magistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "ministral-3b-latest": { + "id": "ministral-3b-latest", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "open-mixtral-8x22b": { + "id": "open-mixtral-8x22b", + "family": "mixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 64000 + } + }, + "devstral-small-2505": { + "id": "devstral-small-2505", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "devstral-medium-2507": { + "id": "devstral-medium-2507", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral-medium-latest": { + "id": "mistral-medium-latest", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "open-mistral-7b": { + "id": "open-mistral-7b", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 8000 + } + }, + "devstral-medium-latest": { + "id": "devstral-medium-latest", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "devstral-small-2507": { + "id": "devstral-small-2507", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "mistral-medium-2508": { + "id": "mistral-medium-2508", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "mixtral-8x7b-instruct-v0.1": { + "id": "mixtral-8x7b-instruct-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "qwen2.5-coder-32b-instruct": { + "id": "qwen2.5-coder-32b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "meta-llama-3_3-70b-instruct": { + "id": "meta-llama-3_3-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistral-7b-instruct-v0.3": { + "id": "mistral-7b-instruct-v0.3", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "nova-pro-v1": { + "id": "nova-pro-v1", + "family": "nova-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 5000 + } + }, + "claude-4-5-sonnet": { + "id": "claude-4-5-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "kimi-k2-instruct": { + "id": "kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "claude-opus4-6": { + "id": "claude-opus4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "devstral-small-2512": { + "id": "devstral-small-2512", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "claude-opus4-5": { + "id": "claude-opus4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "claude-4-6-sonnet": { + "id": "claude-4-6-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "intellect-3": { + "id": "intellect-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "llama-3.1-405b-instruct": { + "id": "llama-3.1-405b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "qwen/qwen2.5-vl-7b-instruct": { + "id": "Qwen/Qwen2.5-VL-7B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "zai-org/glm-5v-turbo": { + "id": "zai-org/GLM-5V-Turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "alibaba/qwen3-coder-plus": { + "id": "alibaba/qwen3-coder-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "alibaba/qwen3-embedding-8b": { + "id": "alibaba/qwen3-embedding-8b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "alibaba/qwen-3-30b": { + "id": "alibaba/qwen-3-30b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen-3-235b": { + "id": "alibaba/qwen-3-235b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen3.5-flash": { + "id": "alibaba/qwen3.5-flash", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "alibaba/qwen3.6-plus": { + "id": "alibaba/qwen3.6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "alibaba/qwen3-max": { + "id": "alibaba/qwen3-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "alibaba/qwen3-embedding-0.6b": { + "id": "alibaba/qwen3-embedding-0.6b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "alibaba/qwen-3-32b": { + "id": "alibaba/qwen-3-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen3-next-80b-a3b-thinking": { + "id": "alibaba/qwen3-next-80b-a3b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "alibaba/qwen3-vl-thinking": { + "id": "alibaba/qwen3-vl-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 129024 + } + }, + "alibaba/qwen3-235b-a22b-thinking": { + "id": "alibaba/qwen3-235b-a22b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262114, + "output": 262114 + } + }, + "alibaba/qwen3-next-80b-a3b-instruct": { + "id": "alibaba/qwen3-next-80b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "alibaba/qwen3-coder-next": { + "id": "alibaba/qwen3-coder-next", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "alibaba/qwen3-embedding-4b": { + "id": "alibaba/qwen3-embedding-4b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "alibaba/qwen3-max-thinking": { + "id": "alibaba/qwen3-max-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "alibaba/qwen3-coder": { + "id": "alibaba/qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "alibaba/qwen3-max-preview": { + "id": "alibaba/qwen3-max-preview", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "alibaba/qwen3.5-plus": { + "id": "alibaba/qwen3.5-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "alibaba/qwen-3-14b": { + "id": "alibaba/qwen-3-14b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen3-vl-instruct": { + "id": "alibaba/qwen3-vl-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 129024 + } + }, + "alibaba/qwen3-coder-30b-a3b": { + "id": "alibaba/qwen3-coder-30b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 32768 + } + }, + "perplexity/sonar-reasoning": { + "id": "perplexity/sonar-reasoning", + "family": "sonar-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 8000 + } + }, + "deepseek/deepseek-v3.2-thinking": { + "id": "deepseek/deepseek-v3.2-thinking", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "deepseek/deepseek-v3": { + "id": "deepseek/deepseek-v3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 16384 + } + }, + "arcee-ai/trinity-large-preview": { + "id": "arcee-ai/trinity-large-preview", + "family": "trinity", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "recraft/recraft-v3": { + "id": "recraft/recraft-v3", + "family": "recraft", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "recraft/recraft-v2": { + "id": "recraft/recraft-v2", + "family": "recraft", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "voyage/voyage-3-large": { + "id": "voyage/voyage-3-large", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-4-large": { + "id": "voyage/voyage-4-large", + "family": "voyage", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 0 + } + }, + "voyage/voyage-3.5-lite": { + "id": "voyage/voyage-3.5-lite", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-code-3": { + "id": "voyage/voyage-code-3", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-finance-2": { + "id": "voyage/voyage-finance-2", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-4-lite": { + "id": "voyage/voyage-4-lite", + "family": "voyage", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 0 + } + }, + "voyage/voyage-4": { + "id": "voyage/voyage-4", + "family": "voyage", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 0 + } + }, + "voyage/voyage-code-2": { + "id": "voyage/voyage-code-2", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-law-2": { + "id": "voyage/voyage-law-2", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-3.5": { + "id": "voyage/voyage-3.5", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "zai/glm-5v-turbo": { + "id": "zai/glm-5v-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "zai/glm-4.7": { + "id": "zai/glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 120000 + } + }, + "zai/glm-5": { + "id": "zai/glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202800, + "output": 131072 + } + }, + "zai/glm-4.7-flashx": { + "id": "zai/glm-4.7-flashx", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "zai/glm-5.1": { + "id": "zai/glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 202752 + } + }, + "zai/glm-4.6v-flash": { + "id": "zai/glm-4.6v-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 24000 + } + }, + "zai/glm-4.5": { + "id": "zai/glm-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "zai/glm-4.5-air": { + "id": "zai/glm-4.5-air", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 96000 + } + }, + "zai/glm-5-turbo": { + "id": "zai/glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202800, + "output": 131100 + } + }, + "zai/glm-4.5v": { + "id": "zai/glm-4.5v", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "zai/glm-4.6": { + "id": "zai/glm-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 96000 + } + }, + "zai/glm-4.6v": { + "id": "zai/glm-4.6v", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 24000 + } + }, + "zai/glm-4.7-flash": { + "id": "zai/glm-4.7-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131000 + } + }, + "cohere/embed-v4.0": { + "id": "cohere/embed-v4.0", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "xai/grok-4.20-non-reasoning": { + "id": "xai/grok-4.20-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-4.20-non-reasoning-beta": { + "id": "xai/grok-4.20-non-reasoning-beta", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-4.20-reasoning": { + "id": "xai/grok-4.20-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-imagine-image": { + "id": "xai/grok-imagine-image", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "xai/grok-4.20-multi-agent-beta": { + "id": "xai/grok-4.20-multi-agent-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-imagine-image-pro": { + "id": "xai/grok-imagine-image-pro", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "xai/grok-4.20-reasoning-beta": { + "id": "xai/grok-4.20-reasoning-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-2-vision": { + "id": "xai/grok-2-vision", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "xai/grok-3-fast": { + "id": "xai/grok-3-fast", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "xai/grok-3-mini-fast": { + "id": "xai/grok-3-mini-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "inception/mercury-coder-small": { + "id": "inception/mercury-coder-small", + "family": "mercury", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 16384 + } + }, + "openai/codex-mini": { + "id": "openai/codex-mini", + "family": "gpt-codex-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 100000, + "output": 100000 + } + }, + "openai/text-embedding-3-large": { + "id": "openai/text-embedding-3-large", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + } + }, + "openai/text-embedding-ada-002": { + "id": "openai/text-embedding-ada-002", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + } + }, + "openai/gpt-5.1-thinking": { + "id": "openai/gpt-5.1-thinking", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/text-embedding-3-small": { + "id": "openai/text-embedding-3-small", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + } + }, + "amazon/titan-embed-text-v2": { + "id": "amazon/titan-embed-text-v2", + "family": "titan-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "amazon/nova-2-lite": { + "id": "amazon/nova-2-lite", + "family": "nova", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "amazon/nova-pro": { + "id": "amazon/nova-pro", + "family": "nova-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "amazon/nova-lite": { + "id": "amazon/nova-lite", + "family": "nova-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "amazon/nova-micro": { + "id": "amazon/nova-micro", + "family": "nova-micro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mistral/mistral-nemo": { + "id": "mistral/mistral-nemo", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 60288, + "output": 16000 + } + }, + "mistral/ministral-14b": { + "id": "mistral/ministral-14b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/codestral-embed": { + "id": "mistral/codestral-embed", + "family": "codestral-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "mistral/mistral-medium": { + "id": "mistral/mistral-medium", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "mistral/mistral-embed": { + "id": "mistral/mistral-embed", + "family": "mistral-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "mistral/devstral-2": { + "id": "mistral/devstral-2", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/mistral-large-3": { + "id": "mistral/mistral-large-3", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/devstral-small-2": { + "id": "mistral/devstral-small-2", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/devstral-small": { + "id": "mistral/devstral-small", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "mistral/ministral-8b": { + "id": "mistral/ministral-8b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/magistral-medium": { + "id": "mistral/magistral-medium", + "family": "magistral-medium", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mistral/mistral-small": { + "id": "mistral/mistral-small", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/magistral-small": { + "id": "mistral/magistral-small", + "family": "magistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/pixtral-12b": { + "id": "mistral/pixtral-12b", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/mixtral-8x22b-instruct": { + "id": "mistral/mixtral-8x22b-instruct", + "family": "mixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 64000 + } + }, + "mistral/pixtral-large": { + "id": "mistral/pixtral-large", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/ministral-3b": { + "id": "mistral/ministral-3b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/codestral": { + "id": "mistral/codestral", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "meta/llama-3.2-1b": { + "id": "meta/llama-3.2-1b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-3.1-8b": { + "id": "meta/llama-3.1-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta/llama-3.2-90b": { + "id": "meta/llama-3.2-90b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-3.2-3b": { + "id": "meta/llama-3.2-3b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-3.2-11b": { + "id": "meta/llama-3.2-11b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-3.1-70b": { + "id": "meta/llama-3.1-70b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta/llama-3.3-70b": { + "id": "meta/llama-3.3-70b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-4-maverick": { + "id": "meta/llama-4-maverick", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-4-scout": { + "id": "meta/llama-4-scout", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "vercel/v0-1.5-md": { + "id": "vercel/v0-1.5-md", + "family": "v0", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "vercel/v0-1.0-md": { + "id": "vercel/v0-1.0-md", + "family": "v0", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "minimax/minimax-m2.1-lightning": { + "id": "minimax/minimax-m2.1-lightning", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "kwaipilot/kat-coder-pro-v1": { + "id": "kwaipilot/kat-coder-pro-v1", + "family": "kat-coder", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "google/gemini-3-pro-image": { + "id": "google/gemini-3-pro-image", + "family": "gemini-pro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 65536, + "output": 32768 + } + }, + "google/imagen-4.0-ultra-generate-001": { + "id": "google/imagen-4.0-ultra-generate-001", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-embedding-001": { + "id": "google/gemini-embedding-001", + "family": "gemini-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "google/text-embedding-005": { + "id": "google/text-embedding-005", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "google/text-multilingual-embedding-002": { + "id": "google/text-multilingual-embedding-002", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "google/imagen-4.0-generate-001": { + "id": "google/imagen-4.0-generate-001", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-embedding-2": { + "id": "google/gemini-embedding-2", + "family": "gemini-embedding", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "google/imagen-4.0-fast-generate-001": { + "id": "google/imagen-4.0-fast-generate-001", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-2.5-flash-image-preview": { + "id": "google/gemini-2.5-flash-image-preview", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "moonshotai/kimi-k2-turbo": { + "id": "moonshotai/kimi-k2-turbo", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "anthropic/claude-3.5-sonnet-20240620": { + "id": "anthropic/claude-3.5-sonnet-20240620", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "bytedance/seed-1.6": { + "id": "bytedance/seed-1.6", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "bytedance/seed-1.8": { + "id": "bytedance/seed-1.8", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "meituan/longcat-flash-thinking": { + "id": "meituan/longcat-flash-thinking", + "family": "longcat", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meituan/longcat-flash-thinking-2601": { + "id": "meituan/longcat-flash-thinking-2601", + "family": "longcat", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "bfl/flux-pro-1.0-fill": { + "id": "bfl/flux-pro-1.0-fill", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-pro-1.1": { + "id": "bfl/flux-pro-1.1", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-kontext-pro": { + "id": "bfl/flux-kontext-pro", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-kontext-max": { + "id": "bfl/flux-kontext-max", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-pro-1.1-ultra": { + "id": "bfl/flux-pro-1.1-ultra", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "gpt-4o-mini-search-preview": { + "id": "gpt-4o-mini-search-preview", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "grok-4-20-beta-0309-non-reasoning": { + "id": "grok-4-20-beta-0309-non-reasoning", "family": "grok", "reasoning": false, "temperature": true, @@ -39481,65 +38649,8 @@ "output": 30000 } }, - "grok-3-fast": { - "id": "grok-3-fast", - "family": "grok", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen-math-plus": { - "id": "qwen-math-plus", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 3072 - } - }, - "deepseek-v3-1": { - "id": "deepseek-v3-1", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "qwen2-5-coder-7b-instruct": { - "id": "qwen2-5-coder-7b-instruct", + "qwen-coder-plus": { + "id": "qwen-coder-plus", "family": "qwen", "reasoning": false, "temperature": true, @@ -39557,66 +38668,9 @@ "output": 8192 } }, - "deepseek-r1-distill-qwen-14b": { - "id": "deepseek-r1-distill-qwen-14b", - "family": "qwen", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 16384 - } - }, - "moonshot-kimi-k2-instruct": { - "id": "moonshot-kimi-k2-instruct", - "family": "kimi", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "qwen-doc-turbo": { - "id": "qwen-doc-turbo", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "tongyi-intent-detect-v3": { - "id": "tongyi-intent-detect-v3", - "family": "yi", + "gemma-3n-e4b-it": { + "id": "gemma-3n-e4b-it", + "family": "gemma", "reasoning": false, "temperature": true, "toolCall": false, @@ -39630,53 +38684,35 @@ }, "limit": { "context": 8192, - "output": 1024 + "output": 2000 } }, - "qwen-plus-character": { - "id": "qwen-plus-character", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 4096 - } - }, - "deepseek-v3-2-exp": { - "id": "deepseek-v3-2-exp", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "deepseek-r1-distill-llama-8b": { - "id": "deepseek-r1-distill-llama-8b", - "family": "deepseek-thinking", + "glm-4.6v-flashx": { + "id": "glm-4.6v-flashx", + "family": "glm", "reasoning": true, "temperature": true, "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "gemma-2-27b-it-together": { + "id": "gemma-2-27b-it-together", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, "modalities": { "input": [ "text" @@ -39686,12 +38722,50 @@ ] }, "limit": { - "context": 32768, + "context": 8192, "output": 16384 } }, - "qwen3.5-flash": { - "id": "qwen3.5-flash", + "codestral-2508": { + "id": "codestral-2508", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "gemma-3-1b-it": { + "id": "gemma-3-1b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 16384 + } + }, + "qwen35-397b-a17b": { + "id": "qwen35-397b-a17b", "family": "qwen", "reasoning": true, "temperature": true, @@ -39699,21 +38773,20 @@ "modalities": { "input": [ "text", - "image", - "video" + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, + "context": 262144, "output": 65536 } }, - "qwen2-5-math-7b-instruct": { - "id": "qwen2-5-math-7b-instruct", - "family": "qwen", + "glm-4-32b-0414-128k": { + "id": "glm-4-32b-0414-128k", + "family": "glm", "reasoning": false, "temperature": true, "toolCall": true, @@ -39726,114 +38799,100 @@ ] }, "limit": { - "context": 4096, - "output": 3072 + "context": 128000, + "output": 16384 } }, - "deepseek-r1-distill-qwen-1-5b": { - "id": "deepseek-r1-distill-qwen-1-5b", - "family": "qwen", + "seed-1-6-flash-250715": { + "id": "seed-1-6-flash-250715", + "family": "seed", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 32768, + "context": 256000, "output": 16384 } }, - "deepseek-r1-distill-qwen-7b": { - "id": "deepseek-r1-distill-qwen-7b", - "family": "qwen", + "seed-1-6-250615": { + "id": "seed-1-6-250615", + "family": "seed", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 32768, + "context": 256000, "output": 16384 } }, - "qwen-deep-research": { - "id": "qwen-deep-research", + "cogview-4": { + "id": "cogview-4", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen2-5-vl-32b-instruct": { + "id": "qwen2-5-vl-32b-instruct", "family": "qwen", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, + "context": 131072, "output": 32768 } }, - "qwen2-5-math-72b-instruct": { - "id": "qwen2-5-math-72b-instruct", + "qwen3-vl-8b-instruct": { + "id": "qwen3-vl-8b-instruct", "family": "qwen", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 3072 - } - }, - "qwen-math-turbo": { - "id": "qwen-math-turbo", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 4096, - "output": 3072 - } - }, - "qwen2-5-coder-32b-instruct": { - "id": "qwen2-5-coder-32b-instruct", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" + "text", + "image" ], "output": [ "text" @@ -39844,238 +38903,89 @@ "output": 8192 } }, - "kimi/kimi-k2.5": { - "id": "kimi/kimi-k2.5", - "family": "kimi", + "claude-3-7-sonnet": { + "id": "claude-3-7-sonnet", + "family": "claude", "reasoning": true, - "temperature": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "grok-4-20-beta-0309-reasoning": { + "id": "grok-4-20-beta-0309-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image", - "video" + "image" ], "output": [ "text" ] }, "limit": { - "context": 262144, - "output": 262144 + "context": 2000000, + "output": 30000 } }, - "siliconflow/deepseek-r1-0528": { - "id": "siliconflow/deepseek-r1-0528", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 32768 - } - }, - "siliconflow/deepseek-v3-0324": { - "id": "siliconflow/deepseek-v3-0324", - "family": "deepseek", + "grok-imagine-image": { + "id": "grok-imagine-image", + "family": "grok", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ - "text" + "text", + "image" ] }, "limit": { - "context": 163840, - "output": 163840 + "context": 2000, + "output": 4096 } }, - "siliconflow/deepseek-v3.1-terminus": { - "id": "siliconflow/deepseek-v3.1-terminus", - "family": "deepseek", + "gemini-pro-latest": { + "id": "gemini-pro-latest", + "family": "gemini", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 163840, + "context": 1048576, "output": 65536 } }, - "siliconflow/deepseek-v3.2": { - "id": "siliconflow/deepseek-v3.2", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "zai-org/glm-4.7-tee": { - "id": "zai-org/GLM-4.7-TEE", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 65535 - } - }, - "zai-org/glm-4.6-tee": { - "id": "zai-org/GLM-4.6-TEE", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 65536 - } - }, - "zai-org/glm-5-tee": { - "id": "zai-org/GLM-5-TEE", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 65535 - } - }, - "zai-org/glm-4.6-fp8": { - "id": "zai-org/GLM-4.6-FP8", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 65535 - } - }, - "zai-org/glm-4.5-tee": { - "id": "zai-org/GLM-4.5-TEE", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "zai-org/glm-5-turbo": { - "id": "zai-org/GLM-5-Turbo", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 202752, - "output": 65535 - } - }, - "nvidia/nvidia-nemotron-3-nano-30b-a3b-bf16": { - "id": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16", - "family": "nemotron", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "nousresearch/hermes-4.3-36b": { - "id": "NousResearch/Hermes-4.3-36B", - "family": "nousresearch", + "mixtral-8x7b-instruct-together": { + "id": "mixtral-8x7b-instruct-together", + "family": "mistral", "reasoning": false, "temperature": true, "toolCall": false, @@ -40089,15 +38999,35 @@ }, "limit": { "context": 32768, - "output": 8192 + "output": 16384 } }, - "nousresearch/deephermes-3-mistral-24b-preview": { - "id": "NousResearch/DeepHermes-3-Mistral-24B-Preview", - "family": "nousresearch", + "seedream-4-0": { + "id": "seedream-4-0", + "family": "seed", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "minimax-text-01": { + "id": "minimax-text-01", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": false, "modalities": { "input": [ "text" @@ -40107,16 +39037,16 @@ ] }, "limit": { - "context": 32768, - "output": 32768 + "context": 1000000, + "output": 131072 } }, - "nousresearch/hermes-4-14b": { - "id": "NousResearch/Hermes-4-14B", - "family": "nousresearch", - "reasoning": true, + "qwen3-32b-fp8": { + "id": "qwen3-32b-fp8", + "family": "qwen", + "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text" @@ -40127,202 +39057,12 @@ }, "limit": { "context": 40960, - "output": 40960 + "output": 20000 } }, - "nousresearch/hermes-4-405b-fp8-tee": { - "id": "NousResearch/Hermes-4-405B-FP8-TEE", - "family": "nousresearch", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "minimaxai/minimax-m2.5-tee": { - "id": "MiniMaxAI/MiniMax-M2.5-TEE", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 65536 - } - }, - "minimaxai/minimax-m2.1-tee": { - "id": "MiniMaxAI/MiniMax-M2.1-TEE", - "family": "minimax", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 196608, - "output": 65536 - } - }, - "deepseek-ai/deepseek-v3.1-terminus-tee": { - "id": "deepseek-ai/DeepSeek-V3.1-Terminus-TEE", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "deepseek-ai/deepseek-v3.2-tee": { - "id": "deepseek-ai/DeepSeek-V3.2-TEE", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 131072, - "output": 65536 - } - }, - "deepseek-ai/deepseek-v3-0324-tee": { - "id": "deepseek-ai/DeepSeek-V3-0324-TEE", - "family": "deepseek", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "deepseek-ai/deepseek-v3.2-speciale-tee": { - "id": "deepseek-ai/DeepSeek-V3.2-Speciale-TEE", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "deepseek-ai/deepseek-r1-tee": { - "id": "deepseek-ai/DeepSeek-R1-TEE", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "deepseek-ai/deepseek-v3.1-tee": { - "id": "deepseek-ai/DeepSeek-V3.1-TEE", - "family": "deepseek", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "deepseek-ai/deepseek-r1-0528-tee": { - "id": "deepseek-ai/DeepSeek-R1-0528-TEE", - "family": "deepseek-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "rednote-hilab/dots.ocr": { - "id": "rednote-hilab/dots.ocr", - "family": "rednote", + "llama-4-scout-17b-instruct": { + "id": "llama-4-scout-17b-instruct", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": false, @@ -40336,13 +39076,51 @@ ] }, "limit": { - "context": 131072, - "output": 131072 + "context": 8192, + "output": 2048 } }, - "unsloth/mistral-nemo-instruct-2407": { - "id": "unsloth/Mistral-Nemo-Instruct-2407", - "family": "unsloth", + "qwen3-4b-fp8": { + "id": "qwen3-4b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 20000 + } + }, + "veo-3.1-generate-preview": { + "id": "veo-3.1-generate-preview", + "family": "gemini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 1 + } + }, + "llama-guard-4-12b": { + "id": "llama-guard-4-12b", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": false, @@ -40356,12 +39134,73 @@ }, "limit": { "context": 131072, - "output": 131072 + "output": 16384 } }, - "unsloth/mistral-small-24b-instruct-2501": { - "id": "unsloth/Mistral-Small-24B-Instruct-2501", - "family": "unsloth", + "gemma-3n-e2b-it": { + "id": "gemma-3n-e2b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2000 + } + }, + "gemini-3.1-flash-image-preview": { + "id": "gemini-3.1-flash-image-preview", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "ministral-8b-2512": { + "id": "ministral-8b-2512", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "gemma-3-27b": { + "id": "gemma-3-27b", + "family": "gemma", "reasoning": false, "temperature": true, "toolCall": true, @@ -40374,13 +39213,627 @@ "text" ] }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "grok-imagine-image-pro": { + "id": "grok-imagine-image-pro", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen3-vl-flash": { + "id": "qwen3-vl-flash", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "llama-3.1-70b-instruct": { + "id": "llama-3.1-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 2048 + } + }, + "seed-1-8-251228": { + "id": "seed-1-8-251228", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "seed-1-6-250915": { + "id": "seed-1-6-250915", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "glm-4.5-x": { + "id": "glm-4.5-x", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "veo-3.1-fast-generate-preview": { + "id": "veo-3.1-fast-generate-preview", + "family": "gemini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 1 + } + }, + "gemma-3-4b-it": { + "id": "gemma-3-4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, "limit": { "context": 32768, + "output": 8192 + } + }, + "qwen-image-max": { + "id": "qwen-image-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "claude-3-5-sonnet": { + "id": "claude-3-5-sonnet", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 16384 + } + }, + "qwen-image-max-2025-12-30": { + "id": "qwen-image-max-2025-12-30", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "ministral-3b-2512": { + "id": "ministral-3b-2512", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "grok-4-20-multi-agent-beta-0309": { + "id": "grok-4-20-multi-agent-beta-0309", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "qwen-plus-latest": { + "id": "qwen-plus-latest", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32000 + } + }, + "seedream-4-5": { + "id": "seedream-4-5", + "family": "seed", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "llama-3.1-nemotron-ultra-253b": { + "id": "llama-3.1-nemotron-ultra-253b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "llama-4-maverick-17b-instruct": { + "id": "llama-4-maverick-17b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "qwen-image-edit-plus": { + "id": "qwen-image-edit-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen3-30b-a3b-fp8": { + "id": "qwen3-30b-a3b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "minimax-m2.1-lightning": { + "id": "minimax-m2.1-lightning", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 131072 + } + }, + "claude-3-haiku": { + "id": "claude-3-haiku", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "glm-image": { + "id": "glm-image", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen-image-edit-max": { + "id": "qwen-image-edit-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "llama-3.2-3b-instruct": { + "id": "llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32000 + } + }, + "qwen-image-plus": { + "id": "qwen-image-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "gpt-4o-search-preview": { + "id": "gpt-4o-search-preview", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "custom": { + "id": "custom", + "family": "auto", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen3-vl-30b-a3b-instruct": { + "id": "qwen3-vl-30b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, "output": 32768 } }, - "unsloth/llama-3.2-1b-instruct": { - "id": "unsloth/Llama-3.2-1B-Instruct", + "qwen3-235b-a22b-fp8": { + "id": "qwen3-235b-a22b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "llama-3-8b-instruct": { + "id": "llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "gemini-2.5-flash-image-preview": { + "id": "gemini-2.5-flash-image-preview", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "qwen25-coder-7b": { + "id": "qwen25-coder-7b", + "family": "qwen", "reasoning": false, "temperature": true, "toolCall": false, @@ -40397,9 +39850,9 @@ "output": 8192 } }, - "unsloth/llama-3.2-3b-instruct": { - "id": "unsloth/Llama-3.2-3B-Instruct", - "family": "unsloth", + "llama-3-70b-instruct": { + "id": "llama-3-70b-instruct", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": false, @@ -40412,13 +39865,71 @@ ] }, "limit": { - "context": 16384, + "context": 8192, + "output": 8000 + } + }, + "glm-4.5-airx": { + "id": "glm-4.5-airx", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, "output": 16384 } }, - "moonshotai/kimi-k2.5-tee": { - "id": "moonshotai/Kimi-K2.5-TEE", - "family": "kimi", + "llama-3.2-11b-instruct": { + "id": "llama-3.2-11b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "claude-3-opus": { + "id": "claude-3-opus", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "gemini-flash-lite-latest": { + "id": "gemini-flash-lite-latest", + "family": "gemini-flash-lite", "reasoning": true, "temperature": true, "toolCall": true, @@ -40426,209 +39937,165 @@ "input": [ "text", "image", - "video" + "audio", + "video", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 262144, - "output": 65535 + "context": 1048576, + "output": 65536 } }, - "moonshotai/kimi-k2-thinking-tee": { - "id": "moonshotai/Kimi-K2-Thinking-TEE", - "family": "kimi-thinking", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65535 - } - }, - "qwen/qwen3.5-397b-a17b-tee": { - "id": "Qwen/Qwen3.5-397B-A17B-TEE", - "family": "qwen", + "gemini-3.1-pro-preview-customtools": { + "id": "gemini-3.1-pro-preview-customtools", + "family": "gemini-pro", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "video", + "audio", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 262144, + "context": 1048576, "output": 65536 } }, - "qwen/qwen3-coder-480b-a35b-instruct-fp8-tee": { - "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8-TEE", - "family": "qwen", + "gemini-embedding-001": { + "id": "gemini-embedding-001", + "family": "gemini", "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 262144 - } - }, - "qwen/qwen3-235b-a22b-instruct-2507-tee": { - "id": "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "qwen/qwen2.5-vl-72b-instruct-tee": { - "id": "Qwen/Qwen2.5-VL-72B-Instruct-TEE", - "family": "qwen", - "reasoning": false, - "temperature": true, + "temperature": false, "toolCall": false, "modalities": { "input": [ - "text", - "image" + "text" ], "output": [ "text" ] }, "limit": { - "context": 32768, + "context": 2048, + "output": 3072 + } + }, + "gemini-flash-latest": { + "id": "gemini-flash-latest", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "zai-org/glm-5-maas": { + "id": "zai-org/glm-5-maas", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "zai-org/glm-4.7-maas": { + "id": "zai-org/glm-4.7-maas", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "deepseek-ai/deepseek-v3.2-maas": { + "id": "deepseek-ai/deepseek-v3.2-maas", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.1-maas": { + "id": "deepseek-ai/deepseek-v3.1-maas", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, "output": 32768 } }, - "qwen/qwen3guard-gen-0.6b": { - "id": "Qwen/Qwen3Guard-Gen-0.6B", - "family": "qwen", - "reasoning": false, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 32768, - "output": 8192 - } - }, - "tngtech/deepseek-r1t-chimera": { - "id": "tngtech/DeepSeek-R1T-Chimera", - "family": "tngtech", - "reasoning": true, - "temperature": true, - "toolCall": false, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 163840 - } - }, - "tngtech/tng-r1t-chimera-turbo": { - "id": "tngtech/TNG-R1T-Chimera-Turbo", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "tngtech/tng-r1t-chimera-tee": { - "id": "tngtech/TNG-R1T-Chimera-TEE", - "family": "tngtech", - "reasoning": true, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 163840, - "output": 65536 - } - }, - "mistralai/devstral-2-123b-instruct-2512-tee": { - "id": "mistralai/Devstral-2-123B-Instruct-2512-TEE", - "reasoning": false, - "temperature": true, - "toolCall": true, - "modalities": { - "input": [ - "text" - ], - "output": [ - "text" - ] - }, - "limit": { - "context": 262144, - "output": 65536 - } - }, - "openai/gpt-oss-120b-tee": { - "id": "openai/gpt-oss-120b-TEE", + "openai/gpt-oss-120b-maas": { + "id": "openai/gpt-oss-120b-maas", "family": "gpt-oss", "reasoning": true, "temperature": true, @@ -40643,12 +40110,432 @@ }, "limit": { "context": 131072, - "output": 65536 + "output": 32768 } }, - "chutesai/mistral-small-3.1-24b-instruct-2503": { - "id": "chutesai/Mistral-Small-3.1-24B-Instruct-2503", - "family": "chutesai", + "openai/gpt-oss-20b-maas": { + "id": "openai/gpt-oss-20b-maas", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "meta/llama-3.3-70b-instruct-maas": { + "id": "meta/llama-3.3-70b-instruct-maas", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-4-maverick-17b-128e-instruct-maas": { + "id": "meta/llama-4-maverick-17b-128e-instruct-maas", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 524288, + "output": 8192 + } + }, + "qwen/qwen3-235b-a22b-instruct-2507-maas": { + "id": "qwen/qwen3-235b-a22b-instruct-2507-maas", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "moonshotai/kimi-k2-thinking-maas": { + "id": "moonshotai/kimi-k2-thinking-maas", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "@cf/zai-org/glm-4.7-flash": { + "id": "@cf/zai-org/glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "@cf/nvidia/nemotron-3-120b-a12b": { + "id": "@cf/nvidia/nemotron-3-120b-a12b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "@cf/openai/gpt-oss-20b": { + "id": "@cf/openai/gpt-oss-20b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/openai/gpt-oss-120b": { + "id": "@cf/openai/gpt-oss-120b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-4-scout-17b-16e-instruct": { + "id": "@cf/meta/llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/google/gemma-4-26b-a4b-it": { + "id": "@cf/google/gemma-4-26b-a4b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "@cf/moonshotai/kimi-k2.5": { + "id": "@cf/moonshotai/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral-saba-24b": { + "id": "mistral-saba-24b", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "llama-guard-3-8b": { + "id": "llama-guard-3-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "allam-2-7b": { + "id": "allam-2-7b", + "family": "allam", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "llama3-70b-8192": { + "id": "llama3-70b-8192", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "qwen-qwq-32b": { + "id": "qwen-qwq-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "whisper-large-v3-turbo": { + "id": "whisper-large-v3-turbo", + "family": "whisper", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 448, + "output": 448 + } + }, + "llama3-8b-8192": { + "id": "llama3-8b-8192", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "canopylabs/orpheus-arabic-saudi": { + "id": "canopylabs/orpheus-arabic-saudi", + "family": "canopylabs", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 4000, + "output": 50000 + } + }, + "canopylabs/orpheus-v1-english": { + "id": "canopylabs/orpheus-v1-english", + "family": "canopylabs", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 4000, + "output": 50000 + } + }, + "meta-llama/llama-prompt-guard-2-22m": { + "id": "meta-llama/llama-prompt-guard-2-22m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 512 + } + }, + "meta-llama/llama-4-maverick-17b-128e-instruct": { + "id": "meta-llama/llama-4-maverick-17b-128e-instruct", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": true, @@ -40663,12 +40550,1734 @@ }, "limit": { "context": 131072, + "output": 8192 + } + }, + "meta-llama/llama-prompt-guard-2-86m": { + "id": "meta-llama/llama-prompt-guard-2-86m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 512 + } + }, + "groq/compound": { + "id": "groq/compound", + "family": "groq", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "groq/compound-mini": { + "id": "groq/compound-mini", + "family": "groq", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "gpt-5.3-chat": { + "id": "gpt-5.3-chat", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "grok-4-20-non-reasoning": { + "id": "grok-4-20-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 8192 + } + }, + "grok-4-20-reasoning": { + "id": "grok-4-20-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 8192 + } + }, + "qwen/qwen3-vl-embedding-8b": { + "id": "Qwen/Qwen3-VL-Embedding-8B", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "qwen/qwen3-vl-235b-a22b-instruct-fp8": { + "id": "Qwen/Qwen3-VL-235B-A22B-Instruct-FP8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 218000, + "output": 8192 + } + }, + "neuralmagic/meta-llama-3.1-8b-instruct-fp8": { + "id": "neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "neuralmagic/mistral-nemo-instruct-2407-fp8": { + "id": "neuralmagic/Mistral-Nemo-Instruct-2407-FP8", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "cortecs/llama-3.3-70b-instruct-fp8-dynamic": { + "id": "cortecs/Llama-3.3-70B-Instruct-FP8-Dynamic", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "hunyuan-turbos": { + "id": "hunyuan-turbos", + "family": "hunyuan", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "hunyuan-t1": { + "id": "hunyuan-t1", + "family": "hunyuan", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "hunyuan-2.0-instruct": { + "id": "hunyuan-2.0-instruct", + "family": "hunyuan", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "tc-code-latest": { + "id": "tc-code-latest", + "family": "auto", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "hunyuan-2.0-thinking": { + "id": "hunyuan-2.0-thinking", + "family": "hunyuan", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "qwen3-embedding-4b": { + "id": "qwen3-embedding-4b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 2560 + } + }, + "qwen3-coder-30b-a3b": { + "id": "qwen3-coder-30b-a3b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "gemini-live-2.5-flash-preview-native-audio": { + "id": "gemini-live-2.5-flash-preview-native-audio", + "family": "gemini-flash", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "gemini-1.5-flash": { + "id": "gemini-1.5-flash", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192 + } + }, + "gemini-1.5-pro": { + "id": "gemini-1.5-pro", + "family": "gemini-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192 + } + }, + "gemini-2.5-flash-preview-tts": { + "id": "gemini-2.5-flash-preview-tts", + "family": "gemini-flash", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 8000, + "output": 16000 + } + }, + "gemma-4-31b-it": { + "id": "gemma-4-31b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "gemini-2.5-pro-preview-tts": { + "id": "gemini-2.5-pro-preview-tts", + "family": "gemini-flash", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 8000, + "output": 16000 + } + }, + "gemma-4-26b-it": { + "id": "gemma-4-26b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "gemini-1.5-flash-8b": { + "id": "gemini-1.5-flash-8b", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192 + } + }, + "gemini-live-2.5-flash": { + "id": "gemini-live-2.5-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 8000 + } + }, + "public/deepseek-r1": { + "id": "public/deepseek-r1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "public/minimax-m25": { + "id": "public/minimax-m25", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, "output": 131072 } }, - "opengvlab/internvl3-78b-tee": { - "id": "OpenGVLab/InternVL3-78B-TEE", - "family": "opengvlab", + "public/deepseek-v3": { + "id": "public/deepseek-v3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "baai/bge-reranker-v2-m3": { + "id": "BAAI/bge-reranker-v2-m3", + "family": "bge", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 512 + } + }, + "intfloat/multilingual-e5-large": { + "id": "intfloat/multilingual-e5-large", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + } + }, + "ai21-labs/ai21-jamba-1.5-mini": { + "id": "ai21-labs/ai21-jamba-1.5-mini", + "family": "jamba", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "ai21-labs/ai21-jamba-1.5-large": { + "id": "ai21-labs/ai21-jamba-1.5-large", + "family": "jamba", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "microsoft/phi-3.5-mini-instruct": { + "id": "microsoft/phi-3.5-mini-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-3-mini-128k-instruct": { + "id": "microsoft/phi-3-mini-128k-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-4-reasoning": { + "id": "microsoft/phi-4-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-3-mini-4k-instruct": { + "id": "microsoft/phi-3-mini-4k-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + } + }, + "microsoft/phi-4-mini-reasoning": { + "id": "microsoft/phi-4-mini-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/mai-ds-r1": { + "id": "microsoft/mai-ds-r1", + "family": "mai", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "cohere/cohere-command-r-08-2024": { + "id": "cohere/cohere-command-r-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-a": { + "id": "cohere/cohere-command-a", + "family": "command-a", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-r-plus": { + "id": "cohere/cohere-command-r-plus", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-r": { + "id": "cohere/cohere-command-r", + "family": "command-r", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-r-plus-08-2024": { + "id": "cohere/cohere-command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "openai/o1-mini": { + "id": "openai/o1-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536 + } + }, + "meta/meta-llama-3.1-8b-instruct": { + "id": "meta/meta-llama-3.1-8b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta/meta-llama-3-70b-instruct": { + "id": "meta/meta-llama-3-70b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "meta/llama-3.2-90b-vision-instruct": { + "id": "meta/llama-3.2-90b-vision-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/meta-llama-3.1-405b-instruct": { + "id": "meta/meta-llama-3.1-405b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta/meta-llama-3.1-70b-instruct": { + "id": "meta/meta-llama-3.1-70b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta/meta-llama-3-8b-instruct": { + "id": "meta/meta-llama-3-8b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "meta/llama-4-maverick-17b-128e-instruct-fp8": { + "id": "meta/llama-4-maverick-17b-128e-instruct-fp8", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "core42/jais-30b-chat": { + "id": "core42/jais-30b-chat", + "family": "jais", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "mistral-ai/mistral-nemo": { + "id": "mistral-ai/mistral-nemo", + "family": "mistral-nemo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mistral-ai/ministral-3b": { + "id": "mistral-ai/ministral-3b", + "family": "ministral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mistral-ai/mistral-large-2411": { + "id": "mistral-ai/mistral-large-2411", + "family": "mistral-large", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "mistral-ai/mistral-small-2503": { + "id": "mistral-ai/mistral-small-2503", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "mistral-ai/mistral-medium-2505": { + "id": "mistral-ai/mistral-medium-2505", + "family": "mistral-medium", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "mistral-ai/codestral-2501": { + "id": "mistral-ai/codestral-2501", + "family": "codestral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "qwen/qwen3-coder-next-fp8": { + "id": "Qwen/Qwen3-Coder-Next-FP8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3-235b-a22b-instruct-2507-tput": { + "id": "Qwen/Qwen3-235B-A22B-Instruct-2507-tput", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "deepseek-ai/deepseek-v3-1": { + "id": "deepseek-ai/DeepSeek-V3-1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "claude-3-sonnet-20240229": { + "id": "claude-3-sonnet-20240229", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "claude-3-opus-20240229": { + "id": "claude-3-opus-20240229", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "claude-opus-4-0": { + "id": "claude-opus-4-0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-3-5-haiku-latest": { + "id": "claude-3-5-haiku-latest", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "claude-sonnet-4-0": { + "id": "claude-sonnet-4-0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "zhipuai/glm-4.5": { + "id": "ZhipuAI/GLM-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "zhipuai/glm-4.6": { + "id": "ZhipuAI/GLM-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 98304 + } + }, + "duo-chat-gpt-5-4-nano": { + "id": "duo-chat-gpt-5-4-nano", + "family": "gpt-nano", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-mini": { + "id": "duo-chat-gpt-5-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-sonnet-4-6": { + "id": "duo-chat-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "duo-chat-gpt-5-2": { + "id": "duo-chat-gpt-5-2", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-codex": { + "id": "duo-chat-gpt-5-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-1": { + "id": "duo-chat-gpt-5-1", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-2-codex": { + "id": "duo-chat-gpt-5-2-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-sonnet-4-5": { + "id": "duo-chat-sonnet-4-5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "duo-chat-gpt-5-4": { + "id": "duo-chat-gpt-5-4", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + } + }, + "duo-chat-haiku-4-5": { + "id": "duo-chat-haiku-4-5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "duo-chat-gpt-5-3-codex": { + "id": "duo-chat-gpt-5-3-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-4-mini": { + "id": "duo-chat-gpt-5-4-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-opus-4-5": { + "id": "duo-chat-opus-4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "duo-chat-opus-4-6": { + "id": "duo-chat-opus-4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "arcee_ai/afm/models/trinity-mini": { + "id": "arcee_ai/AFM/models/trinity-mini", + "family": "trinity-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/completion/models/ministral-3-14b-reasoning-2512": { + "id": "mistralai/completion/models/Ministral-3-14B-Reasoning-2512", + "family": "ministral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "mistralai/completion/models/ministral-3-3b-reasoning-2512": { + "id": "mistralai/completion/models/Ministral-3-3B-Reasoning-2512", + "family": "ministral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "deepseek-ai/deepseek-ocr/models/deepseek-ocr": { + "id": "deepseek-ai/deepseek-ocr/models/DeepSeek-OCR", + "family": "deepseek", "reasoning": false, "temperature": true, "toolCall": false, @@ -40681,9 +42290,188 @@ "text" ] }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "openai/chat-completion/models/gpt-oss-20b": { + "id": "openai/chat-completion/models/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "openai/chat-completion/models/gpt-oss-120b-high-throughput": { + "id": "openai/chat-completion/models/gpt-oss-120b-high-throughput", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "minimaxai/chat-completion/models/minimax-m2_5-high-throughput": { + "id": "minimaxai/chat-completion/models/MiniMax-M2_5-high-throughput", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "qwen/qwencoder/models/qwen3-coder-30b-a3b-instruct": { + "id": "qwen/qwenCoder/models/Qwen3-Coder-30B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwenlm/models/qwen3-30b-a3b-thinking-2507": { + "id": "qwen/qwenLM/models/Qwen3-30B-A3B-Thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "qwen/qwenlm/models/qwen3-30b-a3b-instruct-2507": { + "id": "qwen/qwenLM/models/Qwen3-30B-A3B-Instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "clarifai/main/models/mm-poly-8b": { + "id": "clarifai/main/models/mm-poly-8b", + "family": "mm-poly", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, "limit": { "context": 32768, - "output": 32768 + "output": 4096 + } + }, + "nova-2-lite-v1": { + "id": "nova-2-lite-v1", + "family": "nova-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "nova-2-pro-v1": { + "id": "nova-2-pro-v1", + "family": "nova-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 } } } diff --git a/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts b/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts index 4c1ef6330..28dd23415 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts @@ -84,7 +84,7 @@ describe("executeCompact lock management", () => { let pluginConfig: ReturnType const sessionID = "test-session-123" const directory = "/test/dir" - const msg = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const msg = { providerID: "anthropic", modelID: "claude-opus-4-7" } beforeEach(() => { // given: Fresh state for each test @@ -132,7 +132,7 @@ describe("executeCompact lock management", () => { expect(mockClient.session.summarize).toHaveBeenCalledWith( expect.objectContaining({ path: { id: sessionID }, - body: { providerID: "anthropic", modelID: "claude-opus-4-6", auto: true }, + body: { providerID: "anthropic", modelID: "claude-opus-4-7", auto: true }, }), ) @@ -157,7 +157,7 @@ describe("executeCompact lock management", () => { expect(mockClient.session.summarize).toHaveBeenCalledWith( expect.objectContaining({ path: { id: sessionID }, - body: { providerID: "anthropic", modelID: "claude-opus-4-6", auto: true }, + body: { providerID: "anthropic", modelID: "claude-opus-4-7", auto: true }, }), ) @@ -352,7 +352,7 @@ describe("executeCompact lock management", () => { expect(mockClient.session.summarize).toHaveBeenCalledWith( expect.objectContaining({ path: { id: sessionID }, - body: { providerID: "anthropic", modelID: "claude-opus-4-6", auto: true }, + body: { providerID: "anthropic", modelID: "claude-opus-4-7", auto: true }, }), ) diff --git a/src/hooks/anthropic-effort/index.test.ts b/src/hooks/anthropic-effort/index.test.ts index eb164bc9b..129b6513e 100644 --- a/src/hooks/anthropic-effort/index.test.ts +++ b/src/hooks/anthropic-effort/index.test.ts @@ -29,7 +29,7 @@ function createMockParams(overrides: { existingOptions?: Record }): { input: ChatParamsInput; output: ChatParamsOutput } { const providerID = overrides.providerID ?? "anthropic" - const modelID = overrides.modelID ?? "claude-opus-4-6" + const modelID = overrides.modelID ?? "claude-opus-4-7" const variant = "variant" in overrides ? overrides.variant : "max" const agentName = overrides.agentName ?? "sisyphus" const existingOptions = overrides.existingOptions ?? {} @@ -71,7 +71,7 @@ describe("createAnthropicEffortHook", () => { it("injects effort max for dotted opus ids", async () => { const hook = createAnthropicEffortHook() - const { input, output } = createMockParams({ modelID: "claude-opus-4.6" }) + const { input, output } = createMockParams({ modelID: "claude-opus-4.7" }) await hook["chat.params"](input, output) @@ -158,7 +158,7 @@ describe("createAnthropicEffortHook", () => { const hook = createAnthropicEffortHook() const { input, output } = createMockParams({ providerID: "github-copilot", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) // when @@ -256,7 +256,7 @@ describe("createAnthropicEffortHook", () => { // given an Anthropic OAuth session and variant=max on an Opus model writeAuthFile({ anthropic: { type: "oauth" } }) const hook = createAnthropicEffortHook() - const { input, output } = createMockParams({ modelID: "claude-opus-4-6" }) + const { input, output } = createMockParams({ modelID: "claude-opus-4-7" }) // when chat.params fires await hook["chat.params"](input, output) @@ -270,7 +270,7 @@ describe("createAnthropicEffortHook", () => { // given an Anthropic OAuth session and a dotted opus id writeAuthFile({ anthropic: { type: "oauth" } }) const hook = createAnthropicEffortHook() - const { input, output } = createMockParams({ modelID: "claude-opus-4.6" }) + const { input, output } = createMockParams({ modelID: "claude-opus-4.7" }) // when chat.params fires await hook["chat.params"](input, output) @@ -284,7 +284,7 @@ describe("createAnthropicEffortHook", () => { // given an Anthropic API-key session (not OAuth) writeAuthFile({ anthropic: { type: "api", key: "sk-ant-xxx" } }) const hook = createAnthropicEffortHook() - const { input, output } = createMockParams({ modelID: "claude-opus-4-6" }) + const { input, output } = createMockParams({ modelID: "claude-opus-4-7" }) // when chat.params fires await hook["chat.params"](input, output) @@ -298,7 +298,7 @@ describe("createAnthropicEffortHook", () => { // given OAuth entries for unrelated providers only writeAuthFile({ "github-copilot": { type: "oauth" }, opencode: { type: "api", key: "sk-x" } }) const hook = createAnthropicEffortHook() - const { input, output } = createMockParams({ modelID: "claude-opus-4-6", providerID: "anthropic" }) + const { input, output } = createMockParams({ modelID: "claude-opus-4-7", providerID: "anthropic" }) // when chat.params fires for the anthropic provider await hook["chat.params"](input, output) diff --git a/src/hooks/atlas/compaction-agent-filter.test.ts b/src/hooks/atlas/compaction-agent-filter.test.ts index 790518e6c..b5a120f96 100644 --- a/src/hooks/atlas/compaction-agent-filter.test.ts +++ b/src/hooks/atlas/compaction-agent-filter.test.ts @@ -58,7 +58,7 @@ describe("atlas hook compaction agent filtering", () => { join(messageDir, fileName), JSON.stringify({ agent, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }), ) } diff --git a/src/hooks/atlas/final-wave-approval-gate-regression.test.ts b/src/hooks/atlas/final-wave-approval-gate-regression.test.ts index 180ab7cef..d0ce73c67 100644 --- a/src/hooks/atlas/final-wave-approval-gate-regression.test.ts +++ b/src/hooks/atlas/final-wave-approval-gate-regression.test.ts @@ -91,7 +91,7 @@ describe("Atlas final-wave approval gate regressions", () => { join(messageDirectory, "msg_test001.json"), JSON.stringify({ agent: "atlas", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }), ) } diff --git a/src/hooks/atlas/final-wave-approval-gate.test.ts b/src/hooks/atlas/final-wave-approval-gate.test.ts index 717f66016..608a53235 100644 --- a/src/hooks/atlas/final-wave-approval-gate.test.ts +++ b/src/hooks/atlas/final-wave-approval-gate.test.ts @@ -99,7 +99,7 @@ describe("Atlas final verification approval gate", () => { join(messageDirectory, "msg_test001.json"), JSON.stringify({ agent: "atlas", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }), ) } diff --git a/src/hooks/atlas/index.test.ts b/src/hooks/atlas/index.test.ts index 20fb02fc1..a2e80cf78 100644 --- a/src/hooks/atlas/index.test.ts +++ b/src/hooks/atlas/index.test.ts @@ -79,7 +79,7 @@ describe("atlas hook", () => { } const messageData = { agent, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } writeFileSync(join(messageDir, "msg_test001.json"), JSON.stringify(messageData)) } diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index 637503356..14b3ff6bb 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -24,7 +24,7 @@ const selectFallbackProviderMock = mock((providers: string[], preferredProviderI const transformModelForProviderMock = mock((provider: string, model: string) => { if (provider === "github-copilot") { return model - .replace("claude-opus-4-6", "claude-opus-4.6") + .replace("claude-opus-4-7", "claude-opus-4.7") .replace("claude-sonnet-4-6", "claude-sonnet-4.6") .replace("claude-sonnet-4-5", "claude-sonnet-4.5") .replace("claude-haiku-4-5", "claude-haiku-4.5") @@ -96,13 +96,13 @@ describe("model fallback hook", () => { "ses_model_fallback_main", "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) expect(set).toBe(true) const output = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], @@ -117,7 +117,7 @@ describe("model fallback hook", () => { //#then expect(output.message["model"]).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) }) @@ -132,12 +132,12 @@ describe("model fallback hook", () => { const sessionID = "ses_model_fallback_main" expect( - setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6-thinking"), + setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7-thinking"), ).toBe(true) const firstOutput = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], @@ -149,17 +149,17 @@ describe("model fallback hook", () => { //#then expect(firstOutput.message["model"]).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) //#when - second error re-arms fallback and should advance to next entry expect( - setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6"), + setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7"), ).toBe(true) const secondOutput = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, parts: [{ type: "text", text: "continue" }], } @@ -183,13 +183,13 @@ describe("model fallback hook", () => { sessionID, "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) const secondSet = setPendingModelFallback( sessionID, "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) //#then @@ -211,7 +211,7 @@ describe("model fallback hook", () => { } setSessionFallbackChain(sessionID, [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, { providers: ["opencode"], model: "kimi-k2.5-free" }, ]) @@ -220,13 +220,13 @@ describe("model fallback hook", () => { sessionID, "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6", + "claude-opus-4-7", ), ).toBe(true) const output = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, parts: [{ type: "text", text: "continue" }], } @@ -255,7 +255,7 @@ describe("model fallback hook", () => { } setSessionFallbackChain(sessionID, [ - { providers: ["quotio"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["quotio"], model: "claude-opus-4-7", variant: "max" }, { providers: ["quotio"], model: "gpt-5.2" }, ]) @@ -264,13 +264,13 @@ describe("model fallback hook", () => { sessionID, "Sisyphus - Ultraworker", "quotio", - "claude-opus-4-6", + "claude-opus-4-7", ), ).toBe(true) const output = { message: { - model: { providerID: "quotio", modelID: "claude-opus-4-6" }, + model: { providerID: "quotio", modelID: "claude-opus-4-7" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], @@ -369,13 +369,13 @@ describe("model fallback hook", () => { "ses_model_fallback_toast", "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) expect(set).toBe(true) const output = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], diff --git a/src/hooks/no-hephaestus-non-gpt/index.test.ts b/src/hooks/no-hephaestus-non-gpt/index.test.ts index 7686bdbf1..6ca505f3c 100644 --- a/src/hooks/no-hephaestus-non-gpt/index.test.ts +++ b/src/hooks/no-hephaestus-non-gpt/index.test.ts @@ -30,12 +30,12 @@ describe("no-hephaestus-non-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_1", agent: HEPHAESTUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output1) await hook["chat.message"]?.({ sessionID: "ses_1", agent: HEPHAESTUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output2) // then - toast is shown and agent is switched to sisyphus @@ -66,7 +66,7 @@ describe("no-hephaestus-non-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_opt_out", agent: HEPHAESTUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - warning toast is shown but agent is not switched @@ -114,7 +114,7 @@ describe("no-hephaestus-non-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_3", agent: SISYPHUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - no toast @@ -136,7 +136,7 @@ describe("no-hephaestus-non-gpt hook", () => { // when - chat.message runs without input.agent await hook["chat.message"]?.({ sessionID: "ses_4", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - toast shown via session-agent fallback, switched to sisyphus diff --git a/src/hooks/no-sisyphus-gpt/index.test.ts b/src/hooks/no-sisyphus-gpt/index.test.ts index 908a01351..baeb23722 100644 --- a/src/hooks/no-sisyphus-gpt/index.test.ts +++ b/src/hooks/no-sisyphus-gpt/index.test.ts @@ -83,7 +83,7 @@ describe("no-sisyphus-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_2", agent: SISYPHUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - no toast diff --git a/src/hooks/runtime-fallback/dispose.test.ts b/src/hooks/runtime-fallback/dispose.test.ts index a5cb46ef7..e49cb0904 100644 --- a/src/hooks/runtime-fallback/dispose.test.ts +++ b/src/hooks/runtime-fallback/dispose.test.ts @@ -125,10 +125,10 @@ describe("createRuntimeFallbackHook dispose", () => { const fallbackTimeout = setTimeout(() => {}, 60_000) capturedDeps?.sessionStates.set("session-1", { - originalModel: "anthropic/claude-opus-4-6", + originalModel: "anthropic/claude-opus-4-7", currentModel: "openai/gpt-5.4", fallbackIndex: 1, - failedModels: new Map([["anthropic/claude-opus-4-6", 1]]), + failedModels: new Map([["anthropic/claude-opus-4-7", 1]]), attemptCount: 1, }) capturedDeps?.sessionLastAccess.set("session-1", Date.now()) diff --git a/src/hooks/runtime-fallback/error-classifier.test.ts b/src/hooks/runtime-fallback/error-classifier.test.ts index 958babe5f..c9eef6e06 100644 --- a/src/hooks/runtime-fallback/error-classifier.test.ts +++ b/src/hooks/runtime-fallback/error-classifier.test.ts @@ -7,7 +7,7 @@ describe("runtime-fallback error classifier", () => { //#given const info = { status: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", } //#when @@ -21,7 +21,7 @@ describe("runtime-fallback error classifier", () => { //#given const info = { status: - "All credentials for model claude-opus-4-6 are cooldown [retrying in 7m 56s attempt #1]", + "All credentials for model claude-opus-4-7 are cooldown [retrying in 7m 56s attempt #1]", } //#when @@ -49,7 +49,7 @@ describe("runtime-fallback error classifier", () => { //#given const error = { message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", } //#when @@ -65,8 +65,8 @@ describe("runtime-fallback error classifier", () => { name: "ProviderModelNotFoundError", data: { providerID: "anthropic", - modelID: "claude-opus-4-6", - message: "Model not found: anthropic/claude-opus-4-6.", + modelID: "claude-opus-4-7", + message: "Model not found: anthropic/claude-opus-4-7.", }, } diff --git a/src/hooks/runtime-fallback/fallback-models.test.ts b/src/hooks/runtime-fallback/fallback-models.test.ts index 7cf3f8e32..ebfa8fbc9 100644 --- a/src/hooks/runtime-fallback/fallback-models.test.ts +++ b/src/hooks/runtime-fallback/fallback-models.test.ts @@ -15,7 +15,7 @@ describe("runtime-fallback fallback-models", () => { const pluginConfig = { categories: { quick: { - fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-6"], + fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"], }, }, } as any @@ -24,7 +24,7 @@ describe("runtime-fallback fallback-models", () => { const result = getFallbackModelsForSession(sessionID, undefined, pluginConfig) //#then - expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-6"]) + expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-7"]) }) test("uses agent-specific fallback_models when agent is resolved", () => { @@ -32,7 +32,7 @@ describe("runtime-fallback fallback-models", () => { const pluginConfig = { agents: { oracle: { - fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-6"], + fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"], }, }, } as any @@ -41,7 +41,7 @@ describe("runtime-fallback fallback-models", () => { const result = getFallbackModelsForSession("ses_runtime_fallback_agent", "oracle", pluginConfig) //#then - expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-6"]) + expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-7"]) }) test("does not fall back to another agent chain when agent cannot be resolved", () => { @@ -52,7 +52,7 @@ describe("runtime-fallback fallback-models", () => { fallback_models: ["quotio/gpt-5.2", "quotio/glm-5", "quotio/kimi-k2.5"], }, oracle: { - fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-6"], + fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"], }, }, } as any diff --git a/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts b/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts index 912100011..c008649bd 100644 --- a/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts +++ b/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts @@ -51,7 +51,7 @@ describe("createRuntimeFallbackHook dispose retry-key cleanup", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -63,7 +63,7 @@ describe("createRuntimeFallbackHook dispose retry-key cleanup", () => { status: { type: "retry", attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", }, }, }, @@ -77,7 +77,7 @@ describe("createRuntimeFallbackHook dispose retry-key cleanup", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) await hook.event(retryEvent) diff --git a/src/hooks/runtime-fallback/index.test.ts b/src/hooks/runtime-fallback/index.test.ts index 8c9ad6aa4..76e29c2d3 100644 --- a/src/hooks/runtime-fallback/index.test.ts +++ b/src/hooks/runtime-fallback/index.test.ts @@ -329,7 +329,7 @@ describe("runtime-fallback", () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "anthropic/claude-opus-4.6", + "anthropic/claude-opus-4.7", "openai/gpt-5.4", ]), }) @@ -365,14 +365,14 @@ describe("runtime-fallback", () => { type: "session.error", properties: { sessionID, - error: { name: "UnknownError", data: { message: "Model not found: anthropic/claude-opus-4.6." } }, + error: { name: "UnknownError", data: { message: "Model not found: anthropic/claude-opus-4.7." } }, }, }, }) const fallbackLogs = logCalls.filter((c) => c.msg.includes("Preparing fallback")) expect(fallbackLogs.length).toBeGreaterThanOrEqual(2) - expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.6", to: "openai/gpt-5.4" }) + expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.7", to: "openai/gpt-5.4" }) const nonRetryLog = logCalls.find( (c) => c.msg.includes("Error not retryable") && (c.data as { sessionID?: string } | undefined)?.sessionID === sessionID @@ -384,7 +384,7 @@ describe("runtime-fallback", () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "anthropic/claude-opus-4.6", + "anthropic/claude-opus-4.7", "openai/gpt-5.4", ]), }) @@ -421,8 +421,8 @@ describe("runtime-fallback", () => { name: "ProviderModelNotFoundError", data: { providerID: "anthropic", - modelID: "claude-opus-4.6", - message: "Model not found: anthropic/claude-opus-4.6.", + modelID: "claude-opus-4.7", + message: "Model not found: anthropic/claude-opus-4.7.", }, }, }, @@ -431,7 +431,7 @@ describe("runtime-fallback", () => { const fallbackLogs = logCalls.filter((c) => c.msg.includes("Preparing fallback")) expect(fallbackLogs.length).toBeGreaterThanOrEqual(2) - expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.6", to: "openai/gpt-5.4" }) + expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.7", to: "openai/gpt-5.4" }) }) test("should bootstrap session.error fallback from session category model and preserve variant", async () => { @@ -500,7 +500,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "github-copilot/claude-opus-4.6" } }, + properties: { info: { id: sessionID, model: "github-copilot/claude-opus-4.7" } }, }, }) @@ -511,7 +511,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", status: "Too Many Requests: quota exceeded [retrying in ~2 weeks attempt #1]", }, @@ -524,13 +524,13 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "github-copilot/claude-opus-4.6", to: "openai/gpt-5.4" }) + expect(fallbackLog?.data).toMatchObject({ from: "github-copilot/claude-opus-4.7", to: "openai/gpt-5.4" }) }) test("should trigger fallback on OpenAI auto-retry signal in message.updated", async () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), - pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-6"]), + pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-7"]), }) const sessionID = "test-session-openai-auto-retry" @@ -562,7 +562,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "openai/gpt-5.3-codex", to: "anthropic/claude-opus-4-6" }) + expect(fallbackLog?.data).toMatchObject({ from: "openai/gpt-5.3-codex", to: "anthropic/claude-opus-4-7" }) }) test("should trigger fallback on auto-retry signal in assistant text parts", async () => { @@ -577,7 +577,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -588,7 +588,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "quotio/claude-opus-4-6", + model: "quotio/claude-opus-4-7", }, parts: [ { @@ -605,7 +605,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" }) + expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-7", to: "openai/gpt-5.2" }) }) test("should trigger fallback when auto-retry text parts are nested under info.parts", async () => { @@ -620,7 +620,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -631,7 +631,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "quotio/claude-opus-4-6", + model: "quotio/claude-opus-4-7", parts: [ { type: "text", @@ -648,7 +648,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" }) + expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-7", to: "openai/gpt-5.2" }) }) test("should trigger fallback on session.status auto-retry signal", async () => { @@ -682,7 +682,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -695,7 +695,7 @@ describe("runtime-fallback", () => { type: "retry", next: 476, attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", }, }, }, @@ -706,7 +706,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" }) + expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-7", to: "openai/gpt-5.2" }) expect(promptCalls.length).toBe(1) }) @@ -741,7 +741,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -754,7 +754,7 @@ describe("runtime-fallback", () => { type: "retry", next: 476, attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", }, }, }, @@ -769,7 +769,7 @@ describe("runtime-fallback", () => { type: "retry", next: 475, attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 55s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 55s attempt #1]", }, }, }, @@ -781,7 +781,7 @@ describe("runtime-fallback", () => { test("should NOT trigger fallback on auto-retry signal when timeout_seconds is 0", async () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 0 }), - pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-6"]), + pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-7"]), }) const sessionID = "test-session-auto-retry-timeout-disabled" @@ -1161,8 +1161,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), } @@ -1212,7 +1212,7 @@ describe("runtime-fallback", () => { "Google Generative AI API key is missing. Pass it using the 'apiKey' parameter or the GOOGLE_GENERATIVE_AI_API_KEY environment variable.", }, }, - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", }, }, }, @@ -1251,8 +1251,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), } @@ -1294,7 +1294,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", status: "Too Many Requests: quota exceeded [retrying in ~2 weeks attempt #1]", }, @@ -1303,8 +1303,8 @@ describe("runtime-fallback", () => { }) expect(retriedModels.length).toBeGreaterThanOrEqual(2) - expect(retriedModels[0]).toBe("github-copilot/claude-opus-4.6") - expect(retriedModels[1]).toBe("anthropic/claude-opus-4-6") + expect(retriedModels[0]).toBe("github-copilot/claude-opus-4.7") + expect(retriedModels[1]).toBe("anthropic/claude-opus-4-7") void sessionErrorPromise }) @@ -1335,8 +1335,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1372,8 +1372,8 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 50)) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") expect(abortCalls.some((call) => call.path?.id === sessionID)).toBe(true) const timeoutLog = logCalls.find((c) => c.msg.includes("Session fallback timeout reached")) @@ -1401,8 +1401,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1443,15 +1443,15 @@ describe("runtime-fallback", () => { await hook["chat.message"]?.( { sessionID, - model: { providerID: "github-copilot", modelID: "claude-opus-4.6" }, + model: { providerID: "github-copilot", modelID: "claude-opus-4.7" }, }, output ) await new Promise((resolve) => setTimeout(resolve, 50)) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") }) test("should abort in-flight fallback request before advancing on timeout", async () => { @@ -1486,8 +1486,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1524,8 +1524,8 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 50)) expect(abortCalls.some((call) => call.path?.id === sessionID)).toBe(true) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") void sessionErrorPromise }) @@ -1551,8 +1551,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1586,7 +1586,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") await hook.event({ event: { @@ -1624,9 +1624,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1659,7 +1659,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -1695,7 +1695,7 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 50)) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) }) test("should not clear fallback timeout on assistant non-error update with Copilot retry signal", async () => { @@ -1719,9 +1719,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1754,7 +1754,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -1796,7 +1796,7 @@ describe("runtime-fallback", () => { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1846,7 +1846,7 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 60)) - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") }) test("should not clear fallback timeout on assistant non-error update without user-visible content", async () => { @@ -1870,9 +1870,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1905,7 +1905,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -1914,7 +1914,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", }, }, }, @@ -1946,9 +1946,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1981,7 +1981,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -2022,9 +2022,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -2057,7 +2057,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -2145,7 +2145,7 @@ describe("runtime-fallback", () => { }), { config: createMockConfig({ notify_on_fallback: false }), - pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-6"]), + pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-7"]), } ) @@ -2176,7 +2176,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") }) test("does NOT trigger fallback for normal type:error-free messages", async () => { @@ -2452,7 +2452,7 @@ describe("runtime-fallback", () => { }), { config: createMockConfig({ notify_on_fallback: false }), - pluginConfig: createMockPluginConfigWithAgentFallback("prometheus", ["github-copilot/claude-opus-4.6"]), + pluginConfig: createMockPluginConfigWithAgentFallback("prometheus", ["github-copilot/claude-opus-4.7"]), }, ) const sessionID = "test-preserve-agent-on-retry" @@ -2462,7 +2462,7 @@ describe("runtime-fallback", () => { type: "session.error", properties: { sessionID, - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", error: { statusCode: 503, message: "Service unavailable" }, agent: "prometheus", }, @@ -2472,7 +2472,7 @@ describe("runtime-fallback", () => { expect(promptCalls.length).toBe(1) const callBody = promptCalls[0]?.body as Record expect(callBody?.agent).toBe("prometheus") - expect(callBody?.model).toEqual({ providerID: "github-copilot", modelID: "claude-opus-4.6" }) + expect(callBody?.model).toEqual({ providerID: "github-copilot", modelID: "claude-opus-4.7" }) }) }) diff --git a/src/hooks/runtime-fallback/provider-matrix.test.ts b/src/hooks/runtime-fallback/provider-matrix.test.ts index d94986e78..727b2967d 100644 --- a/src/hooks/runtime-fallback/provider-matrix.test.ts +++ b/src/hooks/runtime-fallback/provider-matrix.test.ts @@ -92,7 +92,7 @@ describe("runtime-fallback provider matrix quota tests", () => { //#given const error = { name: "AI_APICallError", - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in ~2 weeks]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in ~2 weeks]", provider: "anthropic", } diff --git a/src/hooks/runtime-fallback/session-status-handler.test.ts b/src/hooks/runtime-fallback/session-status-handler.test.ts index 42316a6ec..6a7dee7cf 100644 --- a/src/hooks/runtime-fallback/session-status-handler.test.ts +++ b/src/hooks/runtime-fallback/session-status-handler.test.ts @@ -74,12 +74,12 @@ describe("createSessionStatusHandler", () => { const deps = createDeps() const abortCalls: string[] = [] const retryCalls: Array<{ sessionID: string; model: string; source: string }> = [] - const state = createFallbackState("anthropic/claude-opus-4-6") + const state = createFallbackState("anthropic/claude-opus-4-7") state.currentModel = "openai/gpt-5.4" state.fallbackIndex = 0 state.attemptCount = 1 state.pendingFallbackModel = "openai/gpt-5.4" - state.failedModels.set("anthropic/claude-opus-4-6", Date.now()) + state.failedModels.set("anthropic/claude-opus-4-7", Date.now()) deps.sessionStates.set(sessionID, state) const handler = createSessionStatusHandler(deps, createHelpers(abortCalls, retryCalls), deps.sessionStatusRetryKeys) diff --git a/src/hooks/think-mode/index.test.ts b/src/hooks/think-mode/index.test.ts index 34c1ba55c..f85763608 100644 --- a/src/hooks/think-mode/index.test.ts +++ b/src/hooks/think-mode/index.test.ts @@ -49,7 +49,7 @@ describe("createThinkModeHook", () => { const input = createHookInput({ sessionID, providerID: "github-copilot", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) const output = createHookOutput("Please think deeply about this") diff --git a/src/hooks/think-mode/switcher.test.ts b/src/hooks/think-mode/switcher.test.ts index bbe01bed6..94b5f115c 100644 --- a/src/hooks/think-mode/switcher.test.ts +++ b/src/hooks/think-mode/switcher.test.ts @@ -23,26 +23,26 @@ describe("think-mode switcher", () => { describe("getHighVariant with dots vs hyphens", () => { it("should handle dots in Claude version numbers", () => { // given a Claude model ID with dot format - const variant = getHighVariant("claude-opus-4.6") + const variant = getHighVariant("claude-opus-4.7") // then should return high variant with hyphen format - expect(variant).toBe("claude-opus-4-6-high") + expect(variant).toBe("claude-opus-4-7-high") }) it("should handle hyphens in Claude version numbers", () => { // given a Claude model ID with hyphen format - const variant = getHighVariant("claude-opus-4-6") + const variant = getHighVariant("claude-opus-4-7") // then should return high variant - expect(variant).toBe("claude-opus-4-6-high") + expect(variant).toBe("claude-opus-4-7-high") }) - it("should handle claude-opus-4-6 high variant", () => { + it("should handle claude-opus-4-7 high variant", () => { // given a Claude Opus 4.6 model ID - const variant = getHighVariant("claude-opus-4-6") + const variant = getHighVariant("claude-opus-4-7") // then should return high variant - expect(variant).toBe("claude-opus-4-6-high") + expect(variant).toBe("claude-opus-4-7-high") }) it("should handle dots in GPT version numbers", () => { @@ -73,7 +73,7 @@ describe("think-mode switcher", () => { it("should return null for already-high variants", () => { // given model IDs that are already high variants - expect(getHighVariant("claude-opus-4-6-high")).toBeNull() + expect(getHighVariant("claude-opus-4-7-high")).toBeNull() expect(getHighVariant("gpt-5-4-high")).toBeNull() expect(getHighVariant("gemini-3-1-pro-high")).toBeNull() }) @@ -89,7 +89,7 @@ describe("think-mode switcher", () => { describe("isAlreadyHighVariant", () => { it("should detect -high suffix", () => { // given model IDs with -high suffix - expect(isAlreadyHighVariant("claude-opus-4-6-high")).toBe(true) + expect(isAlreadyHighVariant("claude-opus-4-7-high")).toBe(true) expect(isAlreadyHighVariant("gpt-5-4-high")).toBe(true) expect(isAlreadyHighVariant("gemini-3.1-pro-high")).toBe(true) }) @@ -101,8 +101,8 @@ describe("think-mode switcher", () => { it("should return false for base models", () => { // given base model IDs without -high suffix - expect(isAlreadyHighVariant("claude-opus-4-6")).toBe(false) - expect(isAlreadyHighVariant("claude-opus-4.6")).toBe(false) + expect(isAlreadyHighVariant("claude-opus-4-7")).toBe(false) + expect(isAlreadyHighVariant("claude-opus-4.7")).toBe(false) expect(isAlreadyHighVariant("gpt-5.4")).toBe(false) expect(isAlreadyHighVariant("gemini-3.1-pro")).toBe(false) }) @@ -133,10 +133,10 @@ describe("think-mode switcher", () => { it("should handle prefixes with dots in version numbers", () => { // given a model ID with prefix and dots - const variant = getHighVariant("vertex_ai/claude-opus-4.6") + const variant = getHighVariant("vertex_ai/claude-opus-4.7") // then should normalize dots and preserve prefix - expect(variant).toBe("vertex_ai/claude-opus-4-6-high") + expect(variant).toBe("vertex_ai/claude-opus-4-7-high") }) it("should handle multiple different prefixes", () => { @@ -167,7 +167,7 @@ describe("think-mode switcher", () => { it("should return null for already-high prefixed models", () => { // given prefixed model IDs that are already high - expect(getHighVariant("vertex_ai/claude-opus-4-6-high")).toBeNull() + expect(getHighVariant("vertex_ai/claude-opus-4-7-high")).toBeNull() expect(getHighVariant("openai/gpt-5-4-high")).toBeNull() }) }) @@ -175,14 +175,14 @@ describe("think-mode switcher", () => { describe("isAlreadyHighVariant with prefixes", () => { it("should detect -high suffix in prefixed models", () => { // given prefixed model IDs with -high suffix - expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-6-high")).toBe(true) + expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-7-high")).toBe(true) expect(isAlreadyHighVariant("openai/gpt-5-4-high")).toBe(true) expect(isAlreadyHighVariant("custom/gemini-3.1-pro-high")).toBe(true) }) it("should return false for prefixed base models", () => { // given prefixed base model IDs without -high suffix - expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-6")).toBe(false) + expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-7")).toBe(false) expect(isAlreadyHighVariant("openai/gpt-5-4")).toBe(false) }) diff --git a/src/hooks/think-mode/switcher.ts b/src/hooks/think-mode/switcher.ts index 66aa39f5a..8be017d69 100644 --- a/src/hooks/think-mode/switcher.ts +++ b/src/hooks/think-mode/switcher.ts @@ -45,7 +45,7 @@ function extractModelPrefix(modelID: string): { prefix: string; base: string } { const HIGH_VARIANT_MAP: Record = { // Claude "claude-sonnet-4-6": "claude-sonnet-4-6-high", - "claude-opus-4-6": "claude-opus-4-6-high", + "claude-opus-4-7": "claude-opus-4-7-high", // Gemini "gemini-3-1-pro": "gemini-3-1-pro-high", "gemini-3-1-pro-low": "gemini-3-1-pro-high", diff --git a/src/index.compaction-model-agnostic.static.test.ts b/src/index.compaction-model-agnostic.static.test.ts index ccba44101..6dfacb6f3 100644 --- a/src/index.compaction-model-agnostic.static.test.ts +++ b/src/index.compaction-model-agnostic.static.test.ts @@ -13,7 +13,7 @@ describe("experimental.session.compacting", () => { //#then expect(hookIndex).toBeGreaterThanOrEqual(0) - expect(content.includes('modelID: "claude-opus-4-6"')).toBe(false) + expect(content.includes('modelID: "claude-opus-4-7"')).toBe(false) expect(hookSlice.includes("output.context.push")).toBe(true) expect(hookSlice.includes("providerID:")).toBe(false) expect(hookSlice.includes("modelID:")).toBe(false) diff --git a/src/plugin-handlers/agent-config-handler-agents-skills.test.ts b/src/plugin-handlers/agent-config-handler-agents-skills.test.ts index 593f22d9e..4bb94ce41 100644 --- a/src/plugin-handlers/agent-config-handler-agents-skills.test.ts +++ b/src/plugin-handlers/agent-config-handler-agents-skills.test.ts @@ -81,7 +81,7 @@ describe("applyAgentConfig .agents skills", () => { // when await applyAgentConfig({ - config: { model: "anthropic/claude-opus-4-6", agent: {} }, + config: { model: "anthropic/claude-opus-4-7", agent: {} }, pluginConfig: createPluginConfig(), ctx: { directory }, pluginComponents: createPluginComponents(), @@ -111,7 +111,7 @@ describe("applyAgentConfig .agents skills", () => { // when await applyAgentConfig({ - config: { model: "anthropic/claude-opus-4-6", agent: {} }, + config: { model: "anthropic/claude-opus-4-7", agent: {} }, pluginConfig: createPluginConfig(), ctx: { directory: "/tmp/project" }, pluginComponents: createPluginComponents(), diff --git a/src/plugin-handlers/agent-config-handler.test.ts b/src/plugin-handlers/agent-config-handler.test.ts index 8e2571e34..afca8f62b 100644 --- a/src/plugin-handlers/agent-config-handler.test.ts +++ b/src/plugin-handlers/agent-config-handler.test.ts @@ -31,7 +31,7 @@ function createPluginComponents(): PluginComponents { function createBaseConfig(): Record { return { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } } diff --git a/src/plugin-handlers/config-handler.test.ts b/src/plugin-handlers/config-handler.test.ts index 668d21a32..629f97796 100644 --- a/src/plugin-handlers/config-handler.test.ts +++ b/src/plugin-handlers/config-handler.test.ts @@ -88,7 +88,7 @@ beforeEach(async () => { spyOn(mcpModule, "createBuiltinMcps" as any).mockReturnValue({}) spyOn(shared, "log" as any).mockImplementation(() => {}) - spyOn(shared, "fetchAvailableModels" as any).mockResolvedValue(new Set(["anthropic/claude-opus-4-6"])) + spyOn(shared, "fetchAvailableModels" as any).mockResolvedValue(new Set(["anthropic/claude-opus-4-7"])) spyOn(shared, "readConnectedProvidersCache" as any).mockReturnValue(null) spyOn(configDir, "getOpenCodeConfigPaths" as any).mockReturnValue({ @@ -98,7 +98,7 @@ beforeEach(async () => { spyOn(permissionCompat, "migrateAgentConfig" as any).mockImplementation((config: Record) => config) - spyOn(modelResolver, "resolveModelWithFallback" as any).mockReturnValue({ model: "anthropic/claude-opus-4-6" }) + spyOn(modelResolver, "resolveModelWithFallback" as any).mockReturnValue({ model: "anthropic/claude-opus-4-7" }) ;({ createConfigHandler } = await importFreshConfigHandlerModule()) }) @@ -204,7 +204,7 @@ describe("MCP env allowlist initialization", () => { mcp_env_allowlist: ["CUSTOM_API_KEY", "CUSTOM_AUTH_TOKEN"], }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -246,7 +246,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -292,7 +292,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -336,7 +336,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -385,7 +385,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: { plan: { name: "plan", @@ -422,7 +422,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: { plan: { name: "plan", @@ -459,7 +459,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -495,7 +495,7 @@ describe("Agent permission defaults", () => { }) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -523,7 +523,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " hephaestus ", agent: {}, } @@ -547,7 +547,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: "HePhAeStUs", agent: {}, } @@ -571,7 +571,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // #given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: "hephaestus", agent: {}, } @@ -596,7 +596,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { const pluginConfig = createPluginConfig({}) const displayName = getAgentListDisplayName("hephaestus") const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: displayName, agent: {}, } @@ -620,7 +620,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // #given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -643,7 +643,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: "hephaestus", agent: {}, } @@ -667,7 +667,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " ", agent: {}, } @@ -691,7 +691,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " Custom Agent ", agent: {}, } @@ -719,7 +719,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " HePhAeStUs ", agent: {}, } @@ -861,7 +861,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -902,7 +902,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -944,7 +944,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -980,7 +980,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1007,9 +1007,9 @@ describe("Prometheus direct override priority over category", () => { describe("Plan agent model inheritance from prometheus", () => { test("plan agent inherits all model-related settings from resolved prometheus config", async () => { - //#given - prometheus resolves to claude-opus-4-6 with model settings + //#given - prometheus resolves to claude-opus-4-7 with model settings spyOn(prometheusAgentConfigBuilder, "buildPrometheusAgentConfig").mockResolvedValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", mode: "primary", prompt: "prometheus prompt", @@ -1021,7 +1021,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: { plan: { name: "plan", @@ -1047,7 +1047,7 @@ describe("Plan agent model inheritance from prometheus", () => { const agents = config.agent as Record expect(agents.plan).toBeDefined() expect(agents.plan.mode).toBe("subagent") - expect(agents.plan.model).toBe("anthropic/claude-opus-4-6") + expect(agents.plan.model).toBe("anthropic/claude-opus-4-7") expect(agents.plan.variant).toBe("max") expect(agents.plan.prompt).toBeUndefined() }) @@ -1078,7 +1078,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1110,7 +1110,7 @@ describe("Plan agent model inheritance from prometheus", () => { test("plan agent user override takes priority over prometheus inherited settings", async () => { //#given - prometheus resolves to opus, but user has plan override for gpt-5.4 spyOn(shared, "resolveModelPipeline" as any).mockReturnValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", provenance: "provider-fallback", variant: "max", }) @@ -1128,7 +1128,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1153,7 +1153,7 @@ describe("Plan agent model inheritance from prometheus", () => { test("plan agent does NOT inherit prompt, description, or color from prometheus", async () => { //#given spyOn(shared, "resolveModelPipeline" as any).mockReturnValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", provenance: "provider-fallback", variant: "max", }) @@ -1164,7 +1164,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1181,7 +1181,7 @@ describe("Plan agent model inheritance from prometheus", () => { //#then - plan has model settings but NOT prompt/description/color const agents = config.agent as Record> - expect(agents.plan.model).toBe("anthropic/claude-opus-4-6") + expect(agents.plan.model).toBe("anthropic/claude-opus-4-7") expect(agents.plan.prompt).toBeUndefined() expect(agents.plan.description).toBeUndefined() expect(agents.plan.color).toBeUndefined() @@ -1200,7 +1200,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", ( }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const mockClient = { @@ -1233,7 +1233,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash")) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1263,7 +1263,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { experimental: { plugin_load_timeout_ms: 100 }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1289,7 +1289,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash")) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1326,7 +1326,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { }) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1370,7 +1370,7 @@ describe("command agent routing coherence", () => { }) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1420,7 +1420,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { experimental: { task_system: true }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1458,7 +1458,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { experimental: { task_system: false }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1497,7 +1497,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1538,7 +1538,7 @@ describe("disable_omo_env pass-through", () => { experimental: { disable_omo_env: true }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1575,7 +1575,7 @@ describe("disable_omo_env pass-through", () => { const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1621,7 +1621,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1661,7 +1661,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1701,7 +1701,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1749,7 +1749,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ diff --git a/src/plugin-handlers/plan-model-inheritance.test.ts b/src/plugin-handlers/plan-model-inheritance.test.ts index c36948856..5df73a9f8 100644 --- a/src/plugin-handlers/plan-model-inheritance.test.ts +++ b/src/plugin-handlers/plan-model-inheritance.test.ts @@ -18,7 +18,7 @@ describe("buildPlanDemoteConfig", () => { //#given const prometheusConfig = { name: "prometheus", - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", mode: "primary", prompt: "You are Prometheus...", @@ -39,7 +39,7 @@ describe("buildPlanDemoteConfig", () => { //#then - picks model settings, NOT prompt/permission/description/color/name/mode expect(result.mode).toBe("subagent") - expect(result.model).toBe("anthropic/claude-opus-4-6") + expect(result.model).toBe("anthropic/claude-opus-4-7") expect(result.variant).toBe("max") expect(result.temperature).toBe(0.1) expect(result.top_p).toBe(0.95) @@ -58,7 +58,7 @@ describe("buildPlanDemoteConfig", () => { test("plan override takes priority over prometheus for all model settings", () => { //#given const prometheusConfig = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", temperature: 0.1, reasoningEffort: "high", @@ -83,7 +83,7 @@ describe("buildPlanDemoteConfig", () => { test("falls back to prometheus when plan override has partial settings", () => { //#given const prometheusConfig = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", temperature: 0.1, reasoningEffort: "high", @@ -105,14 +105,14 @@ describe("buildPlanDemoteConfig", () => { test("skips undefined values from both sources", () => { //#given const prometheusConfig = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", } //#when const result = buildPlanDemoteConfig(prometheusConfig, undefined) //#then - expect(result).toEqual({ mode: "subagent", hidden: true, model: "anthropic/claude-opus-4-6" }) + expect(result).toEqual({ mode: "subagent", hidden: true, model: "anthropic/claude-opus-4-7" }) expect(Object.keys(result)).toEqual(["mode", "hidden", "model"]) }) }) diff --git a/src/plugin-handlers/prometheus-agent-config-builder.test.ts b/src/plugin-handlers/prometheus-agent-config-builder.test.ts index be19047f4..8c77f562d 100644 --- a/src/plugin-handlers/prometheus-agent-config-builder.test.ts +++ b/src/plugin-handlers/prometheus-agent-config-builder.test.ts @@ -24,7 +24,7 @@ describe("buildPrometheusAgentConfig", () => { (category) => ({ model: `${category}/default-model` } as CategoryConfig) ); resolveModelPipelineSpy = spyOn(shared, "resolveModelPipeline").mockReturnValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", provenance: "provider-fallback", }); ;({ buildPrometheusAgentConfig } = await importFreshPrometheusAgentConfigBuilderModule()) @@ -42,7 +42,7 @@ describe("buildPrometheusAgentConfig", () => { describe("#when currentModel is NOT in Prometheus fallback chain", () => { test("falls through to fallback chain instead of using currentModel as override", async () => { // given - currentModel is a model NOT in Prometheus fallback chain - // Prometheus chain: claude-opus-4-6, gpt-5.4, glm-5, gemini-3.1-pro + // Prometheus chain: claude-opus-4-7, gpt-5.4, glm-5, gemini-3.1-pro const currentModel = "some-provider/gpt-5.3-codex"; // when @@ -65,14 +65,14 @@ describe("buildPrometheusAgentConfig", () => { systemDefaultModel: undefined, }), }); - expect(result.model).toBe("anthropic/claude-opus-4-6"); + expect(result.model).toBe("anthropic/claude-opus-4-7"); }); }); describe("#when currentModel IS in Prometheus fallback chain", () => { - test("preserves currentModel as uiSelectedModel for claude-opus-4-6", async () => { + test("preserves currentModel as uiSelectedModel for claude-opus-4-7", async () => { // given - currentModel matches a Prometheus fallback chain entry - const currentModel = "anthropic/claude-opus-4-6"; + const currentModel = "anthropic/claude-opus-4-7"; // when - should not throw and should produce a valid config const result = await buildPrometheusAgentConfig({ @@ -128,7 +128,7 @@ describe("buildPrometheusAgentConfig", () => { describe("#given explicit Prometheus model configured via plugin override", () => { test("explicit config wins over currentModel and fallback chain", async () => { // given - const currentModel = "anthropic/claude-opus-4-6"; + const currentModel = "anthropic/claude-opus-4-7"; const explicitModel = "custom-provider/custom-model"; // when @@ -163,7 +163,7 @@ describe("buildPrometheusAgentConfig", () => { describe("#given category with model configured", () => { test("category model wins when no explicit override", async () => { // given - const currentModel = "anthropic/claude-opus-4-6"; + const currentModel = "anthropic/claude-opus-4-7"; const categoryModel = "category-provider/category-model"; resolveCategoryConfigSpy.mockReturnValue({ @@ -264,7 +264,7 @@ describe("buildPrometheusAgentConfig", () => { }, }) ); - expect(result.model).toBe("anthropic/claude-opus-4-6"); + expect(result.model).toBe("anthropic/claude-opus-4-7"); }); }); diff --git a/src/plugin/chat-message.test.ts b/src/plugin/chat-message.test.ts index 6ecac08bb..e2e813cd8 100644 --- a/src/plugin/chat-message.test.ts +++ b/src/plugin/chat-message.test.ts @@ -709,7 +709,7 @@ describe("createChatMessageHandler - TUI variant passthrough", () => { shouldOverride: false, pluginConfig: { agents: { - sisyphus: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, }, }, }) @@ -733,7 +733,7 @@ describe("createChatMessageHandler - TUI variant passthrough", () => { shouldOverride: false, pluginConfig: { agents: { - prometheus: { model: "anthropic/claude-opus-4-6" }, + prometheus: { model: "anthropic/claude-opus-4-7" }, }, }, }) @@ -753,7 +753,7 @@ describe("createChatMessageHandler - TUI variant passthrough", () => { test("respects a mid-conversation model switch instead of reusing the previous stored model", async () => { //#given setMainSession("test-session") - setSessionModel("test-session", { providerID: "anthropic", modelID: "claude-opus-4-6" }) + setSessionModel("test-session", { providerID: "anthropic", modelID: "claude-opus-4-7" }) const args = createMockHandlerArgs({ shouldOverride: false }) const handler = createChatMessageHandler(args) const nextModel = { providerID: "openai", modelID: "gpt-5.4" } diff --git a/src/plugin/chat-params.test.ts b/src/plugin/chat-params.test.ts index f75c1a243..5886b7204 100644 --- a/src/plugin/chat-params.test.ts +++ b/src/plugin/chat-params.test.ts @@ -48,7 +48,7 @@ describe("createChatParamsHandler", () => { const input = { sessionID: "ses_chat_params", agent: { name: "sisyphus" }, - model: { providerID: "opencode", modelID: "claude-opus-4-6" }, + model: { providerID: "opencode", modelID: "claude-opus-4-7" }, provider: { id: "opencode" }, message: {}, } diff --git a/src/plugin/event-compaction-agent.test.ts b/src/plugin/event-compaction-agent.test.ts index b247b649e..b5888d7fe 100644 --- a/src/plugin/event-compaction-agent.test.ts +++ b/src/plugin/event-compaction-agent.test.ts @@ -73,7 +73,7 @@ describe("createEventHandler compaction agent filtering", () => { role: "user", agent: "compaction", time: { created: Date.now() }, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, }, }, diff --git a/src/plugin/event.model-fallback.test.ts b/src/plugin/event.model-fallback.test.ts index 481c5c419..3e82817ff 100644 --- a/src/plugin/event.model-fallback.test.ts +++ b/src/plugin/event.model-fallback.test.ts @@ -85,12 +85,12 @@ describe("createEventHandler - model fallback", () => { name: "APIError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", isRetryable: true, }, }, parentID: "msg_user_1", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", mode: "Sisyphus - Ultraworker", agent: "Sisyphus - Ultraworker", @@ -125,7 +125,7 @@ describe("createEventHandler - model fallback", () => { data: { error: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", }, }, }, @@ -182,7 +182,7 @@ describe("createEventHandler - model fallback", () => { role: "user", time: { created: 1 }, content: [], - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, @@ -201,7 +201,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", next: 1234, }, }, @@ -213,7 +213,7 @@ describe("createEventHandler - model fallback", () => { { sessionID, agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, }, output, ) @@ -244,7 +244,7 @@ describe("createEventHandler - model fallback", () => { id: "msg_user_status_dedup", sessionID, role: "user", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", }, @@ -262,7 +262,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", next: 300, }, }, @@ -277,7 +277,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~4 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~4 days attempt #1]", next: 299, }, }, @@ -312,7 +312,7 @@ describe("createEventHandler - model fallback", () => { id: "msg_user_status_runtime_enabled", sessionID, role: "user", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", providerID: "quotio", agent: "Sisyphus - Ultraworker", }, @@ -330,7 +330,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", next: 476, }, }, @@ -393,7 +393,7 @@ describe("createEventHandler - model fallback", () => { role: "user", time: { created: 1 }, content: [], - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", providerID: "quotio", agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, @@ -412,7 +412,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", next: 300, }, }, @@ -424,7 +424,7 @@ describe("createEventHandler - model fallback", () => { { sessionID, agent: "sisyphus", - model: { providerID: "quotio", modelID: "claude-opus-4-6" }, + model: { providerID: "quotio", modelID: "claude-opus-4-7" }, }, output, ) @@ -520,13 +520,13 @@ describe("createEventHandler - model fallback", () => { properties: { sessionID, providerID: "anthropic", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", error: { name: "UnknownError", data: { error: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", }, }, }, @@ -539,7 +539,7 @@ describe("createEventHandler - model fallback", () => { { sessionID, agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, }, output, ) @@ -549,7 +549,7 @@ describe("createEventHandler - model fallback", () => { //#when - first retry cycle const first = await triggerRetryCycle() - //#then - first fallback entry applied (no-op skip: claude-opus-4-6 matches current model after normalization) + //#then - first fallback entry applied (no-op skip: claude-opus-4-7 matches current model after normalization) expect(first.message["model"]).toMatchObject({ providerID: "opencode-go", modelID: "kimi-k2.5", @@ -590,12 +590,12 @@ describe("createEventHandler - model fallback", () => { name: "APIError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", isRetryable: true, }, }, parentID: "msg_user_disabled_1", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, @@ -617,7 +617,7 @@ describe("createEventHandler - model fallback", () => { data: { error: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", }, }, }, diff --git a/src/plugin/event.test.ts b/src/plugin/event.test.ts index 85223806c..cb87efff4 100644 --- a/src/plugin/event.test.ts +++ b/src/plugin/event.test.ts @@ -826,7 +826,7 @@ describe("createEventHandler - retry dedupe lifecycle", () => { const retryStatus = { type: "retry", attempt: 1, - message: "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in 7m 56s attempt #1]", next: 476, } as const @@ -838,7 +838,7 @@ describe("createEventHandler - retry dedupe lifecycle", () => { id: "msg_user_retry_rearm", sessionID, role: "user", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", }, @@ -862,7 +862,7 @@ describe("createEventHandler - retry dedupe lifecycle", () => { { sessionID, agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, }, firstOutput, ) diff --git a/src/plugin/event.ts b/src/plugin/event.ts index 34bc730e1..6d70d7951 100644 --- a/src/plugin/event.ts +++ b/src/plugin/event.ts @@ -515,7 +515,7 @@ export function createEventHandler(args: { sessionID, info?.providerID as string | undefined, ); - const rawModel = (info?.modelID as string | undefined) ?? "claude-opus-4-6"; + const rawModel = (info?.modelID as string | undefined) ?? "claude-opus-4-7"; const currentModel = normalizeFallbackModelID(rawModel); applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); @@ -578,7 +578,7 @@ export function createEventHandler(args: { const parsed = extractProviderModelFromErrorMessage(retryMessage); const lastKnown = lastKnownModelBySession.get(sessionID); const currentProvider = resolveFallbackProviderID(sessionID, parsed.providerID); - let currentModel = parsed.modelID ?? lastKnown?.modelID ?? "claude-opus-4-6"; + let currentModel = parsed.modelID ?? lastKnown?.modelID ?? "claude-opus-4-7"; currentModel = normalizeFallbackModelID(currentModel); applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); @@ -664,7 +664,7 @@ export function createEventHandler(args: { sessionID, (props?.providerID as string | undefined) || parsed.providerID, ); - let currentModel = (props?.modelID as string) || parsed.modelID || "claude-opus-4-6"; + let currentModel = (props?.modelID as string) || parsed.modelID || "claude-opus-4-7"; currentModel = normalizeFallbackModelID(currentModel); applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); diff --git a/src/plugin/fallback.cliproxyapi-matrix.test.ts b/src/plugin/fallback.cliproxyapi-matrix.test.ts index 30535a880..d5e810745 100644 --- a/src/plugin/fallback.cliproxyapi-matrix.test.ts +++ b/src/plugin/fallback.cliproxyapi-matrix.test.ts @@ -59,7 +59,7 @@ function createChatMessageHandlerHooks( const PRIMARY_MODEL = { providerID: PROVIDER_ID, - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", } const PRIMARY_MODEL_STRING = `${PRIMARY_MODEL.providerID}/${PRIMARY_MODEL.modelID}` @@ -313,7 +313,7 @@ async function triggerSessionStatusRetry( type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", next: 476, }, }, diff --git a/src/plugin/ultrawork-db-model-override.test.ts b/src/plugin/ultrawork-db-model-override.test.ts index ea5646d26..84c7ffed0 100644 --- a/src/plugin/ultrawork-db-model-override.test.ts +++ b/src/plugin/ultrawork-db-model-override.test.ts @@ -112,13 +112,13 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_001", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) //#then const model = readMessageModel("msg_001") - expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }) test("should update variant and thinking fields when variant provided", async () => { @@ -128,7 +128,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_002", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) await flushMicrotasks(5) @@ -144,7 +144,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_nonexistent", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushWithTimeout() @@ -162,13 +162,13 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_003", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) //#then const model = readMessageModel("msg_003") - expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) expect(readMessageField("msg_003", "variant")).toBeNull() expect(readMessageField("msg_003", "thinking")).toBeNull() }) @@ -180,7 +180,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_004", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) @@ -200,7 +200,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_corrupt", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) diff --git a/src/plugin/ultrawork-model-override.test.ts b/src/plugin/ultrawork-model-override.test.ts index feaf369c1..b37dc1285 100644 --- a/src/plugin/ultrawork-model-override.test.ts +++ b/src/plugin/ultrawork-model-override.test.ts @@ -79,19 +79,19 @@ describe("resolveUltraworkOverride", () => { test("should resolve override when ultrawork keyword detected", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something") //#when const result = resolveUltraworkOverride(config, "sisyphus", output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }) }) test("should return null when no keyword detected", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("just do something normal") //#when @@ -103,7 +103,7 @@ describe("resolveUltraworkOverride", () => { test("should return null when agent name is undefined", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something") //#when @@ -115,14 +115,14 @@ describe("resolveUltraworkOverride", () => { test("should use message.agent when input agent is undefined", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something", "sisyphus") //#when const result = resolveUltraworkOverride(config, undefined, output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: undefined }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: undefined }) }) test("should return null when agents config is missing", () => { @@ -189,19 +189,19 @@ describe("resolveUltraworkOverride", () => { test("should resolve display name to config key", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ulw do something") //#when const result = resolveUltraworkOverride(config, "Sisyphus - Ultraworker", output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }) }) test("should handle multiple text parts by joining them", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = { message: {} as Record, parts: [ @@ -215,12 +215,12 @@ describe("resolveUltraworkOverride", () => { const result = resolveUltraworkOverride(config, "sisyphus", output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: undefined }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: undefined }) }) test("should use session agent when input and message agents are undefined", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something") const getSessionAgentSpy = spyOn(sessionStateModule, "getSessionAgent") getSessionAgentSpy.mockReturnValue("sisyphus") @@ -230,7 +230,7 @@ describe("resolveUltraworkOverride", () => { //#then expect(getSessionAgentSpy).toHaveBeenCalledWith("ses_test") - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }) getSessionAgentSpy.mockRestore() }) @@ -287,7 +287,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should schedule deferred DB override without variant when SDK unavailable", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) const tui = createMockTui() @@ -297,7 +297,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then - variant should NOT be applied without SDK validation expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) }) @@ -305,7 +305,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should NOT override variant when SDK unavailable even if config specifies variant", () => { //#given const config = createConfig("sisyphus", { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "extended", }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) @@ -319,7 +319,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then - existing variant preserved, not overridden to "extended" expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) expect(output.message["variant"]).toBe("max") @@ -329,7 +329,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should NOT mutate output.message.model when message ID present", () => { //#given const sonnetModel = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something", { existingModel: sonnetModel, messageId: "msg_123", @@ -345,7 +345,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should fall back to direct model mutation without variant when no message ID and no SDK", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something") const tui = createMockTui() @@ -353,7 +353,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui) //#then - model is set but variant is NOT applied without SDK validation - expect(output.message.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(output.message.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) expect(output.message["variant"]).toBeUndefined() expect(dbOverrideSpy).not.toHaveBeenCalled() }) @@ -375,7 +375,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should not apply override when no keyword detected", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("just do something normal", { messageId: "msg_123" }) const tui = createMockTui() @@ -388,7 +388,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should log the model transition with deferred DB tag", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const existingModel = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } const output = createOutput("ultrawork do something", { existingModel, @@ -408,7 +408,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should call showToast on override", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) let toastCalled = false const tui = { @@ -426,7 +426,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should resolve display name to config key with deferred path", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ulw do something", { messageId: "msg_123" }) const tui = createMockTui() @@ -436,16 +436,16 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) }) test("should skip override trigger when current model already matches ultrawork model", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something", { - existingModel: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + existingModel: { providerID: "anthropic", modelID: "claude-opus-4-7" }, messageId: "msg_123", }) let toastCalled = false @@ -465,13 +465,13 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should apply validated variant when SDK confirms model supports it", async () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) const tui = createMockTui() const mockClient = { provider: { list: async () => ({ - data: { all: [{ id: "anthropic", models: { "claude-opus-4-6": { variants: { max: {} } } } }] }, + data: { all: [{ id: "anthropic", models: { "claude-opus-4-7": { variants: { max: {} } } } }] }, }), }, } @@ -482,7 +482,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then - SDK confirmed max exists, so variant is applied expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) }) diff --git a/src/plugin/ultrawork-variant-availability.test.ts b/src/plugin/ultrawork-variant-availability.test.ts index 1fb8a0910..176603698 100644 --- a/src/plugin/ultrawork-variant-availability.test.ts +++ b/src/plugin/ultrawork-variant-availability.test.ts @@ -23,7 +23,7 @@ describe("resolveValidUltraworkVariant", () => { // given const client = createClient({ anthropic: { - "claude-opus-4-6": { + "claude-opus-4-7": { variants: { max: {}, high: {}, @@ -35,7 +35,7 @@ describe("resolveValidUltraworkVariant", () => { // when const result = await resolveValidUltraworkVariant( client, - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) @@ -47,7 +47,7 @@ describe("resolveValidUltraworkVariant", () => { // given const client = createClient({ anthropic: { - "claude-opus-4-6": { + "claude-opus-4-7": { variants: { high: {}, }, @@ -58,7 +58,7 @@ describe("resolveValidUltraworkVariant", () => { // when const result = await resolveValidUltraworkVariant( client, - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) @@ -87,7 +87,7 @@ describe("applyUltraworkModelOverrideOnMessage variant guard", () => { // given const client = createClient({ anthropic: { - "claude-opus-4-6": { + "claude-opus-4-7": { variants: { high: {}, }, @@ -100,7 +100,7 @@ describe("applyUltraworkModelOverrideOnMessage variant guard", () => { agents: { sisyphus: { ultrawork: { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", }, }, @@ -130,7 +130,7 @@ describe("applyUltraworkModelOverrideOnMessage variant guard", () => { expect(output.message["thinking"]).toBeUndefined() expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) dbOverrideSpy.mockRestore() diff --git a/src/shared/agent-config-integration.test.ts b/src/shared/agent-config-integration.test.ts index 6e4726a36..037435b27 100644 --- a/src/shared/agent-config-integration.test.ts +++ b/src/shared/agent-config-integration.test.ts @@ -8,9 +8,9 @@ describe("Agent Config Integration", () => { test("migrates old format agent keys to lowercase", () => { // given - config with old format keys const oldConfig = { - Sisyphus: { model: "anthropic/claude-opus-4-6" }, - Atlas: { model: "anthropic/claude-opus-4-6" }, - "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-6" }, + Sisyphus: { model: "anthropic/claude-opus-4-7" }, + Atlas: { model: "anthropic/claude-opus-4-7" }, + "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-7" }, "Metis - Plan Consultant": { model: "anthropic/claude-sonnet-4-6" }, "Momus - Plan Critic": { model: "anthropic/claude-sonnet-4-6" }, } @@ -33,9 +33,9 @@ describe("Agent Config Integration", () => { expect(result.migrated).not.toHaveProperty("Momus - Plan Critic") // then - values are preserved - expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-6" }) - expect(result.migrated.atlas).toEqual({ model: "anthropic/claude-opus-4-6" }) - expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-7" }) + expect(result.migrated.atlas).toEqual({ model: "anthropic/claude-opus-4-7" }) + expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-7" }) // then - changed flag is true expect(result.changed).toBe(true) @@ -44,7 +44,7 @@ describe("Agent Config Integration", () => { test("preserves already lowercase keys", () => { // given - config with lowercase keys const config = { - sisyphus: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, oracle: { model: "openai/gpt-5.4" }, librarian: { model: "opencode/big-pickle" }, } @@ -62,9 +62,9 @@ describe("Agent Config Integration", () => { test("handles mixed case config", () => { // given - config with mixed old and new format const mixedConfig = { - Sisyphus: { model: "anthropic/claude-opus-4-6" }, + Sisyphus: { model: "anthropic/claude-opus-4-7" }, oracle: { model: "openai/gpt-5.4" }, - "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-6" }, + "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-7" }, librarian: { model: "opencode/big-pickle" }, } @@ -173,8 +173,8 @@ describe("Agent Config Integration", () => { test("old config migrates and displays correctly", () => { // given - old format config const oldConfig = { - Sisyphus: { model: "anthropic/claude-opus-4-6", temperature: 0.1 }, - "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-6" }, + Sisyphus: { model: "anthropic/claude-opus-4-7", temperature: 0.1 }, + "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-7" }, } // when - config is migrated @@ -193,15 +193,15 @@ describe("Agent Config Integration", () => { expect(prometheusDisplay).toBe("Prometheus - Plan Builder") // then - config values are preserved - expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-6", temperature: 0.1 }) - expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-7", temperature: 0.1 }) + expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-7" }) }) test("new config works without migration", () => { // given - new format config (already lowercase) const newConfig = { - sisyphus: { model: "anthropic/claude-opus-4-6" }, - atlas: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, + atlas: { model: "anthropic/claude-opus-4-7" }, } // when - migration is applied (should be no-op) diff --git a/src/shared/agent-variant.test.ts b/src/shared/agent-variant.test.ts index 00ef030fb..58bdd193b 100644 --- a/src/shared/agent-variant.test.ts +++ b/src/shared/agent-variant.test.ts @@ -84,14 +84,14 @@ describe("applyAgentVariant", () => { describe("resolveVariantForModel", () => { test("returns agent override variant when configured", () => { - // given - use a model in sisyphus chain (claude-opus-4-6 has default variant "max") + // given - use a model in sisyphus chain (claude-opus-4-7 has default variant "max") // to verify override takes precedence over fallback chain const config = { agents: { sisyphus: { variant: "high" }, }, } as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "sisyphus", model) @@ -103,7 +103,7 @@ describe("resolveVariantForModel", () => { test("returns correct variant for anthropic provider", () => { // given const config = {} as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "sisyphus", model) @@ -151,7 +151,7 @@ describe("resolveVariantForModel", () => { test("returns undefined for unknown agent", () => { // given const config = {} as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "nonexistent-agent", model) @@ -203,7 +203,7 @@ describe("resolveVariantForModel", () => { test("returns correct variant for oracle agent with anthropic", () => { // given const config = {} as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "oracle", model) diff --git a/src/shared/connected-providers-cache.test.ts b/src/shared/connected-providers-cache.test.ts index 6572a59cc..7d3a7d780 100644 --- a/src/shared/connected-providers-cache.test.ts +++ b/src/shared/connected-providers-cache.test.ts @@ -61,7 +61,7 @@ describe("updateConnectedProvidersCache", () => { name: "Anthropic", env: [], models: { - "claude-opus-4-6": { id: "claude-opus-4-6", name: "Claude Opus 4.6" }, + "claude-opus-4-7": { id: "claude-opus-4-7", name: "Claude Opus 4.6" }, "claude-sonnet-4-6": { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, }, }, @@ -84,7 +84,7 @@ describe("updateConnectedProvidersCache", () => { { id: "gpt-5.4", name: "GPT-5.4" }, ], anthropic: [ - { id: "claude-opus-4-6", name: "Claude Opus 4.6" }, + { id: "claude-opus-4-7", name: "Claude Opus 4.6" }, { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, ], }) diff --git a/src/shared/context-limit-resolver.test.ts b/src/shared/context-limit-resolver.test.ts index a4346a6aa..d924d8a99 100644 --- a/src/shared/context-limit-resolver.test.ts +++ b/src/shared/context-limit-resolver.test.ts @@ -28,15 +28,15 @@ describe("resolveActualContextLimit", () => { resetContextLimitEnv() }) - it("returns cached limit for Anthropic 4.6 models when 1M mode is disabled (GA support)", () => { + it("returns cached limit for Anthropic 4.7 models when 1M mode is disabled (GA support)", () => { // given delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] delete process.env[VERTEX_CONTEXT_ENV_KEY] const modelContextLimitsCache = new Map() - modelContextLimitsCache.set("anthropic/claude-opus-4-6", 1_000_000) + modelContextLimitsCache.set("anthropic/claude-opus-4-7", 1_000_000) // when - const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4-6", { + const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4-7", { anthropicContext1MEnabled: false, modelContextLimitsCache, }) @@ -107,15 +107,15 @@ describe("resolveActualContextLimit", () => { expect(actualLimit).toBe(200000) }) - it("supports Anthropic 4.6 dot-version model IDs without explicit 1M mode", () => { + it("supports Anthropic 4.7 dot-version model IDs without explicit 1M mode", () => { // given delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] delete process.env[VERTEX_CONTEXT_ENV_KEY] const modelContextLimitsCache = new Map() - modelContextLimitsCache.set("anthropic/claude-opus-4.6", 1_000_000) + modelContextLimitsCache.set("anthropic/claude-opus-4.7", 1_000_000) // when - const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4.6", { + const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4.7", { anthropicContext1MEnabled: false, modelContextLimitsCache, }) diff --git a/src/shared/context-limit-resolver.ts b/src/shared/context-limit-resolver.ts index 2bf2a8147..2d440658b 100644 --- a/src/shared/context-limit-resolver.ts +++ b/src/shared/context-limit-resolver.ts @@ -20,7 +20,7 @@ function getAnthropicActualLimit(modelCacheState?: ContextLimitModelCacheState): } function supportsCachedAnthropicLimit(modelID: string): boolean { - return /^claude-(opus|sonnet)-4(?:-|\.)6(?:-high)?$/.test(modelID) + return /^claude-(opus|sonnet)-4(?:-|\.)(?:6|7)(?:-high)?$/.test(modelID) } export function resolveActualContextLimit( diff --git a/src/shared/merge-categories.test.ts b/src/shared/merge-categories.test.ts index c2f56aaa5..5ed82b465 100644 --- a/src/shared/merge-categories.test.ts +++ b/src/shared/merge-categories.test.ts @@ -71,7 +71,7 @@ describe("mergeCategories", () => { it("user overrides merge with defaults", () => { //#given const userCategories = { - "ultrabrain": { model: "anthropic/claude-opus-4-6" }, + "ultrabrain": { model: "anthropic/claude-opus-4-7" }, } //#when @@ -79,6 +79,6 @@ describe("mergeCategories", () => { //#then expect(result["ultrabrain"]).toBeDefined() - expect(result["ultrabrain"].model).toBe("anthropic/claude-opus-4-6") + expect(result["ultrabrain"].model).toBe("anthropic/claude-opus-4-7") }) }) diff --git a/src/shared/model-availability.test.ts b/src/shared/model-availability.test.ts index 7be5e363c..77ca0ca14 100644 --- a/src/shared/model-availability.test.ts +++ b/src/shared/model-availability.test.ts @@ -65,7 +65,7 @@ describe("fetchAvailableModels", () => { it("#given cache file with models #when fetchAvailableModels called with connectedProviders #then returns Set of model IDs", async () => { writeModelsCache({ openai: { id: "openai", models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { id: "anthropic", models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { id: "anthropic", models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, google: { id: "google", models: { "gemini-3.1-pro": { id: "gemini-3.1-pro" } } }, }) @@ -76,7 +76,7 @@ describe("fetchAvailableModels", () => { expect(result).toBeInstanceOf(Set) expect(result.size).toBe(3) expect(result.has("openai/gpt-5.4")).toBe(true) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("google/gemini-3.1-pro")).toBe(true) }) @@ -145,7 +145,7 @@ describe("fetchAvailableModels", () => { it("#given cache read twice #when second call made with same providers #then reads fresh each time", async () => { writeModelsCache({ openai: { id: "openai", models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { id: "anthropic", models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { id: "anthropic", models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result1 = await fetchAvailableModels(undefined, { connectedProviders: ["openai"] }) @@ -192,7 +192,7 @@ describe("fuzzyMatchModel", () => { const available = new Set([ "openai/gpt-5.4", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("gpt-5.4", available) expect(result).toBe("openai/gpt-5.4") @@ -239,25 +239,25 @@ describe("fuzzyMatchModel", () => { // given available models with claude variants // when searching for claude-opus // then return matching claude-opus model - it("should match claude-opus to claude-opus-4-6", () => { + it("should match claude-opus to claude-opus-4-7", () => { const available = new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-6", ]) const result = fuzzyMatchModel("claude-opus", available) - expect(result).toBe("anthropic/claude-opus-4-6") + expect(result).toBe("anthropic/claude-opus-4-7") }) // given github-copilot serves claude versions with dot notation // when fallback chain uses hyphen notation in requested model // then normalize both forms and match github-copilot model - it("should match github-copilot claude-opus-4-6 to claude-opus-4.6", () => { + it("should match github-copilot claude-opus-4-7 to claude-opus-4.7", () => { const available = new Set([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "opencode/big-pickle", ]) - const result = fuzzyMatchModel("claude-opus-4-6", available, ["github-copilot"]) - expect(result).toBe("github-copilot/claude-opus-4.6") + const result = fuzzyMatchModel("claude-opus-4-7", available, ["github-copilot"]) + expect(result).toBe("github-copilot/claude-opus-4.7") }) // given claude models can evolve to newer version numbers @@ -275,7 +275,7 @@ describe("fuzzyMatchModel", () => { it("should filter by provider when providers array is given", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "google/gemini-3", ]) const result = fuzzyMatchModel("gpt", available, ["openai"]) @@ -288,7 +288,7 @@ describe("fuzzyMatchModel", () => { it("should return null when provider filter excludes all matches", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("claude", available, ["openai"]) expect(result).toBeNull() @@ -300,7 +300,7 @@ describe("fuzzyMatchModel", () => { it("should return null when no match found", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("gemini", available) expect(result).toBeNull() @@ -312,7 +312,7 @@ describe("fuzzyMatchModel", () => { it("should match case-insensitively", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("GPT-5.4", available) expect(result).toBe("openai/gpt-5.4") @@ -323,11 +323,11 @@ describe("fuzzyMatchModel", () => { // then return exact match first it("should prioritize exact match over longer variants", () => { const available = new Set([ - "anthropic/claude-opus-4-6", - "anthropic/claude-opus-4-6-extended", + "anthropic/claude-opus-4-7", + "anthropic/claude-opus-4-7-extended", ]) - const result = fuzzyMatchModel("claude-opus-4-6", available) - expect(result).toBe("anthropic/claude-opus-4-6") + const result = fuzzyMatchModel("claude-opus-4-7", available) + expect(result).toBe("anthropic/claude-opus-4-7") }) // given available models with similar model IDs (e.g., glm-5 and big-pickle) @@ -372,7 +372,7 @@ describe("fuzzyMatchModel", () => { it("should search all specified providers", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "google/gemini-3", ]) const result = fuzzyMatchModel("gpt", available, ["openai", "google"]) @@ -520,7 +520,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should filter models by connected providers", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, google: { models: { "gemini-3.1-pro": { id: "gemini-3.1-pro" } } }, }) @@ -529,7 +529,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { }) expect(result.size).toBe(1) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("openai/gpt-5.4")).toBe(false) expect(result.has("google/gemini-3.1-pro")).toBe(false) }) @@ -540,7 +540,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should filter models by multiple connected providers", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, google: { models: { "gemini-3.1-pro": { id: "gemini-3.1-pro" } } }, }) @@ -549,7 +549,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { }) expect(result.size).toBe(2) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("google/gemini-3.1-pro")).toBe(true) expect(result.has("openai/gpt-5.4")).toBe(false) }) @@ -560,7 +560,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should return empty set when connectedProviders is empty", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result = await fetchAvailableModels(undefined, { @@ -576,7 +576,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should return empty set when connectedProviders not specified", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result = await fetchAvailableModels() @@ -605,7 +605,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should return models from providers that exist in both cache and connected list", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result = await fetchAvailableModels(undefined, { @@ -613,7 +613,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { }) expect(result.size).toBe(1) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) }) // given filtered fetch @@ -622,7 +622,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should not cache filtered results", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) // First call with anthropic @@ -706,13 +706,13 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", writeProviderModelsCache({ models: { opencode: ["big-pickle", "gpt-5-nano"], - anthropic: ["claude-opus-4-6"] + anthropic: ["claude-opus-4-7"] }, connected: ["opencode", "anthropic"] }) writeModelsCache({ opencode: { models: { "big-pickle": {}, "gpt-5-nano": {}, "gpt-5.4": {} } }, - anthropic: { models: { "claude-opus-4-6": {}, "claude-sonnet-4-6": {} } } + anthropic: { models: { "claude-opus-4-7": {}, "claude-sonnet-4-6": {} } } }) const result = await fetchAvailableModels(undefined, { @@ -722,7 +722,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", expect(result.size).toBe(3) expect(result.has("opencode/big-pickle")).toBe(true) expect(result.has("opencode/gpt-5-nano")).toBe(true) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("opencode/gpt-5.4")).toBe(false) expect(result.has("anthropic/claude-sonnet-4-6")).toBe(false) }) @@ -773,7 +773,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", writeProviderModelsCache({ models: { opencode: ["big-pickle"], - anthropic: ["claude-opus-4-6"], + anthropic: ["claude-opus-4-7"], google: ["gemini-3.1-pro"] }, connected: ["opencode", "anthropic", "google"] @@ -785,7 +785,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", expect(result.size).toBe(1) expect(result.has("opencode/big-pickle")).toBe(true) - expect(result.has("anthropic/claude-opus-4-6")).toBe(false) + expect(result.has("anthropic/claude-opus-4-7")).toBe(false) expect(result.has("google/gemini-3.1-pro")).toBe(false) }) @@ -812,7 +812,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", it("should handle mixed string[] and object[] formats across providers", async () => { writeProviderModelsCache({ models: { - anthropic: ["claude-opus-4-6", "claude-sonnet-4-6"], + anthropic: ["claude-opus-4-7", "claude-sonnet-4-6"], ollama: [ { id: "ministral-3:14b-32k-agent", provider: "ollama" }, { id: "qwen3-coder:32k-agent", provider: "ollama" } @@ -826,7 +826,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", }) expect(result.size).toBe(4) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("anthropic/claude-sonnet-4-6")).toBe(true) expect(result.has("ollama/ministral-3:14b-32k-agent")).toBe(true) expect(result.has("ollama/qwen3-coder:32k-agent")).toBe(true) @@ -859,7 +859,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", describe("isModelAvailable", () => { it("returns true when model exists via fuzzy match", () => { // given - const available = new Set(["openai/gpt-5.3-codex", "anthropic/claude-opus-4-6"]) + const available = new Set(["openai/gpt-5.3-codex", "anthropic/claude-opus-4-7"]) // when const result = isModelAvailable("gpt-5.3-codex", available) @@ -870,7 +870,7 @@ describe("isModelAvailable", () => { it("returns false when model not found", () => { // given - const available = new Set(["anthropic/claude-opus-4-6"]) + const available = new Set(["anthropic/claude-opus-4-7"]) // when const result = isModelAvailable("gpt-5.3-codex", available) @@ -924,7 +924,7 @@ describe("fallback model availability", () => { it("returns null for completely unknown model", () => { // given - const available = new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6"]) + const available = new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7"]) // when const result = fuzzyMatchModel("non-existent-model-family", available) @@ -936,7 +936,7 @@ describe("fallback model availability", () => { it("returns true when models do not match but provider is connected", () => { // given const fallbackChain = [{ providers: ["openai"], model: "gpt-5.4" }] - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) writeConnectedProvidersCache(["openai"]) // when @@ -950,10 +950,10 @@ describe("fallback model availability", () => { // given const fallbackChain = [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ] const availableModels = new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "openai/gpt-5.4-preview", ]) @@ -968,7 +968,7 @@ describe("fallback model availability", () => { // given const fallbackChain = [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ] const availableModels = new Set(["google/gemini-3.1-pro"]) diff --git a/src/shared/model-availability.ts b/src/shared/model-availability.ts index 595962551..aaec07338 100644 --- a/src/shared/model-availability.ts +++ b/src/shared/model-availability.ts @@ -21,7 +21,7 @@ import { normalizeSDKResponse } from "./normalize-sdk-response" * If providers array is given, only models starting with "provider/" are considered. * * @example - * const available = new Set(["openai/gpt-5.4", "openai/gpt-5.3-codex", "anthropic/claude-opus-4-6"]) + * const available = new Set(["openai/gpt-5.4", "openai/gpt-5.3-codex", "anthropic/claude-opus-4-7"]) * fuzzyMatchModel("gpt-5.4", available) // → "openai/gpt-5.4" * fuzzyMatchModel("claude", available, ["openai"]) // → null (provider filter excludes anthropic) */ diff --git a/src/shared/model-capabilities.test.ts b/src/shared/model-capabilities.test.ts index d221633ef..e79448fbf 100644 --- a/src/shared/model-capabilities.test.ts +++ b/src/shared/model-capabilities.test.ts @@ -16,8 +16,8 @@ describe("getModelCapabilities", () => { generatedAt: "2026-03-25T00:00:00.000Z", sourceUrl: "https://models.dev/api.json", models: { - "claude-opus-4-6": { - id: "claude-opus-4-6", + "claude-opus-4-7": { + id: "claude-opus-4-7", family: "claude-opus", reasoning: true, temperature: true, @@ -66,7 +66,7 @@ describe("getModelCapabilities", () => { findProviderModelMetadataSpy = spyOn(connectedProvidersCache, "findProviderModelMetadata").mockReturnValue(undefined) const result = getModelCapabilities({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", runtimeModel: { variants: { low: {}, @@ -78,7 +78,7 @@ describe("getModelCapabilities", () => { }) expect(result).toMatchObject({ - canonicalModelID: "claude-opus-4-6", + canonicalModelID: "claude-opus-4-7", family: "claude-opus", variants: ["low", "medium", "high"], supportsThinking: true, @@ -173,12 +173,12 @@ describe("getModelCapabilities", () => { findProviderModelMetadataSpy = spyOn(connectedProvidersCache, "findProviderModelMetadata").mockReturnValue(undefined) const result = getModelCapabilities({ providerID: "anthropic", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", bundledSnapshot, }) expect(result).toMatchObject({ - canonicalModelID: "claude-opus-4-6", + canonicalModelID: "claude-opus-4-7", family: "claude-opus", supportsThinking: true, supportsTemperature: true, @@ -247,13 +247,13 @@ describe("getModelCapabilities", () => { test("canonicalizes provider-prefixed Claude thinking aliases to bare snapshot IDs", () => { const result = getModelCapabilities({ providerID: "anthropic", - modelID: "anthropic/claude-opus-4-6-thinking", + modelID: "anthropic/claude-opus-4-7-thinking", bundledSnapshot, }) expect(result).toMatchObject({ - requestedModelID: "anthropic/claude-opus-4-6-thinking", - canonicalModelID: "claude-opus-4-6", + requestedModelID: "anthropic/claude-opus-4-7-thinking", + canonicalModelID: "claude-opus-4-7", family: "claude-opus", supportsThinking: true, supportsTemperature: true, diff --git a/src/shared/model-capability-aliases.test.ts b/src/shared/model-capability-aliases.test.ts index 6d05c3abc..b6f5b6641 100644 --- a/src/shared/model-capability-aliases.test.ts +++ b/src/shared/model-capability-aliases.test.ts @@ -67,22 +67,22 @@ describe("model-capability-aliases", () => { }) test("normalizes provider-prefixed Claude thinking aliases through a pattern rule", () => { - const result = resolveModelIDAlias("anthropic/claude-opus-4-6-thinking") + const result = resolveModelIDAlias("anthropic/claude-opus-4-7-thinking") expect(result).toEqual({ - requestedModelID: "anthropic/claude-opus-4-6-thinking", - canonicalModelID: "claude-opus-4-6", + requestedModelID: "anthropic/claude-opus-4-7-thinking", + canonicalModelID: "claude-opus-4-7", source: "pattern-alias", ruleID: "claude-thinking-legacy-alias", }) }) test("does not pattern-match nearby canonical Claude IDs incorrectly", () => { - const result = resolveModelIDAlias("claude-opus-4-6-think") + const result = resolveModelIDAlias("claude-opus-4-7-think") expect(result).toEqual({ - requestedModelID: "claude-opus-4-6-think", - canonicalModelID: "claude-opus-4-6-think", + requestedModelID: "claude-opus-4-7-think", + canonicalModelID: "claude-opus-4-7-think", source: "canonical", }) }) @@ -98,11 +98,11 @@ describe("model-capability-aliases", () => { }) test("normalizes legacy Claude thinking aliases through a pattern rule", () => { - const result = resolveModelIDAlias("claude-opus-4-6-thinking") + const result = resolveModelIDAlias("claude-opus-4-7-thinking") expect(result).toEqual({ - requestedModelID: "claude-opus-4-6-thinking", - canonicalModelID: "claude-opus-4-6", + requestedModelID: "claude-opus-4-7-thinking", + canonicalModelID: "claude-opus-4-7", source: "pattern-alias", ruleID: "claude-thinking-legacy-alias", }) diff --git a/src/shared/model-capability-aliases.ts b/src/shared/model-capability-aliases.ts index 4f9f1c752..01c7a23ba 100644 --- a/src/shared/model-capability-aliases.ts +++ b/src/shared/model-capability-aliases.ts @@ -42,8 +42,8 @@ const PATTERN_ALIAS_RULES: ReadonlyArray = [ { ruleID: "claude-thinking-legacy-alias", description: "Normalizes the legacy Claude Opus 4.6 thinking suffix to the canonical snapshot ID.", - match: (normalizedModelID) => /^claude-opus-4-6-thinking$/.test(normalizedModelID), - canonicalize: () => "claude-opus-4-6", + match: (normalizedModelID) => /^claude-opus-4-7-thinking$/.test(normalizedModelID), + canonicalize: () => "claude-opus-4-7", }, { ruleID: "gemini-3.1-pro-tier-alias", diff --git a/src/shared/model-capability-guardrails.test.ts b/src/shared/model-capability-guardrails.test.ts index a37534d9a..63ff3aab2 100644 --- a/src/shared/model-capability-guardrails.test.ts +++ b/src/shared/model-capability-guardrails.test.ts @@ -19,7 +19,7 @@ describe("model-capability-guardrails", () => { expect(modelIDs).toEqual([...modelIDs].sort()) expect(new Set(modelIDs).size).toBe(modelIDs.length) - expect(modelIDs).toContain("claude-opus-4-6") + expect(modelIDs).toContain("claude-opus-4-7") expect(modelIDs).toContain("gpt-5.4") expect(modelIDs).toContain("kimi-k2.5") }) diff --git a/src/shared/model-error-classifier.test.ts b/src/shared/model-error-classifier.test.ts index a1f7c5265..35c75de0a 100644 --- a/src/shared/model-error-classifier.test.ts +++ b/src/shared/model-error-classifier.test.ts @@ -31,7 +31,7 @@ describe("model-error-classifier", () => { //#given const error = { message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", } //#when diff --git a/src/shared/model-format-normalizer.test.ts b/src/shared/model-format-normalizer.test.ts index d28ab975b..4cdca42ad 100644 --- a/src/shared/model-format-normalizer.test.ts +++ b/src/shared/model-format-normalizer.test.ts @@ -9,8 +9,8 @@ describe("normalizeModelFormat", () => { }) it("handles provider with multiple slashes", () => { - const result = normalizeModelFormat("anthropic/claude-opus-4-6/max") - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6/max" }) + const result = normalizeModelFormat("anthropic/claude-opus-4-7/max") + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7/max" }) }) it("returns undefined for malformed string without separator", () => { diff --git a/src/shared/model-requirements.test.ts b/src/shared/model-requirements.test.ts index 324176b57..3692677f7 100644 --- a/src/shared/model-requirements.test.ts +++ b/src/shared/model-requirements.test.ts @@ -23,7 +23,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(primary.variant).toBe("high") }) - test("sisyphus has claude-opus-4-6 as primary with k2p5, kimi-k2.5, gpt-5.4 medium fallbacks", () => { + test("sisyphus has claude-opus-4-7 as primary with k2p5, kimi-k2.5, gpt-5.4 medium fallbacks", () => { // #given - sisyphus agent requirement const sisyphus = AGENT_MODEL_REQUIREMENTS["sisyphus"] @@ -36,7 +36,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const primary = sisyphus.fallbackChain[0] expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.variant).toBe("max") const second = sisyphus.fallbackChain[1] @@ -148,34 +148,34 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(last.model).toBe("gpt-5-nano") }) - test("prometheus has claude-opus-4-6 as primary", () => { + test("prometheus has claude-opus-4-7 as primary", () => { // #given - prometheus agent requirement const prometheus = AGENT_MODEL_REQUIREMENTS["prometheus"] // #when - accessing Prometheus requirement - // #then - claude-opus-4-6 is first + // #then - claude-opus-4-7 is first expect(prometheus).toBeDefined() expect(prometheus.fallbackChain).toBeArray() expect(prometheus.fallbackChain.length).toBeGreaterThan(1) const primary = prometheus.fallbackChain[0] - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) expect(primary.variant).toBe("max") }) - test("metis has claude-opus-4-6 as primary", () => { + test("metis has claude-opus-4-7 as primary", () => { // #given - metis agent requirement const metis = AGENT_MODEL_REQUIREMENTS["metis"] // #when - accessing Metis requirement - // #then - claude-opus-4-6 is first + // #then - claude-opus-4-7 is first expect(metis).toBeDefined() expect(metis.fallbackChain).toBeArray() expect(metis.fallbackChain.length).toBeGreaterThan(1) const primary = metis.fallbackChain[0] - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) expect(primary.variant).toBe("max") @@ -356,7 +356,7 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { expect(second.model).toBe("glm-5") const third = visualEngineering.fallbackChain[2] - expect(third.model).toBe("claude-opus-4-6") + expect(third.model).toBe("claude-opus-4-7") expect(third.variant).toBe("max") const fourth = visualEngineering.fallbackChain[3] @@ -402,18 +402,18 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { expect(primary.providers[0]).toBe("anthropic") }) - test("unspecified-high has claude-opus-4-6 as primary and gpt-5.4 as secondary", () => { + test("unspecified-high has claude-opus-4-7 as primary and gpt-5.4 as secondary", () => { // #given - unspecified-high category requirement const unspecifiedHigh = CATEGORY_MODEL_REQUIREMENTS["unspecified-high"] // #when - accessing unspecified-high requirement - // #then - claude-opus-4-6 is first and gpt-5.4 is second + // #then - claude-opus-4-7 is first and gpt-5.4 is second expect(unspecifiedHigh).toBeDefined() expect(unspecifiedHigh.fallbackChain).toBeArray() expect(unspecifiedHigh.fallbackChain.length).toBeGreaterThan(1) const primary = unspecifiedHigh.fallbackChain[0] - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.variant).toBe("max") expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) @@ -505,14 +505,14 @@ describe("FallbackEntry type", () => { // given - a valid FallbackEntry object const entry: FallbackEntry = { providers: ["anthropic", "github-copilot", "opencode"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "high", } // when - accessing properties // then - all properties are accessible expect(entry.providers).toEqual(["anthropic", "github-copilot", "opencode"]) - expect(entry.model).toBe("claude-opus-4-6") + expect(entry.model).toBe("claude-opus-4-7") expect(entry.variant).toBe("high") }) @@ -534,7 +534,7 @@ describe("ModelRequirement type", () => { // given - a valid ModelRequirement object const requirement: ModelRequirement = { fallbackChain: [ - { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7", variant: "max" }, { providers: ["openai", "github-copilot"], model: "gpt-5.4", variant: "high" }, ], } @@ -543,7 +543,7 @@ describe("ModelRequirement type", () => { // then - fallbackChain is accessible with correct structure expect(requirement.fallbackChain).toBeArray() expect(requirement.fallbackChain).toHaveLength(2) - expect(requirement.fallbackChain[0].model).toBe("claude-opus-4-6") + expect(requirement.fallbackChain[0].model).toBe("claude-opus-4-7") expect(requirement.fallbackChain[1].model).toBe("gpt-5.4") }) diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index b9ac989ab..16f64cd6a 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -22,7 +22,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "kimi-k2.5" }, @@ -69,7 +69,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, @@ -104,7 +104,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -123,7 +123,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -144,7 +144,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -193,7 +193,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { { providers: ["zai-coding-plan", "opencode", "vercel"], model: "glm-5" }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, @@ -214,7 +214,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, @@ -229,7 +229,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -248,7 +248,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["openai", "github-copilot", "opencode", "vercel"], model: "gpt-5.4" }, @@ -296,7 +296,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { diff --git a/src/shared/model-resolver.test.ts b/src/shared/model-resolver.test.ts index 292aac718..0e546c312 100644 --- a/src/shared/model-resolver.test.ts +++ b/src/shared/model-resolver.test.ts @@ -12,7 +12,7 @@ describe("resolveModel", () => { test("returns userModel when all three are set", () => { // given const input: ModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", inheritedModel: "openai/gpt-5.4", systemDefault: "google/gemini-3.1-pro", } @@ -21,7 +21,7 @@ describe("resolveModel", () => { const result = resolveModel(input) // then - expect(result).toBe("anthropic/claude-opus-4-6") + expect(result).toBe("anthropic/claude-opus-4-7") }) test("returns inheritedModel when userModel is undefined", () => { @@ -91,7 +91,7 @@ describe("resolveModel", () => { test("same input returns same output (referential transparency)", () => { // given const input: ModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", inheritedModel: "openai/gpt-5.4", systemDefault: "google/gemini-3.1-pro", } @@ -122,11 +122,11 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: "opencode/big-pickle", - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", fallbackChain: [ - { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]), + availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -143,8 +143,8 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: "opencode/big-pickle", - userModel: "anthropic/claude-opus-4-6", - availableModels: new Set(["anthropic/claude-opus-4-6"]), + userModel: "anthropic/claude-opus-4-7", + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -160,8 +160,8 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: " ", - userModel: "anthropic/claude-opus-4-6", - availableModels: new Set(["anthropic/claude-opus-4-6"]), + userModel: "anthropic/claude-opus-4-7", + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -169,16 +169,16 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") - expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-6" }) + expect(result!.model).toBe("anthropic/claude-opus-4-7") + expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-7" }) }) test("empty string uiSelectedModel falls through to config override", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: "", - userModel: "anthropic/claude-opus-4-6", - availableModels: new Set(["anthropic/claude-opus-4-6"]), + userModel: "anthropic/claude-opus-4-7", + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -186,7 +186,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") }) }) @@ -194,11 +194,11 @@ describe("resolveModelWithFallback", () => { test("returns userModel with override source when userModel is provided", () => { // given const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", fallbackChain: [ - { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]), + availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -206,9 +206,9 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("override") - expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-6" }) + expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-7" }) }) test("override takes priority even if model not in availableModels", () => { @@ -216,9 +216,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { userModel: "custom/my-model", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -235,9 +235,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { userModel: " ", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -253,9 +253,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { userModel: "", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -272,9 +272,9 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["github-copilot/claude-opus-4-6-preview", "opencode/claude-opus-4-7"]), + availableModels: new Set(["github-copilot/claude-opus-4-7-preview", "opencode/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -282,12 +282,12 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("github-copilot/claude-opus-4-6-preview") + expect(result!.model).toBe("github-copilot/claude-opus-4-7-preview") expect(result!.source).toBe("provider-fallback") expect(logSpy).toHaveBeenCalledWith("Model resolved via fallback chain (availability confirmed)", { provider: "github-copilot", - model: "claude-opus-4-6", - match: "github-copilot/claude-opus-4-6-preview", + model: "claude-opus-4-7", + match: "github-copilot/claude-opus-4-7-preview", variant: undefined, }) }) @@ -298,7 +298,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["openai", "anthropic", "google"], model: "gpt-5.4" }, ], - availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6", "google/gemini-3.1-pro"]), + availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7", "google/gemini-3.1-pro"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -334,7 +334,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["anthropic", "github-copilot"], model: "claude-opus" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]), + availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -342,14 +342,14 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) test("skips fallback chain when not provided", () => { // given const input: ExtendedModelResolutionInput = { - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -364,7 +364,7 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { fallbackChain: [], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -381,7 +381,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["anthropic"], model: "CLAUDE-OPUS" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -389,7 +389,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) @@ -480,7 +480,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["anthropic"], model: "nonexistent-model" }, ], - availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6"]), + availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -498,7 +498,7 @@ describe("resolveModelWithFallback", () => { const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], availableModels: new Set(), systemDefaultModel: undefined, // no system default configured @@ -517,7 +517,7 @@ describe("resolveModelWithFallback", () => { const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai", "google"]) const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic", "openai"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "openai"], model: "claude-opus-4-7" }, ], availableModels: new Set(), systemDefaultModel: "google/gemini-3.1-pro", @@ -527,7 +527,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - should use connected provider (openai) from fallback chain - expect(result!.model).toBe("openai/claude-opus-4-6") + expect(result!.model).toBe("openai/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") cacheSpy.mockRestore() }) @@ -561,14 +561,14 @@ describe("resolveModelWithFallback", () => { { providers: ["openai", "opencode"], model: "claude-haiku-4-5" }, ], availableModels: new Set(), - systemDefaultModel: "anthropic/claude-opus-4-6-20251101", + systemDefaultModel: "anthropic/claude-opus-4-7-20251101", } // when const result = resolveModelWithFallback(input) // then - no provider in fallback is connected, fall through to system default - expect(result!.model).toBe("anthropic/claude-opus-4-6-20251101") + expect(result!.model).toBe("anthropic/claude-opus-4-7-20251101") expect(result!.source).toBe("system-default") cacheSpy.mockRestore() }) @@ -578,7 +578,7 @@ describe("resolveModelWithFallback", () => { const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], availableModels: new Set(), systemDefaultModel: "google/gemini-3.1-pro", @@ -612,20 +612,20 @@ describe("resolveModelWithFallback", () => { describe("Multi-entry fallbackChain", () => { test("resolves to claude-opus when OpenAI unavailable but Anthropic available (oracle scenario)", () => { // given - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) // when const result = resolveModelWithFallback({ fallbackChain: [ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "high" }, - { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-7", variant: "max" }, ], availableModels, systemDefaultModel: "system/default", }) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) @@ -652,14 +652,14 @@ describe("resolveModelWithFallback", () => { // given const availableModels = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) // when const result = resolveModelWithFallback({ fallbackChain: [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], availableModels, systemDefaultModel: "system/default", @@ -678,7 +678,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback({ fallbackChain: [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, { providers: ["google"], model: "gemini-3.1-pro" }, ], availableModels, @@ -695,7 +695,7 @@ describe("resolveModelWithFallback", () => { test("result has correct ModelResolutionResult shape", () => { // given const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", availableModels: new Set(), systemDefaultModel: "google/gemini-3.1-pro", } @@ -718,7 +718,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro" }, ], - availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-6"]), + availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-7"]), systemDefaultModel: "anthropic/claude-sonnet-4-6", } @@ -754,9 +754,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { categoryDefaultModel: "google/gemini-3.1-pro", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "system/default", } @@ -764,19 +764,19 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - should fall through to fallbackChain - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) test("userModel takes priority over categoryDefaultModel", () => { // given - both userModel and categoryDefaultModel provided const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", categoryDefaultModel: "google/gemini-3.1-pro", fallbackChain: [ { providers: ["google"], model: "gemini-3.1-pro" }, ], - availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-6"]), + availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-7"]), systemDefaultModel: "system/default", } @@ -784,7 +784,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - userModel wins - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("override") }) @@ -916,7 +916,7 @@ describe("resolveModelWithFallback", () => { test("still returns override when userModel provided even if systemDefaultModel undefined", () => { // given const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", availableModels: new Set(), systemDefaultModel: undefined, } @@ -926,7 +926,7 @@ describe("resolveModelWithFallback", () => { // then expect(result).toBeDefined() - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("override") }) @@ -934,9 +934,9 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: undefined, } @@ -945,7 +945,7 @@ describe("resolveModelWithFallback", () => { // then expect(result).toBeDefined() - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) }) diff --git a/src/shared/model-settings-compatibility.test.ts b/src/shared/model-settings-compatibility.test.ts index 6e7a7b590..9cf0ab172 100644 --- a/src/shared/model-settings-compatibility.test.ts +++ b/src/shared/model-settings-compatibility.test.ts @@ -6,7 +6,7 @@ describe("resolveCompatibleModelSettings", () => { test("keeps supported Claude Opus variant unchanged", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: { variant: "max" }, }) @@ -20,7 +20,7 @@ describe("resolveCompatibleModelSettings", () => { test("uses model metadata first for variant support", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: { variant: "max" }, capabilities: { variants: ["low", "medium", "high"] }, }) @@ -42,7 +42,7 @@ describe("resolveCompatibleModelSettings", () => { test("prefers metadata over family heuristics even when family would allow a higher level", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: { variant: "max" }, capabilities: { variants: ["low", "medium"] }, }) @@ -514,7 +514,7 @@ describe("resolveCompatibleModelSettings", () => { test("no-op when desired settings are empty", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: {}, }) diff --git a/src/shared/provider-model-id-transform.ts b/src/shared/provider-model-id-transform.ts index c01942a0f..59904199d 100644 --- a/src/shared/provider-model-id-transform.ts +++ b/src/shared/provider-model-id-transform.ts @@ -23,9 +23,9 @@ function applyGatewayTransforms(model: string): string { } export function transformModelForProvider(provider: string, model: string): string { - // Vercel AI Gateway expects / (e.g. anthropic/claude-opus-4.6). - // Canonical names in model-requirements.ts may be bare (claude-opus-4-6) or - // already prefixed (anthropic/claude-opus-4-6). Both need gateway-specific transforms. + // Vercel AI Gateway expects / (e.g. anthropic/claude-opus-4.7). + // Canonical names in model-requirements.ts may be bare (claude-opus-4-7) or + // already prefixed (anthropic/claude-opus-4-7). Both need gateway-specific transforms. if (provider === "vercel") { // Already prefixed — transform only the model part const slashIndex = model.indexOf("/") diff --git a/src/tools/delegate-task/anthropic-categories.ts b/src/tools/delegate-task/anthropic-categories.ts index e6b0894e3..cb5a88876 100644 --- a/src/tools/delegate-task/anthropic-categories.ts +++ b/src/tools/delegate-task/anthropic-categories.ts @@ -47,7 +47,7 @@ export const ANTHROPIC_CATEGORIES: BuiltinCategoryDefinition[] = [ }, { name: "unspecified-high", - config: { model: "anthropic/claude-opus-4-6", variant: "max" }, + config: { model: "anthropic/claude-opus-4-7", variant: "max" }, description: "Tasks that don't fit other categories, high effort required", promptAppend: UNSPECIFIED_HIGH_CATEGORY_PROMPT_APPEND, }, diff --git a/src/tools/delegate-task/category-resolver.test.ts b/src/tools/delegate-task/category-resolver.test.ts index 4a52f4158..ffe59d705 100644 --- a/src/tools/delegate-task/category-resolver.test.ts +++ b/src/tools/delegate-task/category-resolver.test.ts @@ -99,7 +99,7 @@ describe("resolveCategoryExecution", () => { const executorCtx = createMockExecutorContext() executorCtx.userCategories = { deep: { - model: "quotio/claude-opus-4-6", + model: "quotio/claude-opus-4-7", fallback_models: ["quotio/kimi-k2.5", "openai/gpt-5.2(high)"], }, } diff --git a/src/tools/delegate-task/sync-task.test.ts b/src/tools/delegate-task/sync-task.test.ts index 16bc31521..a81fe4eb1 100644 --- a/src/tools/delegate-task/sync-task.test.ts +++ b/src/tools/delegate-task/sync-task.test.ts @@ -272,11 +272,11 @@ describe("executeSyncTask - cleanup on error paths", () => { const initialModel = { providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", } const fallbackChain = [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["opencode-go"], model: "kimi-k2.5" }, ] @@ -289,7 +289,7 @@ describe("executeSyncTask - cleanup on error paths", () => { expect(result).toContain("Task completed") expect(result).toContain("Model: opencode-go/kimi-k2.5") expect(attemptedModels).toEqual([ - { providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }, + { providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }, { providerID: "opencode-go", modelID: "kimi-k2.5", variant: undefined }, ]) }) @@ -339,11 +339,11 @@ describe("executeSyncTask - cleanup on error paths", () => { const initialModel = { providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", } const fallbackChain = [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["opencode-go"], model: "kimi-k2.5" }, { providers: ["openai"], model: "gpt-5.4", variant: "medium" }, ] @@ -356,7 +356,7 @@ describe("executeSyncTask - cleanup on error paths", () => { //#then expect(result).toBe("Final failure") expect(attemptedModels).toEqual([ - { providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }, + { providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }, { providerID: "opencode-go", modelID: "kimi-k2.5", variant: undefined }, { providerID: "openai", modelID: "gpt-5.4", variant: "medium" }, ]) diff --git a/src/tools/delegate-task/tools.test.ts b/src/tools/delegate-task/tools.test.ts index 8fb3156a2..2f703fa47 100644 --- a/src/tools/delegate-task/tools.test.ts +++ b/src/tools/delegate-task/tools.test.ts @@ -28,7 +28,7 @@ const SYSTEM_DEFAULT_MODEL = "anthropic/claude-sonnet-4-6" const TEST_CONNECTED_PROVIDERS = ["anthropic", "google", "openai"] const TEST_AVAILABLE_MODELS = new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-6", "anthropic/claude-haiku-4-5", "google/gemini-3.1-pro", @@ -66,7 +66,7 @@ describe("sisyphus-task", () => { cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic", "google", "openai"]) providerModelsSpy = spyOn(connectedProvidersCache, "readProviderModelsCache").mockReturnValue({ models: { - anthropic: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"], + anthropic: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"], google: ["gemini-3.1-pro", "gemini-3-flash"], openai: ["gpt-5.4", "gpt-5.3-codex"], }, @@ -112,13 +112,13 @@ describe("sisyphus-task", () => { expect(category.variant).toBe("medium") }) - test("unspecified-high category uses claude-opus-4-6 max as primary", () => { + test("unspecified-high category uses claude-opus-4-7 max as primary", () => { // given const category = DEFAULT_CATEGORIES["unspecified-high"] // when / #then expect(category).toBeDefined() - expect(category.model).toBe("anthropic/claude-opus-4-6") + expect(category.model).toBe("anthropic/claude-opus-4-7") expect(category.variant).toBe("max") }) }) @@ -757,7 +757,7 @@ describe("sisyphus-task", () => { test("blocks requiresModel when availability is known and missing the required model", () => { // given - artistry has requiresModel: gemini-3.1-pro const categoryName = "artistry" - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) // when const result = resolveCategoryConfig(categoryName, { @@ -787,9 +787,9 @@ describe("sisyphus-task", () => { test("bypasses requiresModel when explicit user config provided", () => { // #given const categoryName = "deep" - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) const userCategories = { - deep: { model: "anthropic/claude-opus-4-6" }, + deep: { model: "anthropic/claude-opus-4-7" }, } // #when @@ -801,7 +801,7 @@ describe("sisyphus-task", () => { // #then expect(result).not.toBeNull() - expect(result!.config.model).toBe("anthropic/claude-opus-4-6") + expect(result!.config.model).toBe("anthropic/claude-opus-4-7") }) test("bypasses requiresModel when explicit user config provided even with empty availability", () => { @@ -809,7 +809,7 @@ describe("sisyphus-task", () => { const categoryName = "deep" const availableModels = new Set() const userCategories = { - deep: { model: "anthropic/claude-opus-4-6" }, + deep: { model: "anthropic/claude-opus-4-7" }, } // #when @@ -821,7 +821,7 @@ describe("sisyphus-task", () => { // #then expect(result).not.toBeNull() - expect(result!.config.model).toBe("anthropic/claude-opus-4-6") + expect(result!.config.model).toBe("anthropic/claude-opus-4-7") }) test("returns default model from DEFAULT_CATEGORIES for builtin category", () => { @@ -841,7 +841,7 @@ describe("sisyphus-task", () => { // given const categoryName = "visual-engineering" const userCategories = { - "visual-engineering": { model: "anthropic/claude-opus-4-6" }, + "visual-engineering": { model: "anthropic/claude-opus-4-7" }, } // when @@ -849,7 +849,7 @@ describe("sisyphus-task", () => { // then expect(result).not.toBeNull() - expect(result!.config.model).toBe("anthropic/claude-opus-4-6") + expect(result!.config.model).toBe("anthropic/claude-opus-4-7") }) test("user prompt_append is appended to default", () => { @@ -913,7 +913,7 @@ describe("sisyphus-task", () => { test("category built-in model takes precedence over inheritedModel", () => { // given - builtin category with its own model, parent model also provided const categoryName = "visual-engineering" - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const result = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -927,7 +927,7 @@ describe("sisyphus-task", () => { // given - custom category with no model defined const categoryName = "my-custom-no-model" const userCategories = { "my-custom-no-model": { temperature: 0.5 } } as unknown as Record - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const result = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -943,7 +943,7 @@ describe("sisyphus-task", () => { const userCategories = { "visual-engineering": { model: "my-provider/my-model" }, } - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const result = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -1054,7 +1054,7 @@ describe("sisyphus-task", () => { const mockClient = { app: { agents: async () => ({ data: [] }) }, config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, - model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-6" }] }, + model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-7" }] }, session: { create: async () => ({ data: { id: "test-session" } }), prompt: async () => ({ data: {} }), @@ -1078,7 +1078,7 @@ describe("sisyphus-task", () => { abort: new AbortController().signal, } - // when - unspecified-high uses claude-opus-4-6 max in DEFAULT_CATEGORIES + // when - unspecified-high uses claude-opus-4-7 max in DEFAULT_CATEGORIES await tool.execute( { description: "Test unspecified-high default variant", @@ -1090,10 +1090,10 @@ describe("sisyphus-task", () => { toolContext ) - // then - claude-opus-4-6 should be passed with max variant + // then - claude-opus-4-7 should be passed with max variant expect(launchInput.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", }) }, { timeout: 20000 }) @@ -1113,7 +1113,7 @@ describe("sisyphus-task", () => { const mockClient = { app: { agents: async () => ({ data: [] }) }, config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, - model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-6" }] }, + model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-7" }] }, session: { get: async () => ({ data: { directory: "/project" } }), create: async () => ({ data: { id: "ses_sync_default_variant" } }), @@ -1139,7 +1139,7 @@ describe("sisyphus-task", () => { abort: new AbortController().signal, } - // when - unspecified-high uses claude-opus-4-6 max in DEFAULT_CATEGORIES + // when - unspecified-high uses claude-opus-4-7 max in DEFAULT_CATEGORIES await tool.execute( { description: "Test unspecified-high sync variant", @@ -1151,10 +1151,10 @@ describe("sisyphus-task", () => { toolContext ) - // then - claude-opus-4-6 should be passed with max variant + // then - claude-opus-4-7 should be passed with max variant expect(promptBody.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) expect(promptBody.variant).toBe("max") }, { timeout: 20000 }) @@ -1550,7 +1550,7 @@ describe("sisyphus-task", () => { let promptCalled = false const mockManager = { launch: async () => ({}) } const mockClient = { - app: { agents: async () => ({ data: [{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-6" } }] }) }, + app: { agents: async () => ({ data: [{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-7" } }] }) }, config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, session: { get: async () => ({ data: { directory: "/project" } }), @@ -1835,7 +1835,7 @@ describe("sisyphus-task", () => { id: "msg_001", role: "user", agent: "sisyphus-junior", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, variant: "max", time: { created: baseTime }, }, @@ -1917,7 +1917,7 @@ describe("sisyphus-task", () => { const callArgs = promptMock.mock.calls[0][0] expect(callArgs.body.variant).toBe("max") expect(callArgs.body.agent).toBe("sisyphus-junior") - expect(callArgs.body.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(callArgs.body.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }, { timeout: 10000 }) test("task_id with background=true should return immediately without waiting", async () => { @@ -2551,7 +2551,7 @@ describe("sisyphus-task", () => { // Override provider cache to include kimi-for-coding provider providerModelsSpy.mockReturnValue({ models: { - anthropic: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"], + anthropic: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"], google: ["gemini-3.1-pro", "gemini-3-flash"], openai: ["gpt-5.4", "gpt-5.3-codex"], "kimi-for-coding": ["k2p5"], @@ -2798,7 +2798,7 @@ describe("sisyphus-task", () => { manager: mockManager, client: mockClient, userCategories: { - "fallback-test": { model: "anthropic/claude-opus-4-6" }, + "fallback-test": { model: "anthropic/claude-opus-4-7" }, }, connectedProvidersOverride: TEST_CONNECTED_PROVIDERS, availableModelsOverride: createTestAvailableModels(), @@ -3465,7 +3465,7 @@ describe("sisyphus-task", () => { test("category built-in model takes precedence over inheritedModel for builtin category", () => { // given - builtin ultrabrain category with its own model, inherited model also provided const categoryName = "ultrabrain" - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const resolved = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3480,7 +3480,7 @@ describe("sisyphus-task", () => { // given const categoryName = "ultrabrain" const userCategories = { "ultrabrain": { model: "my-provider/custom-model" } } - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3497,7 +3497,7 @@ describe("sisyphus-task", () => { // given - This test verifies the fix for PR #770 bug // The bug was: checking `if (inheritedModel)` instead of `if (actualModel === inheritedModel)` const categoryName = "ultrabrain" - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" const userCategories = { "ultrabrain": { model: "user/model" } } // when - user model wins @@ -3525,7 +3525,7 @@ describe("sisyphus-task", () => { // given a builtin category with its own model, and an inherited model from parent // The CORRECT chain: userConfig?.model ?? categoryBuiltIn ?? systemDefaultModel const categoryName = "ultrabrain" - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" // when category has a built-in model (gpt-5.4 for ultrabrain) const resolved = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3556,7 +3556,7 @@ describe("sisyphus-task", () => { // given userConfig.model is explicitly set const categoryName = "ultrabrain" const userCategories = { "ultrabrain": { model: "custom/user-model" } } - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" const systemDefaultModel = "anthropic/claude-sonnet-4-6" // when resolveCategoryConfig is called with all sources @@ -3575,7 +3575,7 @@ describe("sisyphus-task", () => { // given userConfig.model is empty string "" for a custom category (no built-in model) const categoryName = "custom-empty-model" const userCategories = { "custom-empty-model": { model: "", temperature: 0.3 } } - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" // when resolveCategoryConfig is called const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3590,7 +3590,7 @@ describe("sisyphus-task", () => { const categoryName = "visual-engineering" // Using type assertion since we're testing fallback behavior for categories without model const userCategories = { "visual-engineering": { temperature: 0.2 } } as unknown as Record - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" // when resolveCategoryConfig is called const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3810,7 +3810,7 @@ describe("sisyphus-task", () => { app: { agents: async () => ({ data: [ - { name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-6" } }, + { name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-7" } }, ], }), }, @@ -3854,7 +3854,7 @@ describe("sisyphus-task", () => { // then - matched agent's model should be passed to session.prompt expect(promptBody.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) }, { timeout: 20000 }) @@ -3956,7 +3956,7 @@ describe("sisyphus-task", () => { manager: mockManager, client: mockClient, agentOverrides: { - oracle: { model: "anthropic/claude-opus-4-6" }, + oracle: { model: "anthropic/claude-opus-4-7" }, }, }) @@ -3982,7 +3982,7 @@ describe("sisyphus-task", () => { // then - user-configured model should take priority over matchedAgent.model expect(promptBody.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) }, { timeout: 20000 }) @@ -4023,7 +4023,7 @@ describe("sisyphus-task", () => { manager: mockManager, client: mockClient, agentOverrides: { - oracle: { model: "anthropic/claude-opus-4-6", variant: "max" }, + oracle: { model: "anthropic/claude-opus-4-7", variant: "max" }, }, }) @@ -4111,7 +4111,7 @@ describe("sisyphus-task", () => { ) // then - should resolve via AGENT_MODEL_REQUIREMENTS fallback chain for oracle - // oracle fallback chain: gpt-5.4 (openai) > gemini-3.1-pro (google) > claude-opus-4-6 (anthropic) + // oracle fallback chain: gpt-5.4 (openai) > gemini-3.1-pro (google) > claude-opus-4-7 (anthropic) // Since openai is in connectedProviders, should resolve to openai/gpt-5.4 expect(promptBody.model).toBeDefined() expect(promptBody.model.providerID).toBe("openai") From 4ca4c06698f52a7664a25cc1c2248ddddcbb455e Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 14:52:02 +0900 Subject: [PATCH 023/146] refactor(migration): auto-upgrade claude-opus-4-5 and 4-6 to claude-opus-4-7 MODEL_VERSION_MAP now chains the legacy claude-opus-4-5 entry straight to claude-opus-4-7 and adds an explicit claude-opus-4-6 to 4-7 bump path, letting existing user configs upgrade on next load without an intermediate 4-6 stop. MODEL_TO_CATEGORY_MAP picks up claude-opus-4-7 as the canonical unspecified-high model (prior 4-6 entry is covered by the chained version map above, so legacy hardcoded configs still resolve). Migration tests rewritten to reflect the chained 4-5 to 4-7 behavior and the new 4-6 to 4-7 bump path, including the sidecar-union scenario. --- src/shared/migration.test.ts | 54 +++++++++---------- src/shared/migration/agent-category.ts | 2 +- src/shared/migration/config-migration.test.ts | 12 ++--- .../migration/migrations-sidecar.test.ts | 6 +-- src/shared/migration/migrations-sidecar.ts | 2 +- src/shared/migration/model-versions.ts | 3 +- 6 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/shared/migration.test.ts b/src/shared/migration.test.ts index e0b5f2808..072858d7c 100644 --- a/src/shared/migration.test.ts +++ b/src/shared/migration.test.ts @@ -19,7 +19,7 @@ describe("migrateAgentNames", () => { test("migrates legacy OmO names to lowercase", () => { // given: Config with legacy OmO agent names const agents = { - omo: { model: "anthropic/claude-opus-4-6" }, + omo: { model: "anthropic/claude-opus-4-7" }, OmO: { temperature: 0.5 }, "OmO-Plan": { prompt: "custom prompt" }, } @@ -88,7 +88,7 @@ describe("migrateAgentNames", () => { test("migrates orchestrator-sisyphus to atlas", () => { // given: Config with legacy orchestrator-sisyphus agent name const agents = { - "orchestrator-sisyphus": { model: "anthropic/claude-opus-4-6" }, + "orchestrator-sisyphus": { model: "anthropic/claude-opus-4-7" }, } // when: Migrate agent names @@ -96,14 +96,14 @@ describe("migrateAgentNames", () => { // then: orchestrator-sisyphus should be migrated to atlas expect(changed).toBe(true) - expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-7" }) expect(migrated["orchestrator-sisyphus"]).toBeUndefined() }) test("migrates lowercase atlas to atlas", () => { // given: Config with lowercase atlas agent name const agents = { - atlas: { model: "anthropic/claude-opus-4-6" }, + atlas: { model: "anthropic/claude-opus-4-7" }, } // when: Migrate agent names @@ -111,7 +111,7 @@ describe("migrateAgentNames", () => { // then: lowercase atlas should remain atlas (no change needed) expect(changed).toBe(false) - expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-7" }) }) test("migrates Sisyphus variants to lowercase", () => { @@ -524,7 +524,7 @@ describe("migrateConfigFile", () => { // then: Model version should be migrated expect(needsWrite).toBe(true) const categories = rawConfig.categories as Record> - expect(categories["my-category"].model).toBe("anthropic/claude-opus-4-6") + expect(categories["my-category"].model).toBe("anthropic/claude-opus-4-7") }) test("does not set needsWrite when no model versions need migration", () => { @@ -534,7 +534,7 @@ describe("migrateConfigFile", () => { sisyphus: { model: "openai/gpt-5.4-codex" }, }, categories: { - "my-category": { model: "anthropic/claude-opus-4-6" }, + "my-category": { model: "anthropic/claude-opus-4-7" }, }, } @@ -572,10 +572,10 @@ describe("MODEL_VERSION_MAP", () => { expect(MODEL_VERSION_MAP["openai/gpt-5.4-codex"]).toBeUndefined() }) - test("maps anthropic/claude-opus-4-5 to anthropic/claude-opus-4-6", () => { + test("maps anthropic/claude-opus-4-5 to anthropic/claude-opus-4-7", () => { // given/when: Check MODEL_VERSION_MAP // then: Should contain correct mapping - expect(MODEL_VERSION_MAP["anthropic/claude-opus-4-5"]).toBe("anthropic/claude-opus-4-6") + expect(MODEL_VERSION_MAP["anthropic/claude-opus-4-5"]).toBe("anthropic/claude-opus-4-7") }) test("maps openai/gpt-5.3-codex to openai/gpt-5.4 for deep category migration", () => { @@ -614,7 +614,7 @@ describe("migrateModelVersions", () => { // then: Model should be updated expect(changed).toBe(true) const prometheus = migrated["prometheus"] as Record - expect(prometheus.model).toBe("anthropic/claude-opus-4-6") + expect(prometheus.model).toBe("anthropic/claude-opus-4-7") }) test("leaves unknown model strings untouched", () => { @@ -674,7 +674,7 @@ describe("migrateModelVersions", () => { // then: Only mapped models should be updated expect(changed).toBe(true) expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.4-codex") - expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-6") + expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-7") expect((migrated["oracle"] as Record).model).toBe("openai/gpt-5.4") }) @@ -736,9 +736,9 @@ describe("migrateModelVersions", () => { // then: Only prometheus should be migrated expect(changed).toBe(true) - expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"]) + expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"]) expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.4-codex") - expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-6") + expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-7") }) test("backward compatible without appliedMigrations param", () => { @@ -820,12 +820,12 @@ describe("migrateConfigFile _migrations tracking", () => { // (legacy + new) is written to the sidecar file exactly once. expect(result).toBe(true) expect(rawConfig._migrations).toBeUndefined() - expect((rawConfig.agents as Record>).prometheus.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).prometheus.model).toBe("anthropic/claude-opus-4-7") const sidecar = JSON.parse(fs.readFileSync(`${configPath}.migrations.json`, "utf-8")) expect(new Set(sidecar.appliedMigrations)).toEqual(new Set([ "model-version:openai/gpt-5.4-codex->openai/gpt-5.3-codex", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ])) // cleanup @@ -890,7 +890,7 @@ describe("migrateAgentConfigToCategory", () => { { model: "google/gemini-3-flash" }, { model: "openai/gpt-5.4" }, { model: "anthropic/claude-haiku-4-5" }, - { model: "anthropic/claude-opus-4-6" }, + { model: "anthropic/claude-opus-4-7" }, { model: "anthropic/claude-sonnet-4-6" }, ] @@ -970,7 +970,7 @@ describe("shouldDeleteAgentConfig", () => { // given: Config with custom model override const config = { category: "visual-engineering", - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", } // when: Check if config should be deleted @@ -1245,9 +1245,9 @@ describe("migrateModelVersions with applied migrations", () => { // then: Skip sisyphus (already applied), apply oracle expect(changed).toBe(true) - expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"]) + expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"]) expect((migrated.sisyphus as Record).model).toBe("openai/gpt-5.4-codex") - expect((migrated.oracle as Record).model).toBe("anthropic/claude-opus-4-6") + expect((migrated.oracle as Record).model).toBe("anthropic/claude-opus-4-7") }) test("backward compatible: no appliedMigrations param", () => { @@ -1334,12 +1334,12 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => const needsWrite = migrateConfigFile(testConfigPath, rawConfig) expect(needsWrite).toBe(true) - expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-7") expect(rawConfig._migrations).toBeUndefined() const sidecar = JSON.parse(fs.readFileSync(sidecarPath(testConfigPath), "utf-8")) expect(sidecar.appliedMigrations).toEqual([ - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ]) }) @@ -1408,7 +1408,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => JSON.stringify({ appliedMigrations: [ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ], }), ) @@ -1416,7 +1416,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => agents: { oracle: { model: "anthropic/claude-opus-4-5" }, }, - _migrations: ["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"], + _migrations: ["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"], } fs.writeFileSync(testConfigPath, JSON.stringify(rawConfig, null, 2)) @@ -1430,7 +1430,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => const sidecar = JSON.parse(fs.readFileSync(sidecarPath(testConfigPath), "utf-8")) expect(sidecar.appliedMigrations).toEqual([ - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", ]) }) @@ -1460,13 +1460,13 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => // codex was reverted, must stay expect((rawConfig.agents as Record>).codex.model).toBe("openai/gpt-5.3-codex") // claude migrates - expect((rawConfig.agents as Record>).claude.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).claude.model).toBe("anthropic/claude-opus-4-7") expect(rawConfig._migrations).toBeUndefined() const sidecar = JSON.parse(fs.readFileSync(sidecarPath(testConfigPath), "utf-8")) expect(new Set(sidecar.appliedMigrations)).toEqual(new Set([ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ])) }) @@ -1494,7 +1494,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => expect(Array.isArray(migrations)).toBe(true) expect(migrations).toContain("model-version:openai/gpt-5.3-codex->openai/gpt-5.4") expect(migrations.length).toBeGreaterThanOrEqual(1) - expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-7") // Sidecar should not exist because write failed expect(fs.existsSync(sidecarPath(testConfigPath))).toBe(false) diff --git a/src/shared/migration/agent-category.ts b/src/shared/migration/agent-category.ts index 6f75682ca..9960cfca4 100644 --- a/src/shared/migration/agent-category.ts +++ b/src/shared/migration/agent-category.ts @@ -16,7 +16,7 @@ export const MODEL_TO_CATEGORY_MAP: Record = { "google/gemini-3-flash": "writing", "openai/gpt-5.4": "ultrabrain", "anthropic/claude-haiku-4-5": "quick", - "anthropic/claude-opus-4-6": "unspecified-high", + "anthropic/claude-opus-4-7": "unspecified-high", "anthropic/claude-sonnet-4-6": "unspecified-low", } diff --git a/src/shared/migration/config-migration.test.ts b/src/shared/migration/config-migration.test.ts index 35f8b574a..ff59d7ca3 100644 --- a/src/shared/migration/config-migration.test.ts +++ b/src/shared/migration/config-migration.test.ts @@ -8,7 +8,7 @@ import { migrateConfigFile } from "./config-migration" import { getSidecarPath } from "./migrations-sidecar" const createdDirectories: string[] = [] -const MIGRATION_KEY = "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6" +const MIGRATION_KEY = "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7" function createWorkdir(): string { const workdir = mkdtempSync(join(tmpdir(), "omo-config-migration-")) @@ -46,13 +46,13 @@ describe("migrateConfigFile sidecar write ordering", () => { expect(needsWrite).toBe(true) expect(rawConfig._migrations).toBeUndefined() expect((rawConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) const persistedConfig = JSON.parse(readFileSync(configPath, "utf-8")) as Record expect(persistedConfig._migrations).toBeUndefined() expect((persistedConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) const sidecar = JSON.parse(readFileSync(getSidecarPath(configPath), "utf-8")) as { @@ -87,7 +87,7 @@ describe("migrateConfigFile sidecar write ordering", () => { expect(retriedNeedsWrite).toBe(true) expect(retriedConfig._migrations).toBeUndefined() expect((retriedConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) expect(existsSync(getSidecarPath(configPath))).toBe(true) }) @@ -108,13 +108,13 @@ describe("migrateConfigFile sidecar write ordering", () => { expect(needsWrite).toBe(true) expect(rawConfig._migrations).toEqual([MIGRATION_KEY]) expect((rawConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) const persistedConfig = JSON.parse(readFileSync(configPath, "utf-8")) as Record expect(persistedConfig._migrations).toEqual([MIGRATION_KEY]) expect((persistedConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) expect(statSync(getSidecarPath(configPath)).isDirectory()).toBe(true) }) diff --git a/src/shared/migration/migrations-sidecar.test.ts b/src/shared/migration/migrations-sidecar.test.ts index 5809bde94..503ea9105 100644 --- a/src/shared/migration/migrations-sidecar.test.ts +++ b/src/shared/migration/migrations-sidecar.test.ts @@ -42,7 +42,7 @@ describe("migrations sidecar", () => { JSON.stringify({ appliedMigrations: [ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ], }), ) @@ -51,7 +51,7 @@ describe("migrations sidecar", () => { expect(applied.size).toBe(2) expect(applied.has("model-version:openai/gpt-5.3-codex->openai/gpt-5.4")).toBe(true) - expect(applied.has("model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6")).toBe(true) + expect(applied.has("model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7")).toBe(true) }) test("returns an empty set on malformed JSON instead of throwing", () => { @@ -134,7 +134,7 @@ describe("migrations sidecar", () => { const configPath = join(workdir, "oh-my-openagent.jsonc") const original = new Set([ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ]) writeAppliedMigrations(configPath, original) diff --git a/src/shared/migration/migrations-sidecar.ts b/src/shared/migration/migrations-sidecar.ts index cd0088922..0cbac7db1 100644 --- a/src/shared/migration/migrations-sidecar.ts +++ b/src/shared/migration/migrations-sidecar.ts @@ -22,7 +22,7 @@ import { writeFileAtomically } from "../write-file-atomically" * { * "appliedMigrations": [ * "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - * "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6" + * "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7" * ] * } */ diff --git a/src/shared/migration/model-versions.ts b/src/shared/migration/model-versions.ts index 13731dcaa..40aee07b3 100644 --- a/src/shared/migration/model-versions.ts +++ b/src/shared/migration/model-versions.ts @@ -6,7 +6,8 @@ * Keys are full "provider/model" strings. Only openai and anthropic entries needed. */ export const MODEL_VERSION_MAP: Record = { - "anthropic/claude-opus-4-5": "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-5": "anthropic/claude-opus-4-7", + "anthropic/claude-opus-4-6": "anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-5": "anthropic/claude-sonnet-4-6", "openai/gpt-5.3-codex": "openai/gpt-5.4", } From f34a074f12923e6e1cce3ef0bae86bcd5c6609f4 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 14:52:19 +0900 Subject: [PATCH 024/146] docs: bump claude-opus-4-6 to claude-opus-4-7 across docs, examples, and AGENTS.md Syncs the README translations, CONTRIBUTING, docs/reference, docs/guide, docs/examples JSONC configs, and the hierarchical src/**/AGENTS.md files with the model version bump already landed in the source and migration commits. --- CONTRIBUTING.md | 2 +- README.ja.md | 4 +-- README.ko.md | 4 +-- README.md | 4 +-- README.ru.md | 4 +-- README.zh-cn.md | 4 +-- docs/examples/coding-focused.jsonc | 2 +- docs/examples/default.jsonc | 6 ++-- docs/examples/planning-focused.jsonc | 10 +++---- docs/guide/agent-model-matching.md | 26 ++++++++-------- docs/guide/installation.md | 16 +++++----- docs/guide/orchestration.md | 24 +++++++-------- docs/guide/overview.md | 6 ++-- docs/reference/configuration.md | 40 ++++++++++++------------- docs/reference/features.md | 16 +++++----- src/agents/AGENTS.md | 10 +++---- src/features/background-agent/AGENTS.md | 2 +- src/tools/AGENTS.md | 2 +- 18 files changed, 91 insertions(+), 91 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e12993d1b..f1ae6e419 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -183,7 +183,7 @@ import type { AgentConfig } from "./types"; export const myAgent: AgentConfig = { name: "my-agent", - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", description: "Description of what this agent does", prompt: `Your agent's system prompt here`, temperature: 0.1, diff --git a/README.ja.md b/README.ja.md index af5d32400..a8fe8e1e1 100644 --- a/README.ja.md +++ b/README.ja.md @@ -170,11 +170,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu -**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。 +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。 **Hephaestus** (`gpt-5.4`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。 +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。 すべてのエージェントは、それぞれのモデルの強みに合わせてチューニングされています。手動でモデルを切り替える必要はありません。[詳しくはこちら →](docs/guide/overview.md) diff --git a/README.ko.md b/README.ko.md index cf1f60a83..1e3a8294f 100644 --- a/README.ko.md +++ b/README.ko.md @@ -164,11 +164,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu -**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다. +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다. **Hephaestus** (`gpt-5.4`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다. +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다. 모든 에이전트는 해당 모델의 특장점에 맞춰 튜닝되어 있습니다. 수동으로 모델 바꿔가며 뻘짓하지 마세요. [더 알아보기 →](docs/guide/overview.md) diff --git a/README.md b/README.md index 8aec143a3..8f7644cc3 100644 --- a/README.md +++ b/README.md @@ -166,11 +166,11 @@ Even only with following subscriptions, ultrawork will work well (this project i -**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway. +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway. **Hephaestus** (`gpt-5.4`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your strategic planner. Interview mode: it questions, identifies scope, and builds a detailed plan before a single line of code is touched. +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`** ) is your strategic planner. Interview mode: it questions, identifies scope, and builds a detailed plan before a single line of code is touched. Every agent is tuned to its model's specific strengths. No manual model-juggling. [Learn more →](docs/guide/overview.md) diff --git a/README.ru.md b/README.ru.md index f7564f8b1..65af04c3a 100644 --- a/README.ru.md +++ b/README.ru.md @@ -154,11 +154,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
-**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути. +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути. **Hephaestus** (`gpt-5.4`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода. +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода. Каждый агент настроен под сильные стороны своей модели. Никакого ручного переключения между моделями. Подробнее → diff --git a/README.zh-cn.md b/README.zh-cn.md index a3316541c..2d80093bd 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -171,11 +171,11 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu -**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。 +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。 **Hephaestus** (`gpt-5.4`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。 +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。 每一个 Agent 都针对其底层模型的特点进行了专门调优。你无需手动来回切换模型。[阅读背景设定了解更多 →](docs/guide/overview.md) diff --git a/docs/examples/coding-focused.jsonc b/docs/examples/coding-focused.jsonc index 5df5592bc..d697884f8 100644 --- a/docs/examples/coding-focused.jsonc +++ b/docs/examples/coding-focused.jsonc @@ -8,7 +8,7 @@ // Primary orchestrator: aggressive parallel delegation "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "prompt_append": "Delegate heavily to hephaestus for implementation. Parallelize exploration.", }, diff --git a/docs/examples/default.jsonc b/docs/examples/default.jsonc index d48f26e7d..160ef1405 100644 --- a/docs/examples/default.jsonc +++ b/docs/examples/default.jsonc @@ -7,8 +7,8 @@ "agents": { // Main orchestrator: handles delegation and drives tasks to completion "sisyphus": { - "model": "anthropic/claude-opus-4-6", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "model": "anthropic/claude-opus-4-7", + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Deep autonomous worker: end-to-end implementation @@ -50,7 +50,7 @@ "categories": { "quick": { "model": "opencode/gpt-5-nano" }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, - "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "writing": { "model": "google/gemini-3-flash" }, "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" }, "deep": { "model": "openai/gpt-5.4" }, diff --git a/docs/examples/planning-focused.jsonc b/docs/examples/planning-focused.jsonc index 48ab12c1b..407045244 100644 --- a/docs/examples/planning-focused.jsonc +++ b/docs/examples/planning-focused.jsonc @@ -7,8 +7,8 @@ "agents": { // Orchestrator: delegates to planning agents first "sisyphus": { - "model": "anthropic/claude-opus-4-6", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "model": "anthropic/claude-opus-4-7", + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "prompt_append": "Always consult prometheus and atlas for planning. Never rush to implementation.", }, @@ -20,7 +20,7 @@ // Primary planner: deep interview mode "prometheus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "thinking": { "type": "enabled", "budgetTokens": 160000 }, "prompt_append": "Interview extensively. Question assumptions. Build exhaustive plans with milestones, risks, and contingencies. Use deep & quick agents heavily in parallel for research.", }, @@ -43,7 +43,7 @@ // Plan review and refinement: heavily utilized "metis": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "prompt_append": "Critically evaluate plans. Identify gaps, risks, and improvements. Be thorough.", }, @@ -98,7 +98,7 @@ "openai": 3, }, "modelConcurrency": { - "anthropic/claude-opus-4-6": 2, + "anthropic/claude-opus-4-7": 2, "openai/gpt-5.4": 2, }, }, diff --git a/docs/guide/agent-model-matching.md b/docs/guide/agent-model-matching.md index 1d5cc103e..ecf9731ac 100644 --- a/docs/guide/agent-model-matching.md +++ b/docs/guide/agent-model-matching.md @@ -64,8 +64,8 @@ These agents have Claude-optimized prompts — long, detailed, mechanics-driven. | Agent | Role | Fallback Chain | Notes | | ------------ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- | -| **Sisyphus** | Main orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → zai-coding-plan\|opencode\|vercel/glm-5 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Metis** | Plan gap analyzer | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Sisyphus** | Main orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → zai-coding-plan\|opencode\|vercel/glm-5 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Metis** | Plan gap analyzer | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | Exact runtime chain from `src/shared/model-requirements.ts`. | ### Dual-Prompt Agents → Claude preferred, GPT supported @@ -73,7 +73,7 @@ These agents ship separate prompts for Claude and GPT families. They auto-detect | Agent | Role | Fallback Chain | Notes | | -------------- | ----------------- | -------------------------------------- | -------------------------------------------------------------------- | -| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 | Exact runtime chain from `src/shared/model-requirements.ts`. | ### Deep Specialists → GPT @@ -83,8 +83,8 @@ These agents are built for GPT's principle-driven style. Their prompts assume au | Agent | Role | Fallback Chain | Notes | | -------------- | ----------------------- | -------------------------------------- | ------------------------------------------------ | | **Hephaestus** | Autonomous deep worker | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) | Single-entry chain. Requires one of those providers. The craftsman. | -| **Oracle** | Architecture consultant | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Momus** | Ruthless reviewer | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Oracle** | Architecture consultant | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Momus** | Ruthless reviewer | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | ### Utility Runners → Speed over Intelligence @@ -169,12 +169,12 @@ When agents delegate work, they don't pick a model name — they pick a **catego | Category | When Used | Fallback Chain | | -------------------- | -------------------------- | -------------------------------------------- | -| `visual-engineering` | Frontend, UI, CSS, design | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → zai-coding-plan\|opencode\|vercel/glm-5 → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | -| `ultrabrain` | Maximum reasoning needed | openai\|opencode\|vercel/gpt-5.4 (xhigh) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 | -| `deep` | Deep coding, complex logic | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) | -| `artistry` | Creative, novel approaches | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 | +| `visual-engineering` | Frontend, UI, CSS, design | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → zai-coding-plan\|opencode\|vercel/glm-5 → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | +| `ultrabrain` | Maximum reasoning needed | openai\|opencode\|vercel/gpt-5.4 (xhigh) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 | +| `deep` | Deep coding, complex logic | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) | +| `artistry` | Creative, novel approaches | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 | | `quick` | Simple, fast tasks | openai\|github-copilot\|opencode\|vercel/gpt-5.4-mini → anthropic\|github-copilot\|opencode\|vercel/claude-haiku-4-5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 → opencode\|vercel/gpt-5-nano | -| `unspecified-high` | General complex work | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → zai-coding-plan\|opencode\|vercel/glm-5 → kimi-for-coding/k2p5 → opencode-go\|vercel/glm-5 → opencode\|vercel/kimi-k2.5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 | +| `unspecified-high` | General complex work | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → zai-coding-plan\|opencode\|vercel/glm-5 → kimi-for-coding/k2p5 → opencode-go\|vercel/glm-5 → opencode\|vercel/kimi-k2.5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 | | `unspecified-low` | General standard work | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → openai\|opencode\|vercel/gpt-5.3-codex (medium) → opencode-go\|vercel/kimi-k2.5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 | | `writing` | Text, docs, prose | google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/kimi-k2.5 → anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/minimax-m2.7 | @@ -198,7 +198,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch // Main orchestrator: Claude Opus or Kimi K2.5 work best "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Research agents: cheaper models are fine @@ -217,7 +217,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch "categories": { "quick": { "model": "opencode/gpt-5-nano" }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, - "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high", @@ -234,7 +234,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch "zai-coding-plan": 10, }, "modelConcurrency": { - "anthropic/claude-opus-4-6": 2, + "anthropic/claude-opus-4-7": 2, "opencode/gpt-5-nano": 20, }, }, diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 85aee5abf..ac00edcbf 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -225,7 +225,7 @@ When GitHub Copilot is the best available provider, install-time defaults are ag | Agent | Model | | ------------- | ---------------------------------- | -| **Sisyphus** | `github-copilot/claude-opus-4.6` | +| **Sisyphus** | `github-copilot/claude-opus-4.7` | | **Oracle** | `github-copilot/gpt-5.4` | | **Explore** | `github-copilot/grok-code-fast-1` | | **Atlas** | `github-copilot/claude-sonnet-4.6` | @@ -247,13 +247,13 @@ If Z.ai is your main provider, the most important fallbacks are: #### OpenCode Zen -OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-6`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, `opencode/minimax-m2.7`, and `opencode/minimax-m2.7-highspeed`. +OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-7`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, `opencode/minimax-m2.7`, and `opencode/minimax-m2.7-highspeed`. When OpenCode Zen is the best available provider, these are the most relevant source-backed examples: | Agent | Model | | ------------- | ---------------------------------------------------- | -| **Sisyphus** | `opencode/claude-opus-4-6` | +| **Sisyphus** | `opencode/claude-opus-4-7` | | **Oracle** | `opencode/gpt-5.4` | | **Explore** | `opencode/minimax-m2.7` | @@ -330,8 +330,8 @@ Based on your subscriptions, here's how the agents were configured: | Agent | Role | Default Chain | What It Does | | ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- | -| **Sisyphus** | Main ultraworker | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Primary coding agent. Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Metis** | Plan review | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Reviews Prometheus plans for gaps. Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Sisyphus** | Main ultraworker | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Primary coding agent. Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Metis** | Plan review | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Reviews Prometheus plans for gaps. Exact runtime chain from `src/shared/model-requirements.ts`. | **Dual-Prompt Agents** (auto-switch between Claude and GPT prompts): @@ -341,7 +341,7 @@ Priority: **Claude > GPT > Claude-like models** | Agent | Role | Default Chain | GPT Prompt? | | -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- | -| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) | +| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) | | **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → opencode-go/minimax-m2.7 | Yes - GPT-optimized todo management | **GPT-Native Agents** (built for GPT, don't override to Claude): @@ -349,8 +349,8 @@ Priority: **Claude > GPT > Claude-like models** | Agent | Role | Default Chain | Notes | | -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ | | **Hephaestus** | Deep autonomous worker | GPT-5.4 (medium) only | "Codex on steroids." No fallback. Requires GPT access. | -| **Oracle** | Architecture/debugging | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/glm-5 | High-IQ strategic backup. GPT preferred. | -| **Momus** | High-accuracy reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Verification agent. GPT preferred. | +| **Oracle** | Architecture/debugging | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → opencode-go/glm-5 | High-IQ strategic backup. GPT preferred. | +| **Momus** | High-accuracy reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Verification agent. GPT preferred. | **Utility Agents** (speed over intelligence): diff --git a/docs/guide/orchestration.md b/docs/guide/orchestration.md index 345ebce3b..0e21ce50a 100644 --- a/docs/guide/orchestration.md +++ b/docs/guide/orchestration.md @@ -35,9 +35,9 @@ The orchestration system uses a three-layer architecture that solves context ove flowchart TB subgraph Planning["Planning Layer (Human + Prometheus)"] User[(" User")] - Prometheus[" Prometheus
(Planner)
claude-opus-4-6 / gpt-5.4 / glm-5"] - Metis[" Metis
(Consultant)
claude-opus-4-6 / gpt-5.4 / glm-5"] - Momus[" Momus
(Reviewer)
gpt-5.4 / claude-opus-4-6 / gemini-3.1-pro / glm-5"] + Prometheus[" Prometheus
(Planner)
claude-opus-4-7 / gpt-5.4 / glm-5"] + Metis[" Metis
(Consultant)
claude-opus-4-7 / gpt-5.4 / glm-5"] + Momus[" Momus
(Reviewer)
gpt-5.4 / claude-opus-4-7 / gemini-3.1-pro / glm-5"] end subgraph Execution["Execution Layer (Orchestrator)"] @@ -46,10 +46,10 @@ flowchart TB subgraph Workers["Worker Layer (Specialized Agents)"] Junior[" Sisyphus-Junior
(Task Executor)
claude-sonnet-4-6 / kimi-k2.5 / gpt-5.4 / minimax-m2.7"] - Oracle[" Oracle
(Architecture)
gpt-5.4 / gemini-3.1-pro / claude-opus-4-6 / glm-5"] + Oracle[" Oracle
(Architecture)
gpt-5.4 / gemini-3.1-pro / claude-opus-4-7 / glm-5"] Explore[" Explore
(Codebase Grep)
grok-code-fast-1 / minimax-m2.7-highspeed / claude-haiku-4-5"] Librarian[" Librarian
(Docs/OSS)
minimax-m2.7 / minimax-m2.7-highspeed / claude-haiku-4-5"] - Frontend[" visual-engineering
(category + frontend-ui-ux)
gemini-3.1-pro / glm-5 / claude-opus-4-6"] + Frontend[" visual-engineering
(category + frontend-ui-ux)
gemini-3.1-pro / glm-5 / claude-opus-4-7"] end User -->|"Describe work"| Prometheus @@ -282,7 +282,7 @@ This "boulder pushing" mechanism is why the system is named after Sisyphus. ```typescript // OLD: Model name creates distributional bias task({ agent: "gpt-5.4", prompt: "..." }); // Model knows its limitations -task({ agent: "claude-opus-4-6", prompt: "..." }); // Different self-perception +task({ agent: "claude-opus-4-7", prompt: "..." }); // Different self-perception ``` **The Solution: Semantic Categories:** @@ -298,13 +298,13 @@ task({ category: "quick", prompt: "..." }); // "Just get it done fast" | Category | Default config | Runtime fallback order | When to Use | | -------------------- | ------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| `visual-engineering` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `glm-5` → `claude-opus-4-6` → `glm-5` → `k2p5` | Frontend, UI/UX, design, styling, animation | -| `ultrabrain` | `openai/gpt-5.4 xhigh` | `gpt-5.4` → `gemini-3.1-pro` → `claude-opus-4-6` → `glm-5` | Deep logical reasoning, complex architecture decisions | -| `deep` | `openai/gpt-5.4 medium` | `gpt-5.4` → `claude-opus-4-6` → `gemini-3.1-pro` | Goal-oriented autonomous problem-solving, thorough research | -| `artistry` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `claude-opus-4-6` → `gpt-5.4` | Highly creative or artistic tasks, novel ideas | +| `visual-engineering` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `glm-5` → `claude-opus-4-7` → `glm-5` → `k2p5` | Frontend, UI/UX, design, styling, animation | +| `ultrabrain` | `openai/gpt-5.4 xhigh` | `gpt-5.4` → `gemini-3.1-pro` → `claude-opus-4-7` → `glm-5` | Deep logical reasoning, complex architecture decisions | +| `deep` | `openai/gpt-5.4 medium` | `gpt-5.4` → `claude-opus-4-7` → `gemini-3.1-pro` | Goal-oriented autonomous problem-solving, thorough research | +| `artistry` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `claude-opus-4-7` → `gpt-5.4` | Highly creative or artistic tasks, novel ideas | | `quick` | `openai/gpt-5.4-mini` | `gpt-5.4-mini` → `claude-haiku-4-5` → `gemini-3-flash` → `minimax-m2.7` → `gpt-5-nano` | Trivial tasks, single file changes, typo fixes | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | `claude-sonnet-4-6` → `gpt-5.3-codex` → `kimi-k2.5` → `gemini-3-flash` → `minimax-m2.7` | Tasks that don't fit other categories, low effort | -| `unspecified-high` | `anthropic/claude-opus-4-6 max` | `claude-opus-4-6` → `gpt-5.4` → `glm-5` → `k2p5` → `kimi-k2.5` | Tasks that don't fit other categories, high effort | +| `unspecified-high` | `anthropic/claude-opus-4-7 max` | `claude-opus-4-7` → `gpt-5.4` → `glm-5` → `k2p5` → `kimi-k2.5` | Tasks that don't fit other categories, high effort | | `writing` | `kimi-for-coding/k2p5` | `gemini-3-flash` → `kimi-k2.5` → `claude-sonnet-4-6` → `minimax-m2.7` | Documentation, prose, technical writing | ### Skills: Domain-Specific Instructions @@ -423,7 +423,7 @@ Atlas is automatically activated when you run `/start-work`. You don't need to m | Aspect | Hephaestus | Sisyphus + `ulw` / `ultrawork` | | --------------- | ------------------------------------------ | ---------------------------------------------------- | -| **Model** | `gpt-5.4` (`medium`) | `claude-opus-4-6` / `kimi-k2.5` / `gpt-5.4` / `glm-5` depending on setup | +| **Model** | `gpt-5.4` (`medium`) | `claude-opus-4-7` / `kimi-k2.5` / `gpt-5.4` / `glm-5` depending on setup | | **Approach** | Autonomous deep worker | Keyword-activated ultrawork mode | | **Best For** | Complex architectural work, deep reasoning | General complex tasks, "just do it" scenarios | | **Planning** | Self-plans during execution | Uses Prometheus plans if available | diff --git a/docs/guide/overview.md b/docs/guide/overview.md index 5e4501920..37720a1e6 100644 --- a/docs/guide/overview.md +++ b/docs/guide/overview.md @@ -173,7 +173,7 @@ You can override specific agents or categories in your config: // Main orchestrator: Claude Opus or Kimi K2.5 work best "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Research agents: cheaper models are fine @@ -207,10 +207,10 @@ You can override specific agents or categories in your config: "unspecified-low": { "model": "openai/gpt-5.4-mini" }, // High-effort fallback: best available - "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, // Prose and documentation - "writing": { "model": "anthropic/claude-opus-4-6", "variant": "high" }, + "writing": { "model": "anthropic/claude-opus-4-7", "variant": "high" }, }, } ``` diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index d37b9104b..04f510b6d 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -78,7 +78,7 @@ Here's a practical starting configuration: // Main orchestrator: Claude Opus or Kimi K2.5 work best "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Research agents: cheap fast models are fine @@ -102,7 +102,7 @@ Here's a practical starting configuration: "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, // unspecified-high - complex work - "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, // writing - docs/prose "writing": { "model": "google/gemini-3-flash" }, @@ -130,7 +130,7 @@ Here's a practical starting configuration: "zai-coding-plan": 10, }, "modelConcurrency": { - "anthropic/claude-opus-4-6": 2, + "anthropic/claude-opus-4-7": 2, "opencode/gpt-5-nano": 20, }, }, @@ -229,7 +229,7 @@ Control what tools an agent can use: { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ // Simple string fallback "openai/gpt-5.4", @@ -293,7 +293,7 @@ Domain-specific model delegation used by the `task()` tool. When Sisyphus delega | `artistry` | `google/gemini-3.1-pro` (high) | Creative/unconventional approaches | | `quick` | `openai/gpt-5.4-mini` | Trivial tasks, typo fixes, single-file changes | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | General tasks, low effort | -| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | General tasks, high effort | +| `unspecified-high` | `anthropic/claude-opus-4-7` (max) | General tasks, high effort | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | > **Note**: Built-in defaults only apply if the category is present in your config. Otherwise the system default model is used. @@ -355,28 +355,28 @@ Capability data comes from provider runtime metadata first. OmO also ships bundl | Agent | Default Model | Provider Priority | | --------------------- | ------------------- | ---------------------------------------------------------------------------- | -| **Sisyphus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle` | +| **Sisyphus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle` | | **Hephaestus** | `gpt-5.4` | `gpt-5.4 (medium)` | -| **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5` | +| **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` | | **librarian** | `minimax-m2.7` | `opencode-go/minimax-m2.7` → `opencode/minimax-m2.7-highspeed` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano` | | **explore** | `grok-code-fast-1` | `github-copilot\|xai/grok-code-fast-1` → `opencode-go/minimax-m2.7-highspeed` → `opencode/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano` | | **multimodal-looker** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (medium)` → `opencode-go/kimi-k2.5` → `zai-coding-plan/glm-4.6v` → `openai\|github-copilot\|opencode/gpt-5-nano` | -| **Prometheus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro` | -| **Metis** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | -| **Momus** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (xhigh)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5` | +| **Prometheus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro` | +| **Metis** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | +| **Momus** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (xhigh)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5` | | **Atlas** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6` → `opencode-go/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `opencode-go/minimax-m2.7` | #### Category Provider Chains | Category | Default Model | Provider Priority | | ---------------------- | ------------------- | -------------------------------------------------------------- | -| **visual-engineering** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `zai-coding-plan\|opencode/glm-5` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | -| **ultrabrain** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (xhigh)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5` | -| **deep** | `gpt-5.4` | `openai\|github-copilot\|venice\|opencode/gpt-5.4 (medium)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` | -| **artistry** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4` | +| **visual-engineering** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `zai-coding-plan\|opencode/glm-5` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | +| **ultrabrain** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (xhigh)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` | +| **deep** | `gpt-5.4` | `openai\|github-copilot\|venice\|opencode/gpt-5.4 (medium)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` | +| **artistry** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4` | | **quick** | `gpt-5.4-mini` | `openai\|github-copilot\|opencode/gpt-5.4-mini` → `anthropic\|github-copilot\|opencode/claude-haiku-4-5` → `google\|github-copilot\|opencode/gemini-3-flash` → `opencode-go/minimax-m2.7` → `opencode/gpt-5-nano` | | **unspecified-low** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6` → `openai\|opencode/gpt-5.3-codex (medium)` → `opencode-go/kimi-k2.5` → `google\|github-copilot\|opencode/gemini-3-flash` → `opencode-go/minimax-m2.7` | -| **unspecified-high** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `zai-coding-plan\|opencode/glm-5` → `kimi-for-coding/k2p5` → `opencode-go/glm-5` → `opencode/kimi-k2.5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` | +| **unspecified-high** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `zai-coding-plan\|opencode/glm-5` → `kimi-for-coding/k2p5` → `opencode-go/glm-5` → `opencode/kimi-k2.5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` | | **writing** | `gemini-3-flash` | `google\|github-copilot\|opencode/gemini-3-flash` → `opencode-go/kimi-k2.5` → `anthropic\|github-copilot\|opencode/claude-sonnet-4-6` → `opencode-go/minimax-m2.7` | Run `bunx oh-my-opencode doctor --verbose` to see effective model resolution for your config. @@ -395,7 +395,7 @@ Control parallel agent execution and concurrency limits. "defaultConcurrency": 5, "staleTimeoutMs": 180000, "providerConcurrency": { "anthropic": 3, "openai": 5, "google": 10 }, - "modelConcurrency": { "anthropic/claude-opus-4-6": 2 } + "modelConcurrency": { "anthropic/claude-opus-4-7": 2 } } } ``` @@ -678,7 +678,7 @@ Define `fallback_models` per agent or category: { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ "openai/gpt-5.4", { @@ -697,7 +697,7 @@ Define `fallback_models` per agent or category: { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ "openai/gpt-5.4", { @@ -798,7 +798,7 @@ Mix string entries and object entries when only some fallback models need specia { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ "openai/gpt-5.4", { @@ -832,7 +832,7 @@ Mix string entries and object entries when only some fallback models need specia "maxTokens": 12000 }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", "temperature": 0.2 }, diff --git a/docs/reference/features.md b/docs/reference/features.md index d79c11ec1..366554b6c 100644 --- a/docs/reference/features.md +++ b/docs/reference/features.md @@ -10,9 +10,9 @@ Core-agent tab cycling is deterministic via injected runtime order field. The fi | Agent | Model | Purpose | | --------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Sisyphus** | `claude-opus-4-6` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle`. | +| **Sisyphus** | `claude-opus-4-7` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle`. | | **Hephaestus** | `gpt-5.4` | The Legitimate Craftsman. Autonomous deep worker inspired by AmpCode's deep mode. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end without premature stopping. Named after the Greek god of forge and craftsmanship. Requires a GPT-capable provider. | -| **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5`. | +| **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5`. | | **Librarian** | `minimax-m2.7` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode/minimax-m2.7-highspeed` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano`. | | **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed` → `opencode/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano`. | | **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `opencode-go/kimi-k2.5` → `zai-coding-plan/glm-4.6v` → `openai\|github-copilot\|opencode/gpt-5-nano`. | @@ -20,9 +20,9 @@ Core-agent tab cycling is deterministic via injected runtime order field. The fi | Agent | Model | Purpose | | -------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Prometheus** | `claude-opus-4-6` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro`. | -| **Metis** | `claude-opus-4-6` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5`. | -| **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5`. | +| **Prometheus** | `claude-opus-4-7` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro`. | +| **Metis** | `claude-opus-4-7` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5`. | +| **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5`. | ### Orchestration Agents @@ -115,7 +115,7 @@ By combining these two concepts, you can generate optimal agents through `task`. | `artistry` | `google/gemini-3.1-pro` (high) | Highly creative/artistic tasks, novel ideas | | `quick` | `openai/gpt-5.4-mini` | Trivial tasks - single file changes, typo fixes, simple modifications | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | Tasks that don't fit other categories, low effort required | -| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | Tasks that don't fit other categories, high effort required | +| `unspecified-high` | `anthropic/claude-opus-4-7` (max) | Tasks that don't fit other categories, high effort required | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | ### Usage @@ -138,7 +138,7 @@ You can define custom categories in your plugin config file. During the rename t | Field | Type | Description | | ------------------- | ------- | --------------------------------------------------------------------------- | | `description` | string | Human-readable description of the category's purpose. Shown in task prompt. | -| `model` | string | AI model ID to use (e.g., `anthropic/claude-opus-4-6`) | +| `model` | string | AI model ID to use (e.g., `anthropic/claude-opus-4-7`) | | `variant` | string | Model variant (e.g., `max`, `xhigh`) | | `temperature` | number | Creativity level (0.0 ~ 2.0). Lower is more deterministic. | | `top_p` | number | Nucleus sampling parameter (0.0 ~ 1.0) | @@ -170,7 +170,7 @@ You can define custom categories in your plugin config file. During the rename t // 3. Configure thinking model and restrict tools "deep-reasoning": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "thinking": { "type": "enabled", "budgetTokens": 32000, diff --git a/src/agents/AGENTS.md b/src/agents/AGENTS.md index 137658b1f..03bfd5b1b 100644 --- a/src/agents/AGENTS.md +++ b/src/agents/AGENTS.md @@ -10,16 +10,16 @@ Agent factories following `createXXXAgent(model) → AgentConfig` pattern. Each | Agent | Model | Temp | Mode | Fallback Chain | Purpose | |-------|-------|------|------|----------------|---------| -| **Sisyphus** | claude-opus-4-6 max | 0.1 | all | k2p5 -> kimi-k2.5 -> gpt-5.4 medium -> glm-5 -> big-pickle | Main orchestrator, plans + delegates | +| **Sisyphus** | claude-opus-4-7 max | 0.1 | all | k2p5 -> kimi-k2.5 -> gpt-5.4 medium -> glm-5 -> big-pickle | Main orchestrator, plans + delegates | | **Hephaestus** | gpt-5.4 medium | 0.1 | all | — | Autonomous deep worker | -| **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high -> claude-opus-4-6 max | Read-only consultation | +| **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high -> claude-opus-4-7 max | Read-only consultation | | **Librarian** | minimax-m2.7 | 0.1 | subagent | minimax-m2.7-highspeed -> claude-haiku-4-5 -> gpt-5-nano | External docs/code search | | **Explore** | grok-code-fast-1 | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5-nano | Contextual grep | | **Multimodal-Looker** | gpt-5.3-codex medium | 0.1 | subagent | k2p5 -> gemini-3-flash -> glm-4.6v -> gpt-5-nano | PDF/image analysis | -| **Metis** | claude-opus-4-6 max | **0.3** | subagent | gpt-5.4 high -> gemini-3.1-pro high | Pre-planning consultant | -| **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-6 max -> gemini-3.1-pro high | Plan reviewer | +| **Metis** | claude-opus-4-7 max | **0.3** | subagent | gpt-5.4 high -> gemini-3.1-pro high | Pre-planning consultant | +| **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-7 max -> gemini-3.1-pro high | Plan reviewer | | **Atlas** | claude-sonnet-4-6 | 0.1 | primary | gpt-5.4 medium | Todo-list orchestrator | -| **Prometheus** | claude-opus-4-6 max | 0.1 | — | internal planner | Strategic planner (internal) | +| **Prometheus** | claude-opus-4-7 max | 0.1 | — | internal planner | Strategic planner (internal) | | **Sisyphus-Junior** | claude-sonnet-4-6 | 0.1 | all | user-configurable | Category-spawned executor | ## TOOL RESTRICTIONS diff --git a/src/features/background-agent/AGENTS.md b/src/features/background-agent/AGENTS.md index bac2302fe..6c6761eee 100644 --- a/src/features/background-agent/AGENTS.md +++ b/src/features/background-agent/AGENTS.md @@ -44,7 +44,7 @@ Both must agree before marking a task complete. Prevents premature completion on ## CONCURRENCY MODEL -- Key format: `{providerID}/{modelID}` (e.g., `anthropic/claude-opus-4-6`) +- Key format: `{providerID}/{modelID}` (e.g., `anthropic/claude-opus-4-7`) - Default limit: 5 concurrent per key (configurable via `background_task` config) - FIFO queue: tasks wait in order when slots full - Slot released on: completion, error, cancellation diff --git a/src/tools/AGENTS.md b/src/tools/AGENTS.md index 6c69183cf..a4b51ce22 100644 --- a/src/tools/AGENTS.md +++ b/src/tools/AGENTS.md @@ -97,7 +97,7 @@ | artistry | gemini-3.1-pro high | Creative approaches | | quick | gpt-5.4-mini | Trivial tasks | | unspecified-low | claude-sonnet-4-6 | Moderate effort | -| unspecified-high | claude-opus-4-6 max | High effort | +| unspecified-high | claude-opus-4-7 max | High effort | | writing | gemini-3-flash | Documentation | ## HOW TO ADD A TOOL From 5478bab4578440977235b641cb9a57362600e49f Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 15:35:11 +0900 Subject: [PATCH 025/146] refactor(models): preserve legacy claude-opus-4-6 aliases and category mapping Addresses review feedback on #3486: 1. claude-thinking-legacy-alias now matches both claude-opus-4-6-thinking and claude-opus-4-7-thinking, canonicalizing both to claude-opus-4-7. The previous diff retargeted the regex to 4-7 only, which dropped backward compatibility for users still pinned to the 4-6 thinking suffix. 2. MODEL_TO_CATEGORY_MAP keeps the claude-opus-4-6 to unspecified-high entry alongside the new 4-7 entry. The map is order-independent from MODEL_VERSION_MAP, so preserving the 4-6 key avoids relying on a specific migration ordering for legacy agent configs. 3. Fix stale 'Claude Opus 4.6' labels and BDD test comments that the sed-based bump missed. --- src/hooks/think-mode/switcher.test.ts | 2 +- src/shared/connected-providers-cache.test.ts | 4 ++-- src/shared/migration/agent-category.ts | 1 + src/shared/model-capability-aliases.ts | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hooks/think-mode/switcher.test.ts b/src/hooks/think-mode/switcher.test.ts index 94b5f115c..b462e76ff 100644 --- a/src/hooks/think-mode/switcher.test.ts +++ b/src/hooks/think-mode/switcher.test.ts @@ -38,7 +38,7 @@ describe("think-mode switcher", () => { }) it("should handle claude-opus-4-7 high variant", () => { - // given a Claude Opus 4.6 model ID + // given a Claude Opus 4.7 model ID const variant = getHighVariant("claude-opus-4-7") // then should return high variant diff --git a/src/shared/connected-providers-cache.test.ts b/src/shared/connected-providers-cache.test.ts index 7d3a7d780..36abdac26 100644 --- a/src/shared/connected-providers-cache.test.ts +++ b/src/shared/connected-providers-cache.test.ts @@ -61,7 +61,7 @@ describe("updateConnectedProvidersCache", () => { name: "Anthropic", env: [], models: { - "claude-opus-4-7": { id: "claude-opus-4-7", name: "Claude Opus 4.6" }, + "claude-opus-4-7": { id: "claude-opus-4-7", name: "Claude Opus 4.7" }, "claude-sonnet-4-6": { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, }, }, @@ -84,7 +84,7 @@ describe("updateConnectedProvidersCache", () => { { id: "gpt-5.4", name: "GPT-5.4" }, ], anthropic: [ - { id: "claude-opus-4-7", name: "Claude Opus 4.6" }, + { id: "claude-opus-4-7", name: "Claude Opus 4.7" }, { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, ], }) diff --git a/src/shared/migration/agent-category.ts b/src/shared/migration/agent-category.ts index 9960cfca4..f3ddf291a 100644 --- a/src/shared/migration/agent-category.ts +++ b/src/shared/migration/agent-category.ts @@ -16,6 +16,7 @@ export const MODEL_TO_CATEGORY_MAP: Record = { "google/gemini-3-flash": "writing", "openai/gpt-5.4": "ultrabrain", "anthropic/claude-haiku-4-5": "quick", + "anthropic/claude-opus-4-6": "unspecified-high", "anthropic/claude-opus-4-7": "unspecified-high", "anthropic/claude-sonnet-4-6": "unspecified-low", } diff --git a/src/shared/model-capability-aliases.ts b/src/shared/model-capability-aliases.ts index 01c7a23ba..fe7ef6b3b 100644 --- a/src/shared/model-capability-aliases.ts +++ b/src/shared/model-capability-aliases.ts @@ -41,8 +41,8 @@ const EXACT_ALIAS_RULES_BY_MODEL: ReadonlyMap = new Map( const PATTERN_ALIAS_RULES: ReadonlyArray = [ { ruleID: "claude-thinking-legacy-alias", - description: "Normalizes the legacy Claude Opus 4.6 thinking suffix to the canonical snapshot ID.", - match: (normalizedModelID) => /^claude-opus-4-7-thinking$/.test(normalizedModelID), + description: "Normalizes legacy Claude Opus thinking suffixes (4-6, 4-7) to the canonical snapshot ID.", + match: (normalizedModelID) => /^claude-opus-4-(?:6|7)-thinking$/.test(normalizedModelID), canonicalize: () => "claude-opus-4-7", }, { From b3beea129ca0c5cec189eda259a101cd3b11b4b5 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 15:35:22 +0900 Subject: [PATCH 026/146] docs: complete claude-opus-4-7 bump in installation, matching, and overview guides Sed-based bulk replace only touched hyphenated IDs (claude-opus-4-6) but the tutorial prose and comparison tables used the dotted human form 'Claude Opus 4.6' / 'Opus 4.6'. Sync those occurrences to 4.7 in: - docs/guide/installation.md (model families table + Sisyphus tutorial) - docs/guide/agent-model-matching.md (recommended-model table) - docs/guide/overview.md (three references to Opus default) Without this commit, users following the installation guide would be told Sisyphus 'strongly recommends Opus 4.6' while the plugin itself already routes to Opus 4.7. --- docs/guide/agent-model-matching.md | 2 +- docs/guide/installation.md | 4 ++-- docs/guide/overview.md | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/guide/agent-model-matching.md b/docs/guide/agent-model-matching.md index ecf9731ac..8c750a9b2 100644 --- a/docs/guide/agent-model-matching.md +++ b/docs/guide/agent-model-matching.md @@ -107,7 +107,7 @@ Communicative, instruction-following, structured output. Best for agents that ne | Model | Strengths | | --------------------- | ---------------------------------------------------------------------------- | -| **Claude Opus 4.6** | Best overall. Highest compliance with complex prompts. Default for Sisyphus. | +| **Claude Opus 4.7** | Best overall. Highest compliance with complex prompts. Default for Sisyphus. | | **Claude Sonnet 4.6** | Faster, cheaper. Good balance for everyday tasks. | | **Claude Haiku 4.5** | Fast and cheap. Good for quick tasks and utility work. | | **Kimi K2.5** | Behaves very similarly to Claude. Great all-rounder at lower cost. | diff --git a/docs/guide/installation.md b/docs/guide/installation.md index ac00edcbf..582b5d8ba 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -287,7 +287,7 @@ Not all models behave the same way. Understanding which models are "similar" hel | Model | Provider(s) | Notes | | ------------------------ | ----------------------------------- | ----------------------------------------------------------------------- | -| **Claude Opus 4.6** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. | +| **Claude Opus 4.7** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. | | **Claude Sonnet 4.6** | anthropic, github-copilot, opencode | Faster, cheaper. Good balance. | | **Claude Haiku 4.5** | anthropic, opencode | Fast and cheap. Good for quick tasks. | | **Kimi K2.5** | kimi-for-coding, opencode-go, opencode, moonshotai, moonshotai-cn, firmware, ollama-cloud, aihubmix | Behaves very similarly to Claude. Great all-rounder that appears in several orchestration fallback chains. | @@ -463,7 +463,7 @@ gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-openagent >/dev/nu Tell the user of following: -1. **Sisyphus agent strongly recommends Opus 4.6 model. Using other models may result in significantly degraded experience.** +1. **Sisyphus agent strongly recommends Opus 4.7 model. Using other models may result in significantly degraded experience.** 2. **Feeling lazy?** Just include `ultrawork` (or `ulw`) in your prompt. That's it. The agent figures out the rest. diff --git a/docs/guide/overview.md b/docs/guide/overview.md index 37720a1e6..cf1bb783c 100644 --- a/docs/guide/overview.md +++ b/docs/guide/overview.md @@ -82,11 +82,11 @@ Sisyphus is your main orchestrator. He plans, delegates to specialists, and driv **Recommended models:** -- **Claude Opus 4.6** — Best overall experience. Sisyphus was built with Claude-optimized prompts. +- **Claude Opus 4.7** — Best overall experience. Sisyphus was built with Claude-optimized prompts. - **Kimi K2.5** — Great Claude-like alternative. Many users run this combo exclusively. - **GLM 5** — Solid option, especially via Z.ai. -Sisyphus works best on Claude Opus 4.6, Kimi K2.5, and GLM 5. GPT-5.4 now has a dedicated prompt path, but older GPT models are still a poor fit and should route to Hephaestus instead. +Sisyphus works best on Claude Opus 4.7, Kimi K2.5, and GLM 5. GPT-5.4 now has a dedicated prompt path, but older GPT models are still a poor fit and should route to Hephaestus instead. ### Hephaestus: The Legitimate Craftsman @@ -219,7 +219,7 @@ You can override specific agents or categories in your config: **Claude-like models** (instruction-following, structured output): -- Claude Opus 4.6, Claude Haiku 4.5 +- Claude Opus 4.7, Claude Haiku 4.5 - Kimi K2.5 — behaves very similarly to Claude - GLM 5 — Claude-like behavior, good for broad tasks From 73f09fdb37deed2056a9309a851846daef2401f7 Mon Sep 17 00:00:00 2001 From: chan1103 Date: Fri, 17 Apr 2026 16:42:43 +0900 Subject: [PATCH 027/146] fix(explore): allow LSP and ast-grep tools --- src/agents/explore.ts | 11 ++++------- src/shared/permission-compat.ts | 10 ++++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/agents/explore.ts b/src/agents/explore.ts index c62cc9993..3449ee346 100644 --- a/src/agents/explore.ts +++ b/src/agents/explore.ts @@ -25,13 +25,10 @@ export const EXPLORE_PROMPT_METADATA: AgentPromptMetadata = { } export function createExploreAgent(model: string): AgentConfig { - const restrictions = createAgentToolRestrictions([ - "write", - "edit", - "apply_patch", - "task", - "call_omo_agent", - ]) + const restrictions = createAgentToolRestrictions( + ["write", "edit", "apply_patch", "task", "call_omo_agent"], + ["lsp_symbols", "lsp_goto_definition", "lsp_find_references", "lsp_diagnostics", "ast_grep_search"], + ) return { description: diff --git a/src/shared/permission-compat.ts b/src/shared/permission-compat.ts index fd8253b77..d6df20aed 100644 --- a/src/shared/permission-compat.ts +++ b/src/shared/permission-compat.ts @@ -13,12 +13,14 @@ export interface PermissionFormat { * Creates tool restrictions that deny specified tools. */ export function createAgentToolRestrictions( - denyTools: string[] + denyTools: string[], + allowTools: string[] = [], ): PermissionFormat { return { - permission: Object.fromEntries( - denyTools.map((tool) => [tool, "deny" as const]) - ), + permission: Object.fromEntries([ + ...denyTools.map((tool) => [tool, "deny" as const]), + ...allowTools.map((tool) => [tool, "allow" as const]), + ]), } } From 3a656136b6f6ccf94d8103e8efe540d4fc0aa8aa Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 14:41:08 +0900 Subject: [PATCH 028/146] feat(delegate-task): add resolveMetadataModel helper for model fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper that picks primary model with fallback to a secondary model (e.g., categoryModel → parentContext.model). Enforces consistent {providerID, modelID} shape. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../resolve-metadata-model.test.ts | 50 +++++++++++++++++++ .../delegate-task/resolve-metadata-model.ts | 21 ++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/tools/delegate-task/resolve-metadata-model.test.ts create mode 100644 src/tools/delegate-task/resolve-metadata-model.ts diff --git a/src/tools/delegate-task/resolve-metadata-model.test.ts b/src/tools/delegate-task/resolve-metadata-model.test.ts new file mode 100644 index 000000000..50b29f253 --- /dev/null +++ b/src/tools/delegate-task/resolve-metadata-model.test.ts @@ -0,0 +1,50 @@ +const { describe, test, expect } = require("bun:test") + +import { resolveMetadataModel } from "./resolve-metadata-model" + +const PRIMARY = { providerID: "openai", modelID: "gpt-5.4" } +const FALLBACK = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } + +describe("resolveMetadataModel", () => { + describe("#given primary and fallback are both present", () => { + test("#when resolving #then returns primary", () => { + const result = resolveMetadataModel(PRIMARY, FALLBACK) + + expect(result).toEqual(PRIMARY) + }) + }) + + describe("#given only fallback is present", () => { + test("#when resolving #then returns fallback", () => { + const result = resolveMetadataModel(undefined, FALLBACK) + + expect(result).toEqual(FALLBACK) + }) + }) + + describe("#given only primary is present", () => { + test("#when resolving #then returns primary", () => { + const result = resolveMetadataModel(PRIMARY, undefined) + + expect(result).toEqual(PRIMARY) + }) + }) + + describe("#given both are undefined", () => { + test("#when resolving #then returns undefined", () => { + const result = resolveMetadataModel(undefined, undefined) + + expect(result).toBeUndefined() + }) + }) + + describe("#given primary has extra fields", () => { + test("#when resolving #then strips to providerID and modelID only", () => { + const extended = { providerID: "openai", modelID: "gpt-5.4", variant: "high", temperature: 0.7 } as const + + const result = resolveMetadataModel(extended, undefined) + + expect(result).toEqual({ providerID: "openai", modelID: "gpt-5.4" }) + }) + }) +}) diff --git a/src/tools/delegate-task/resolve-metadata-model.ts b/src/tools/delegate-task/resolve-metadata-model.ts new file mode 100644 index 000000000..3c68ed3ad --- /dev/null +++ b/src/tools/delegate-task/resolve-metadata-model.ts @@ -0,0 +1,21 @@ +import type { DelegatedModelConfig } from "./types" + +export interface MetadataModel { + providerID: string + modelID: string +} + +type ModelLike = Pick | MetadataModel + +export function resolveMetadataModel( + primary: ModelLike | undefined, + fallback: ModelLike | undefined, +): MetadataModel | undefined { + if (primary) { + return { providerID: primary.providerID, modelID: primary.modelID } + } + if (fallback) { + return { providerID: fallback.providerID, modelID: fallback.modelID } + } + return undefined +} From 2892ca4adf06c93e4dc34a14aa8887550dc0359b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 17 Apr 2026 14:42:38 +0900 Subject: [PATCH 029/146] fix(delegate-task): align metadata with opencode core task tool Match opencode core 'task' tool behavior for metadata consistency: 1. Model fallback: When categoryModel/task.model/resumeModel is undefined, fall back to parentContext.model so subagent metadata always includes model info. Thread parentContext into executeSyncContinuation for parity. 2. Task ID consistency: unstable-agent-task was missing taskId and backgroundTaskId in metadata. background_output used inconsistent snake_case 'task_id' vs camelCase 'taskId' elsewhere. Standardize on camelCase: taskId = sessionID (resume id), backgroundTaskId = bg task id. Update text output blocks to use buildTaskMetadataBlock helper. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../create-background-output.metadata.test.ts | 2 +- .../create-background-output.ts | 4 +- .../delegate-task/background-continuation.ts | 3 +- src/tools/delegate-task/background-task.ts | 4 +- .../metadata-model-unification.test.ts | 177 +++++++++++++- .../metadata-task-id-consistency.test.ts | 218 ++++++++++++++++++ .../delegate-task/sync-continuation.test.ts | 20 +- src/tools/delegate-task/sync-continuation.ts | 6 +- src/tools/delegate-task/sync-task.ts | 3 +- src/tools/delegate-task/tools.ts | 2 +- .../delegate-task/unstable-agent-task.ts | 36 ++- 11 files changed, 445 insertions(+), 30 deletions(-) create mode 100644 src/tools/delegate-task/metadata-task-id-consistency.test.ts diff --git a/src/tools/background-task/create-background-output.metadata.test.ts b/src/tools/background-task/create-background-output.metadata.test.ts index 5111667bb..7b031abee 100644 --- a/src/tools/background-task/create-background-output.metadata.test.ts +++ b/src/tools/background-task/create-background-output.metadata.test.ts @@ -59,7 +59,7 @@ describe("createBackgroundOutput metadata", () => { agent: "test-agent", category: undefined, description: "background task", - task_id: "task-1", + backgroundTaskId: "task-1", }, }) diff --git a/src/tools/background-task/create-background-output.ts b/src/tools/background-task/create-background-output.ts index 7e8ac8f3d..56634b191 100644 --- a/src/tools/background-task/create-background-output.ts +++ b/src/tools/background-task/create-background-output.ts @@ -66,11 +66,11 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client: const meta = { title: formatResolvedTitle(task), metadata: { - task_id: task.id, + backgroundTaskId: task.id, agent: task.agent, category: task.category, description: task.description, - ...(task.sessionID ? { sessionId: task.sessionID } : {}), + ...(task.sessionID ? { sessionId: task.sessionID, taskId: task.sessionID } : {}), } as Record, } await publishToolMetadata(ctx, meta) diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index becf732b9..90ea1398b 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -4,6 +4,7 @@ import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { resolveMetadataModel } from "./resolve-metadata-model" import { getTaskID } from "./task-id" export async function executeBackgroundContinuation( @@ -42,7 +43,7 @@ export async function executeBackgroundContinuation( backgroundTaskId: task.id, sessionId: task.sessionID, command: args.command, - model: task.model ? { providerID: task.model.providerID, modelID: task.model.modelID } : undefined, + model: resolveMetadataModel(task.model, parentContext.model), }, } await publishToolMetadata(ctx, bgContMeta) diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 17b3bd632..6d982992b 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -11,6 +11,7 @@ import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied import { setSessionFallbackChain } from "../../hooks/model-fallback/hook" import { stripAgentListSortPrefix } from "../../shared/agent-display-names" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { resolveMetadataModel } from "./resolve-metadata-model" function continueSessionSetup(args: { taskID: string @@ -118,6 +119,7 @@ export async function executeBackgroundTask( SessionCategoryRegistry.register(sessionId, args.category) } + const resolvedModel = resolveMetadataModel(categoryModel, parentContext.model) const metadata = { prompt: args.prompt, agent: task.agent, @@ -129,7 +131,7 @@ export async function executeBackgroundTask( ...(sessionId ? { taskId: sessionId } : {}), backgroundTaskId: task.id, ...(sessionId ? { sessionId } : {}), - ...(categoryModel ? { model: { providerID: categoryModel.providerID, modelID: categoryModel.modelID } } : {}), + ...(resolvedModel ? { model: resolvedModel } : {}), } const unstableMeta = { diff --git a/src/tools/delegate-task/metadata-model-unification.test.ts b/src/tools/delegate-task/metadata-model-unification.test.ts index fbd407015..799b9537e 100644 --- a/src/tools/delegate-task/metadata-model-unification.test.ts +++ b/src/tools/delegate-task/metadata-model-unification.test.ts @@ -161,7 +161,7 @@ describe("metadata model unification", () => { prompt: async () => ({}), }, }, - } as any, deps) + } as any, parentContext, deps) const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) expect(meta).toBeDefined() @@ -169,4 +169,179 @@ describe("metadata model unification", () => { }) }) }) + + describe("#given categoryModel is undefined but parent.model is set", () => { + describe("#when executors publish metadata", () => { + test("#then sync-task metadata falls back to parent.model", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + subagent_type: "explore", load_skills: [], run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "explore", undefined, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then background-task metadata falls back to parent.model", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + load_skills: [], run_in_background: true, subagent_type: "explore", + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_1", description: "test", agent: "explore", + status: "pending", sessionID: "ses_bg", + }), + getTask: () => undefined, + }, + } as any, parentContext, "explore", undefined, undefined) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then unstable-agent-task metadata falls back to parent.model", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "quick", load_skills: [], run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable", description: "test", agent: "explore", + status: "completed", sessionID: "ses_unstable", + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "explore", undefined, undefined, "anthropic/claude-sonnet-4-6", + ) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then background-continuation metadata falls back to parent.model when task.model missing", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_2", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed", + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then sync-continuation metadata falls back to parent.model when resume model missing", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ data: [] }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + }) + }) + + describe("#given both categoryModel and parent.model are undefined", () => { + test("#when sync-task runs #then metadata.model is undefined without crashing", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + subagent_type: "explore", load_skills: [], run_in_background: false, + } + + const parentContextWithoutModel: ParentContext = { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContextWithoutModel, "explore", undefined, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toBeUndefined() + }) + }) }) diff --git a/src/tools/delegate-task/metadata-task-id-consistency.test.ts b/src/tools/delegate-task/metadata-task-id-consistency.test.ts new file mode 100644 index 000000000..c9a2a0b8c --- /dev/null +++ b/src/tools/delegate-task/metadata-task-id-consistency.test.ts @@ -0,0 +1,218 @@ +const { describe, test, expect } = require("bun:test") + +import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" +import type { ParentContext } from "./executor-types" + +const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } + +function makeMockCtx(): ToolContextWithMetadata & { captured: any[] } { + const captured: any[] = [] + return { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + abort: new AbortController().signal, + callID: "call_001", + metadata: async (input: any) => { captured.push(input) }, + captured, + } +} + +const parentContext: ParentContext = { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + model: MODEL, +} + +describe("taskId and backgroundTaskId metadata consistency", () => { + describe("#given sync-task runs", () => { + test("#when publishing metadata #then taskId equals sessionId", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "quick", load_skills: [], run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "explore", MODEL, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_sync") + expect(meta.metadata.sessionId).toBe("ses_sync") + expect(meta.metadata.taskId).toBe(meta.metadata.sessionId) + }) + }) + + describe("#given background-task runs", () => { + test("#when publishing metadata #then taskId is sessionID and backgroundTaskId is task.id", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + load_skills: [], run_in_background: true, subagent_type: "explore", + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_abc123", description: "test", agent: "explore", + status: "pending", sessionID: "ses_xyz789", + }), + getTask: () => undefined, + }, + } as any, parentContext, "explore", MODEL, undefined) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_xyz789") + expect(meta.metadata.sessionId).toBe("ses_xyz789") + expect(meta.metadata.backgroundTaskId).toBe("bg_abc123") + }) + }) + + describe("#given unstable-agent-task runs", () => { + test("#when publishing metadata #then taskId and backgroundTaskId are both included", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "quick", load_skills: [], run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable_abc", description: "test", agent: "explore", + status: "completed", sessionID: "ses_unstable_xyz", + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable_xyz: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "explore", MODEL, undefined, "anthropic/claude-sonnet-4-6", + ) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_unstable_xyz") + expect(meta.metadata.sessionId).toBe("ses_unstable_xyz") + expect(meta.metadata.backgroundTaskId).toBe("bg_unstable_abc") + }) + }) + + describe("#given background-continuation runs", () => { + test("#when publishing metadata #then taskId is sessionID and backgroundTaskId is bg.id", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed_x", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resumed_y", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_x", model: MODEL, + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_resumed_x") + expect(meta.metadata.sessionId).toBe("ses_resumed_x") + expect(meta.metadata.backgroundTaskId).toBe("bg_resumed_y") + }) + }) + + describe("#given sync-continuation runs", () => { + test("#when publishing metadata #then taskId is sessionID", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont_abc", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_cont_abc") + expect(meta.metadata.sessionId).toBe("ses_cont_abc") + }) + }) + + describe("#given background_output runs", () => { + test("#when publishing metadata #then backgroundTaskId is task.id not task_id", async () => { + const { createBackgroundOutput } = require("../background-task/create-background-output") + const ctx = makeMockCtx() + const manager = { + getTask: (id: string) => ({ + id, + sessionID: "ses_bg_session", + agent: "explore", + category: "deep", + description: "test", + status: "completed" as const, + }), + } + const client = { + session: { + messages: async () => ({ data: [] }), + }, + } + + const bgOutput = createBackgroundOutput(manager as any, client as any) + await bgOutput.execute({ task_id: "bg_output_xyz" } as any, ctx as any) + + const meta = ctx.captured.find((m: any) => m.metadata?.backgroundTaskId) + expect(meta).toBeDefined() + expect(meta.metadata.backgroundTaskId).toBe("bg_output_xyz") + expect(meta.metadata.sessionId).toBe("ses_bg_session") + expect(meta.metadata.taskId).toBe("ses_bg_session") + }) + }) +}) diff --git a/src/tools/delegate-task/sync-continuation.test.ts b/src/tools/delegate-task/sync-continuation.test.ts index 47205ce73..37757dbeb 100644 --- a/src/tools/delegate-task/sync-continuation.test.ts +++ b/src/tools/delegate-task/sync-continuation.test.ts @@ -97,7 +97,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { let error: any = null let result: string | null = null try { - result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) } catch (e) { error = e } @@ -159,7 +159,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { let error: any = null let result: string | null = null try { - result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) } catch (e) { error = e } @@ -222,7 +222,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation completes successfully - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - toast should be removed exactly once expect(removeTaskCalls.length).toBe(1) @@ -286,7 +286,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation with abort signal - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - removeTask should be called at least once (poller and finally may both call it) expect(removeTaskCalls.length).toBeGreaterThanOrEqual(1) @@ -346,7 +346,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { let error: any = null let result: string | null = null try { - result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) } catch (e) { error = e } @@ -403,7 +403,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation completes with agent info in messages - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - task_metadata should contain subagent field with the agent name expect(result).toContain("") @@ -457,7 +457,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation completes without agent info - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - task_metadata should NOT contain subagent field expect(result).toContain("") @@ -522,7 +522,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then expect(promptAsyncCalls).toHaveLength(1) @@ -592,7 +592,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then expect(promptAsyncCalls).toHaveLength(1) @@ -662,7 +662,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then expect(promptAsyncCalls).toHaveLength(1) diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index 45b06ea88..5ec1406b0 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -1,5 +1,5 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" -import type { ExecutorContext, SessionMessage } from "./executor-types" +import type { ExecutorContext, ParentContext, SessionMessage } from "./executor-types" import { isPlanFamily } from "./constants" import { publishToolMetadata } from "../../features/tool-metadata-store" import { getTaskToastManager } from "../../features/task-toast-manager" @@ -14,11 +14,13 @@ import { normalizeSDKResponse } from "../../shared" import { buildTaskPrompt } from "./prompt-builder" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" import { getTaskID } from "./task-id" +import { resolveMetadataModel } from "./resolve-metadata-model" export async function executeSyncContinuation( args: DelegateTaskArgs, ctx: ToolContextWithMetadata, executorCtx: ExecutorContext, + parentContext: ParentContext, deps: SyncContinuationDeps = syncContinuationDeps ): Promise { const { client, syncPollTimeoutMs, sisyphusAgentConfig } = executorCtx @@ -81,7 +83,7 @@ export async function executeSyncContinuation( sessionId: continuationID, sync: true, command: args.command, - model: resumeModel, + model: resolveMetadataModel(resumeModel, parentContext.model), }, } await publishToolMetadata(ctx, syncContMeta) diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 6cd42bb93..111371a51 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -12,6 +12,7 @@ import { syncTaskDeps, type SyncTaskDeps } from "./sync-task-deps" import { setSessionFallbackChain, clearSessionFallbackChain } from "../../hooks/model-fallback/hook" import { retrySyncPromptWithFallbacks } from "./sync-task-fallback" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { resolveMetadataModel } from "./resolve-metadata-model" export async function executeSyncTask( args: DelegateTaskArgs, @@ -128,7 +129,7 @@ export async function executeSyncTask( sync: true, spawnDepth: spawnContext.childDepth, command: args.command, - model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, + model: resolveMetadataModel(categoryModel, parentContext.model), }, } await publishToolMetadata(ctx, syncTaskMeta) diff --git a/src/tools/delegate-task/tools.ts b/src/tools/delegate-task/tools.ts index f53d50fb2..397048aa1 100644 --- a/src/tools/delegate-task/tools.ts +++ b/src/tools/delegate-task/tools.ts @@ -162,7 +162,7 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini if (runInBackground) { return executeBackgroundContinuation(args, ctx, options, parentContext) } - return executeSyncContinuation(args, ctx, options) + return executeSyncContinuation(args, ctx, options, parentContext) } if (!args.category && !args.subagent_type) { diff --git a/src/tools/delegate-task/unstable-agent-task.ts b/src/tools/delegate-task/unstable-agent-task.ts index 7a6d46e0d..7afffdeee 100644 --- a/src/tools/delegate-task/unstable-agent-task.ts +++ b/src/tools/delegate-task/unstable-agent-task.ts @@ -9,6 +9,8 @@ import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" import { normalizeSDKResponse } from "../../shared" import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied-session-permission" +import { resolveMetadataModel } from "./resolve-metadata-model" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" export async function executeUnstableAgentTask( args: DelegateTaskArgs, @@ -75,9 +77,11 @@ export async function executeUnstableAgentTask( load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, + taskId: sessionID, + backgroundTaskId: task.id, sessionId: sessionID, command: args.command, - model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, + model: resolveMetadataModel(categoryModel, parentContext.model), }, } await publishToolMetadata(ctx, bgTaskMeta) @@ -147,9 +151,13 @@ Model: ${actualModel} The task session may contain partial results. - -session_id: ${sessionID} -` +${buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + backgroundTaskId: task.id, + agent: agentToUse, + category: args.category, + })}` } if (!completedDuringMonitoring) { @@ -167,9 +175,13 @@ Model: ${actualModel} The task session may still contain partial results. - -session_id: ${sessionID} -` +${buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + backgroundTaskId: task.id, + agent: agentToUse, + category: args.category, + })}` } const messagesResult = await client.session.messages({ path: { id: sessionID } }) @@ -217,9 +229,13 @@ RESULT: ${textContent || "(No text output)"} - -session_id: ${sessionID} -` +${buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + backgroundTaskId: task.id, + agent: agentToUse, + category: args.category, + })}` } catch (error) { if (!cleanupReason) { cleanupReason = "exception" From 5759a9c503dba4dd82c738731e06d5fa64ecccc7 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:21:20 +0900 Subject: [PATCH 030/146] docs(agents): refresh AGENTS.md hierarchy via /init-deep Updated root + 14 core subdirectory AGENTS.md files to reflect current state (commit 2892ca4a on dev). Added 4 new AGENTS.md files for gap directories: hooks/comment-checker (AI slop blocker), features/claude- code-plugin-loader (CC compat layer), features/claude-code-mcp-loader (tier 2 MCP loader), cli/doctor (health diagnostics with 25 check files). --- AGENTS.md | 4 +- src/AGENTS.md | 2 +- src/agents/AGENTS.md | 2 +- src/cli/AGENTS.md | 2 +- src/cli/doctor/AGENTS.md | 82 +++++++++++++++++++ src/config/AGENTS.md | 2 +- src/features/AGENTS.md | 2 +- src/features/claude-code-mcp-loader/AGENTS.md | 78 ++++++++++++++++++ .../claude-code-plugin-loader/AGENTS.md | 78 ++++++++++++++++++ src/hooks/AGENTS.md | 2 +- src/hooks/atlas/AGENTS.md | 2 +- src/hooks/claude-code-hooks/AGENTS.md | 2 +- src/hooks/comment-checker/AGENTS.md | 62 ++++++++++++++ src/mcp/AGENTS.md | 2 +- src/openclaw/AGENTS.md | 2 +- src/plugin-handlers/AGENTS.md | 2 +- src/plugin/AGENTS.md | 2 +- src/shared/AGENTS.md | 2 +- src/tools/AGENTS.md | 2 +- 19 files changed, 316 insertions(+), 16 deletions(-) create mode 100644 src/cli/doctor/AGENTS.md create mode 100644 src/features/claude-code-mcp-loader/AGENTS.md create mode 100644 src/features/claude-code-plugin-loader/AGENTS.md create mode 100644 src/hooks/comment-checker/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md index 64bed7618..79ed0312f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,10 +1,10 @@ # oh-my-opencode — OpenCode Plugin -**Generated:** 2026-04-11 | **Commit:** f5dc1c0e | **Branch:** dev +**Generated:** 2026-04-18 | **Commit:** 2892ca4a | **Branch:** dev ## OVERVIEW -OpenCode plugin (npm: `oh-my-opencode`) extending Claude Code with multi-agent orchestration, 52 lifecycle hooks, 26 tools, skill/command/MCP systems, Hashline edit tool, IntentGate classifier, and Claude Code compatibility. ~1600 TypeScript source files. Dual-published as `oh-my-opencode` + `oh-my-openagent` during transition. +OpenCode plugin (npm: `oh-my-opencode`, dual-published as `oh-my-openagent` during transition) extending Claude Code with 11 agents, 52 lifecycle hooks, 26 tools, 3-tier MCP system (built-in + .mcp.json + skill-embedded), Hashline LINE#ID edit tool, IntentGate classifier, and Claude Code compatibility. 1766 TypeScript source files, 377k LOC, 104 barrel index.ts files. Entry: `src/index.ts` → 5-step init (loadConfig → createManagers → createTools → createHooks → createPluginInterface). ## STRUCTURE diff --git a/src/AGENTS.md b/src/AGENTS.md index 255bd8ea6..77e66d2d5 100644 --- a/src/AGENTS.md +++ b/src/AGENTS.md @@ -1,6 +1,6 @@ # src/ — Plugin Source -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/agents/AGENTS.md b/src/agents/AGENTS.md index 03bfd5b1b..f92c44406 100644 --- a/src/agents/AGENTS.md +++ b/src/agents/AGENTS.md @@ -1,6 +1,6 @@ # src/agents/ — 11 Agent Definitions -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/cli/AGENTS.md b/src/cli/AGENTS.md index 7ac648408..47b61eb49 100644 --- a/src/cli/AGENTS.md +++ b/src/cli/AGENTS.md @@ -1,6 +1,6 @@ # src/cli/ — CLI: install, run, doctor, mcp-oauth -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/cli/doctor/AGENTS.md b/src/cli/doctor/AGENTS.md new file mode 100644 index 000000000..5ba601afe --- /dev/null +++ b/src/cli/doctor/AGENTS.md @@ -0,0 +1,82 @@ +# src/cli/doctor/ — Health Diagnostics (25 Check Files) + +**Generated:** 2026-04-18 + +## OVERVIEW + +`bunx oh-my-opencode doctor` — parallel diagnostic checks across 4 categories (System, Config, Tools, Models). Catches broken installs, config typos, missing dependencies, provider misconfigurations before they become runtime errors. + +## COMMAND FLAGS + +```bash +bunx oh-my-opencode doctor # Full diagnostics (all 4 categories) +bunx oh-my-opencode doctor --status # Compact dashboard (status only) +bunx oh-my-opencode doctor --verbose # Deep details (model resolution traces) +bunx oh-my-opencode doctor --json # Machine-readable output +``` + +## CHECK CATEGORIES + +| Category | File | Validates | +|----------|------|-----------| +| **SYSTEM** | `checks/system.ts` | OpenCode binary found + version ≥1.0.150, plugin registered in opencode.json, loaded plugin version matches installed | +| **CONFIG** | `checks/config.ts` | JSONC validity, Zod schema passes, no unknown keys, model override syntax correct | +| **TOOLS** | `checks/tools.ts` | AST-Grep CLI + NAPI, comment-checker binary, LSP servers reachable, GitHub CLI auth, built-in MCP reachability | +| **MODELS** | `checks/model-resolution.ts` | models.json cache exists, per-agent fallback resolution, category overrides valid, provider availability | + +## SUPPORTING CHECK FILES (25 total) + +``` +checks/ +├── index.ts # Registration +├── system.ts # Main System aggregator +├── system-binary.ts # OpenCode binary discovery (PATH + desktop app) +├── system-plugin.ts # opencode.json plugin entry detection +├── system-loaded-version.ts # Cache vs npm latest +├── config.ts # Main Config aggregator +├── tools.ts # Main Tools aggregator +├── dependencies.ts # AST-Grep CLI/NAPI + comment-checker presence +├── tools-gh.ts # gh cli install + auth status +├── tools-lsp.ts # LSP server enumeration +├── tools-mcp.ts # Built-in + user MCP reachability +├── model-resolution.ts # Main Models aggregator +├── model-resolution-cache.ts # models.json presence + freshness +├── model-resolution-config.ts # oh-my-opencode.jsonc parse +├── model-resolution-effective-model.ts # Per-agent fallback chain trace +├── model-resolution-variant.ts # Model variant (max, high, medium) handling +├── model-resolution-details.ts # Verbose output formatter +└── model-resolution-types.ts # Shared types +``` + +## EXECUTION FLOW + +``` +doctor command + → runner.ts: parallel check execution with 30s per-check timeout + → checks/index.ts registers all 4 category checks + → each check returns: { status: "ok" | "warn" | "error", detail: string } + → formatter.ts: render to stdout (text/status/json) + → exit code: 0 (all ok) | 1 (errors) | 2 (warnings only) +``` + +## KEY FILES + +| File | Purpose | +|------|---------| +| `index.ts` | CLI command entry, flag parsing | +| `runner.ts` | Parallel `Promise.allSettled()` orchestration, 30s timeout per check | +| `formatter.ts` | Pretty printing: colored status, hierarchical output | +| `types.ts` | `DoctorCheck`, `CheckResult`, `DoctorReport` types | + +## HOW TO ADD A CHECK + +1. Create `src/cli/doctor/checks/{name}.ts` exporting check function matching `DoctorCheck` +2. Register in `checks/index.ts` +3. Category-level aggregator (system/config/tools/model-resolution) invokes it +4. Return `{ status, detail }` — no throws, all errors caught by runner + +## EXIT CODES + +- `0`: All checks passed (or only info messages) +- `1`: One or more errors — plugin will likely not work +- `2`: Warnings only — plugin works with degraded features diff --git a/src/config/AGENTS.md b/src/config/AGENTS.md index 517ccc9a1..d180669b3 100644 --- a/src/config/AGENTS.md +++ b/src/config/AGENTS.md @@ -1,6 +1,6 @@ # src/config/ — Zod v4 Schema System -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/features/AGENTS.md b/src/features/AGENTS.md index ff920a1bd..5deea8450 100644 --- a/src/features/AGENTS.md +++ b/src/features/AGENTS.md @@ -1,6 +1,6 @@ # src/features/ — 19 Feature Modules -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/features/claude-code-mcp-loader/AGENTS.md b/src/features/claude-code-mcp-loader/AGENTS.md new file mode 100644 index 000000000..593ca22de --- /dev/null +++ b/src/features/claude-code-mcp-loader/AGENTS.md @@ -0,0 +1,78 @@ +# src/features/claude-code-mcp-loader/ — Tier 2 MCP Loader (.mcp.json) + +**Generated:** 2026-04-18 + +## OVERVIEW + +11 files. Loads `.mcp.json` files from project/user scopes and expands `${VAR}` env vars. Feeds Tier 2 of the 3-tier MCP system into `mcp-config-handler.ts` during Phase 5 of config loading. + +## WHY IT EXISTS + +Claude Code ecosystem ships MCPs via `.mcp.json` files with `${VAR}` env var placeholders. OmO consumes these unchanged so existing Claude Code MCP configs work. + +## LOAD PIPELINE + +``` +loadMcpConfigs(ctx) + → scope-filter.ts: discover .mcp.json at project + user scopes + → loader.ts: parse JSON + → env-expander.ts: replace ${VAR} with process.env[VAR] + → transformer.ts: map Claude Code format → OpenCode McpLocal / McpRemote shape + → return LoadedMcpServer[] +``` + +## MCP FORMAT + +```jsonc +// .mcp.json +{ + "mcpServers": { + "my-stdio": { + "type": "stdio", + "command": "node", + "args": ["server.js"], + "env": { + "API_KEY": "${MY_API_KEY}" + } + }, + "my-http": { + "type": "http", // "sse" legacy → mapped to http + "url": "https://example.com/mcp", + "headers": { + "Authorization": "Bearer ${MY_TOKEN}" + } + } + } +} +``` + +## KEY FILES + +| File | Purpose | +|------|---------| +| `index.ts` | Barrel: `loadMcpConfigs`, types | +| `loader.ts` | `loadMcpConfigs()` main entry | +| `types.ts` | `ClaudeCodeMcpServer`, `LoadedMcpServer`, `McpScope` | +| `env-expander.ts` | `expandEnvVarsInObject()` — recursive `${VAR}` substitution | +| `transformer.ts` | Claude Code format → OpenCode `Mcp` shape | +| `scope-filter.ts` | Project vs user scope precedence | + +## THREE-TIER MCP CONTEXT + +| Tier | Loader | Scope | +|------|--------|-------| +| 1. Built-in | `src/mcp/` `createBuiltinMcps()` | Global, 3 remote HTTP MCPs | +| 2. **Claude Code** | **This module** | **From `.mcp.json`, project + user** | +| 3. Skill-embedded | `src/features/skill-mcp-manager/` | Per-session, from SKILL.md YAML | + +## SECURITY + +- **Env var allowlist**: `mcp_env_allowlist` config restricts which env vars can be expanded +- **No shell execution**: `${VAR}` is string replacement only, not shell `$()` +- **Secrets redaction**: `env-cleaner.ts` (in skill-mcp-manager) filters known secret patterns from logs + +## RELATED + +- Phase 5 integration: `src/plugin-handlers/mcp-config-handler.ts` +- Skill-embedded MCPs (Tier 3): `src/features/skill-mcp-manager/` +- Built-in MCPs (Tier 1): `src/mcp/` diff --git a/src/features/claude-code-plugin-loader/AGENTS.md b/src/features/claude-code-plugin-loader/AGENTS.md new file mode 100644 index 000000000..ae6cd3158 --- /dev/null +++ b/src/features/claude-code-plugin-loader/AGENTS.md @@ -0,0 +1,78 @@ +# src/features/claude-code-plugin-loader/ — Unified Claude Code Plugin Loader + +**Generated:** 2026-04-18 + +## OVERVIEW + +16 files. Full Claude Code plugin compatibility layer. Discovers and loads ALL plugin components (commands, agents, skills, hooks, MCP servers, LSP servers) from `.opencode/plugins/` and `~/.claude/plugins/`. + +## WHY IT EXISTS + +Claude Code plugins ship commands/agents/skills as separate files with `plugin.json` manifest. OmO uses this loader to ingest them into its own registry so existing Claude Code plugins work unchanged under OmO. + +## LOAD PIPELINE + +``` +loadAllPluginComponents(ctx) + → discoverPlugins() # scan .opencode/plugins + ~/.claude/plugins + → readPluginManifest(plugin.json) # parse name/version/commands/agents/skills/hooks/mcpServers + → loadPluginCommands() + → loadPluginAgents() + → loadPluginSkills() + → loadPluginHooks() # register hook handlers + → loadPluginMcpServers() # feed into mcp-config-handler (tier 2) + → loadPluginLspServers() + → return LoadedPluginBundle +``` + +Called from `src/plugin-handlers/plugin-components-loader.ts` during Phase 2 of config handler (10s timeout with error isolation — one broken plugin does not sink the plugin load). + +## KEY FILES + +| File | Purpose | +|------|---------| +| `index.ts` | Barrel: `loadAllPluginComponents`, `PluginManifest`, `ClaudeSettings` types | +| `plugin-discovery.ts` | Find plugin directories across scopes | +| `plugin-manifest-parser.ts` | Parse `plugin.json` with Zod validation | +| `command-loader.ts` | Load commands from `commands/` or `COMMANDS.md` | +| `agent-loader.ts` | Load agents from `agents/` or `AGENTS.md` frontmatter | +| `skill-loader.ts` | Load skills from `skills/` or `SKILL.md` | +| `hook-loader.ts` | Load hooks config from `hooks/` or manifest | +| `mcp-loader.ts` | Extract MCP server configs | +| `lsp-loader.ts` | Extract LSP server configs | +| `settings-loader.ts` | Parse Claude Code `settings.json` | + +## PLUGIN MANIFEST (plugin.json) + +```jsonc +{ + "name": "my-plugin", + "version": "1.0.0", + "description": "...", + "commands": ["./commands"], // or string[] of paths + "agents": ["./agents"], + "skills": ["./skills"], + "hooks": "./hooks/config.json", + "mcpServers": "./.mcp.json", + "lspServers": "./lsp" +} +``` + +## SCOPES + +| Scope | Path | Priority | +|-------|------|----------| +| `project` | `.opencode/plugins/` | Highest | +| `local` | `~/.opencode/plugins/` | Medium | +| `user` | `~/.claude/plugins/` | Medium | +| `managed` | Built-in | Lowest | + +## ERROR ISOLATION + +Each plugin loads in isolation — if one fails (bad manifest, missing file, syntax error), others still load. Errors surface as warnings in `bunx oh-my-opencode doctor`. + +## RELATED + +- Phase 2 loader: `src/plugin-handlers/plugin-components-loader.ts` +- Tier 2 MCP integration: `src/features/claude-code-mcp-loader/` +- Claude Code compat hooks: `src/hooks/claude-code-hooks/` diff --git a/src/hooks/AGENTS.md b/src/hooks/AGENTS.md index a0f9f80f9..135338424 100644 --- a/src/hooks/AGENTS.md +++ b/src/hooks/AGENTS.md @@ -1,6 +1,6 @@ # src/hooks/ — 52 Lifecycle Hooks -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/hooks/atlas/AGENTS.md b/src/hooks/atlas/AGENTS.md index 21e4243fa..215e53861 100644 --- a/src/hooks/atlas/AGENTS.md +++ b/src/hooks/atlas/AGENTS.md @@ -1,6 +1,6 @@ # src/hooks/atlas/ — Master Boulder Orchestrator -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/hooks/claude-code-hooks/AGENTS.md b/src/hooks/claude-code-hooks/AGENTS.md index 6055c4969..10a357756 100644 --- a/src/hooks/claude-code-hooks/AGENTS.md +++ b/src/hooks/claude-code-hooks/AGENTS.md @@ -1,6 +1,6 @@ # src/hooks/claude-code-hooks/ — Claude Code Compatibility -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/hooks/comment-checker/AGENTS.md b/src/hooks/comment-checker/AGENTS.md new file mode 100644 index 000000000..cc58f96dd --- /dev/null +++ b/src/hooks/comment-checker/AGENTS.md @@ -0,0 +1,62 @@ +# src/hooks/comment-checker/ — AI Slop Comment Blocker + +**Generated:** 2026-04-18 + +## OVERVIEW + +Tool Guard tier hook. Runs after `write`/`edit` tools to detect AI-generated comment patterns in code and block them before they land. Backed by `@code-yeongyu/comment-checker` binary (trusted dependency). + +## WHAT IT BLOCKS + +AI slop comment smells: +- Restating what code literally does (`// increment counter`) +- Filler phrases (`// obviously`, `// clearly`, `// simply`) +- Decorative separators without purpose +- JSDoc on trivially-named functions +- `// TODO:` without context +- Comments contradicting surrounding code + +See `@code-yeongyu/comment-checker` for the authoritative blocklist. + +## EXECUTION FLOW + +``` +tool.execute.after (write | edit | hashline edit) + → extract changed lines from tool output + → spawn comment-checker binary with changed file path + → parse findings (line ranges + violation category) + → if findings → inject tool-level error → agent must fix +``` + +## KEY FILES + +| File | Purpose | +|------|---------| +| `hook.ts` | `createCommentCheckerHook()` — main factory, tool.execute.after handler | +| `comment-checker-runner.ts` | Spawn binary, parse JSON output | +| `changed-line-extractor.ts` | Extract which lines changed from tool result | +| `findings-formatter.ts` | Format violations as actionable error message | +| `binary-resolver.ts` | Locate `comment-checker` binary (node_modules + PATH) | + +## CONFIG + +```jsonc +// oh-my-opencode.jsonc +{ + "comment_checker": { + "enabled": true, // default: true + "severity": "error" // error blocks, warning notifies only + } +} +``` + +Disable via `"disabled_hooks": ["comment-checker"]`. + +## BYPASS FOR LEGITIMATE COMMENTS + +Prefix with `// @allow` or mark file scope with `// comment-checker-disable-file` at top. Use sparingly — defeating the purpose. + +## RELATED + +- Doctor check: `src/cli/doctor/checks/tools.ts` verifies `comment-checker` binary availability +- Postinstall: `postinstall.mjs` downloads binary if missing diff --git a/src/mcp/AGENTS.md b/src/mcp/AGENTS.md index 2518ba92f..4914d491b 100644 --- a/src/mcp/AGENTS.md +++ b/src/mcp/AGENTS.md @@ -1,6 +1,6 @@ # src/mcp/ — 3 Built-in Remote MCPs -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/openclaw/AGENTS.md b/src/openclaw/AGENTS.md index 93b32eff3..680141de8 100644 --- a/src/openclaw/AGENTS.md +++ b/src/openclaw/AGENTS.md @@ -1,6 +1,6 @@ # src/openclaw/ — Bidirectional External Integration -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/plugin-handlers/AGENTS.md b/src/plugin-handlers/AGENTS.md index f0d9949a7..df6c8bf14 100644 --- a/src/plugin-handlers/AGENTS.md +++ b/src/plugin-handlers/AGENTS.md @@ -1,6 +1,6 @@ # src/plugin-handlers/ — 6-Phase Config Loading Pipeline -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## CRITICAL: AGENT ORDERING diff --git a/src/plugin/AGENTS.md b/src/plugin/AGENTS.md index c58d32000..94732c5b9 100644 --- a/src/plugin/AGENTS.md +++ b/src/plugin/AGENTS.md @@ -1,6 +1,6 @@ # src/plugin/ — 10 OpenCode Hook Handlers + Hook Composition -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/shared/AGENTS.md b/src/shared/AGENTS.md index 46f178b5b..b6336e6f2 100644 --- a/src/shared/AGENTS.md +++ b/src/shared/AGENTS.md @@ -1,6 +1,6 @@ # src/shared/ — 100+ Utility Files -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/tools/AGENTS.md b/src/tools/AGENTS.md index a4b51ce22..d6e6f41ad 100644 --- a/src/tools/AGENTS.md +++ b/src/tools/AGENTS.md @@ -1,6 +1,6 @@ # src/tools/ - 26 Tools Across 16 Directories -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW From 1b10ab36d2c5de743510574dec673b72647f9071 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:37:46 +0900 Subject: [PATCH 031/146] refactor(plugin): migrate to V1 PluginModule format Convert the default export from the legacy callable Plugin to the V1 PluginModule shape (`{ id, server }`) documented by opencode's plugin SDK. This aligns oh-my-openagent with the canonical plugin entry format and removes plugin-format legacy debt. Drop the module-level `let activePluginDispose` cleanup guard: opencode instantiates plugins in a scope-bound Layer per server and dynamic-imports fresh modules on reload, so module-level state is not preserved across reloads. Individual managers already register their own SIGINT/SIGTERM cleanup (skill-mcp-manager, background-agent process-cleanup), so the orphaned createPluginDispose call provided no runtime value. Remove the non-standard `name` return field that opencode's Hooks interface does not include. The PluginModule's `id` now carries the plugin identity instead. Drop the unused `lspManager` import that only fed the orphaned createPluginDispose. Update src/index.test.ts and src/index.telemetry.test.ts to call `plugin.server(ctx)` instead of `plugin(ctx)`, and assert the V1 shape. --- src/index.telemetry.test.ts | 7 ++--- src/index.test.ts | 21 ++++++++++----- src/index.ts | 52 +++++++++++++++---------------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/index.telemetry.test.ts b/src/index.telemetry.test.ts index f3026a1cb..1f552f7eb 100644 --- a/src/index.telemetry.test.ts +++ b/src/index.telemetry.test.ts @@ -125,12 +125,13 @@ describe("OhMyOpenCodePlugin telemetry isolation", () => { const { default: plugin } = await import(`./index?telemetry=${Date.now()}-${Math.random()}`) // when - const result = await plugin({ + const result = await plugin.server({ directory: "/tmp/project", client: {}, - } as Parameters[0]) + } as Parameters[0]) // then - expect(result).toMatchObject({ name: "oh-my-openagent" }) + expect(typeof result).toBe("object") + expect(result).not.toBeNull() }) }) diff --git a/src/index.test.ts b/src/index.test.ts index 7101b9f09..00af70bb9 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -257,7 +257,7 @@ const mockCreatePluginInterface = mock(() => ({})) const mockInitializeOpenClaw = mock(async () => {}) const mockStartTmuxCheck = mock(() => {}) -let OhMyOpenCodePlugin: (typeof import("./index"))["default"] +let pluginModule: (typeof import("./index"))["default"] function installIndexModuleMocks(): void { mock.module("./cli/config-manager/config-context", () => ({ @@ -337,7 +337,7 @@ describe("OhMyOpenCodePlugin", () => { beforeEach(async () => { mock.restore() installIndexModuleMocks() - ;({ default: OhMyOpenCodePlugin } = await importFreshIndexModule()) + ;({ default: pluginModule } = await importFreshIndexModule()) mockInitConfigContext.mockClear() mockDetectExternalSkillPlugin.mockClear() mockGetSkillPluginConflictWarning.mockClear() @@ -375,10 +375,10 @@ describe("OhMyOpenCodePlugin", () => { }) // when - await OhMyOpenCodePlugin({ + await pluginModule.server({ directory: "/tmp/project", client: {}, - } as Parameters[0]) + } as Parameters[0]) // then expect(mockInitializeOpenClaw).toHaveBeenCalledTimes(1) @@ -390,12 +390,21 @@ describe("OhMyOpenCodePlugin", () => { mockLoadPluginConfig.mockReturnValue({}) // when - await OhMyOpenCodePlugin({ + await pluginModule.server({ directory: "/tmp/project", client: {}, - } as Parameters[0]) + } as Parameters[0]) // then expect(mockInitializeOpenClaw).not.toHaveBeenCalled() }) + + it("exports a V1 PluginModule shape with id and server", () => { + // given the plugin module is loaded + // when inspecting the default export + // then it has the expected V1 shape + expect(typeof pluginModule).toBe("object") + expect(pluginModule.id).toBe("oh-my-openagent") + expect(typeof pluginModule.server).toBe("function") + }) }) diff --git a/src/index.ts b/src/index.ts index b36e6c4b9..b41f611e1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import { initConfigContext } from "./cli/config-manager/config-context" -import type { Plugin } from "@opencode-ai/plugin" +import type { Hooks, Plugin, PluginModule } from "@opencode-ai/plugin" import type { HookName } from "./config" @@ -9,7 +9,6 @@ import { createRuntimeTmuxConfig, isTmuxIntegrationEnabled } from "./create-runt import { createTools } from "./create-tools" import { initializeOpenClaw } from "./openclaw" import { createPluginInterface } from "./plugin-interface" -import { createPluginDispose, type PluginDispose } from "./plugin-dispose" import { loadPluginConfig } from "./plugin-config" import { createModelCacheState } from "./plugin-state" @@ -17,27 +16,23 @@ import { createFirstMessageVariantGate } from "./shared/first-message-variant" import { injectServerAuthIntoClient, log, logLegacyPluginStartupWarning } from "./shared" import { detectExternalSkillPlugin, getSkillPluginConflictWarning } from "./shared/external-plugin-detector" import { startBackgroundCheck as startTmuxCheck } from "./tools/interactive-bash" -import { lspManager } from "./tools/lsp/client" import { createPluginPostHog, getPostHogDistinctId } from "./shared/posthog" -let activePluginDispose: PluginDispose | null = null - -const OhMyOpenCodePlugin: Plugin = async (ctx) => { +const serverPlugin: Plugin = async (input, _options): Promise => { initConfigContext("opencode", null) log("[OhMyOpenCodePlugin] ENTRY - plugin loading", { - directory: ctx.directory, + directory: input.directory, }) logLegacyPluginStartupWarning() - const skillPluginCheck = detectExternalSkillPlugin(ctx.directory) + const skillPluginCheck = detectExternalSkillPlugin(input.directory) if (skillPluginCheck.detected && skillPluginCheck.pluginName) { console.warn(getSkillPluginConflictWarning(skillPluginCheck.pluginName)) } - injectServerAuthIntoClient(ctx.client) - await activePluginDispose?.() + injectServerAuthIntoClient(input.client) - const pluginConfig = loadPluginConfig(ctx.directory, ctx) + const pluginConfig = loadPluginConfig(input.directory, input) const posthog = createPluginPostHog() const distinctId = getPostHogDistinctId() @@ -78,7 +73,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { const modelCacheState = createModelCacheState() const managers = createManagers({ - ctx, + ctx: input, pluginConfig, tmuxConfig, modelCacheState, @@ -86,13 +81,13 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { }) const toolsResult = await createTools({ - ctx, + ctx: input, pluginConfig, managers, }) const hooks = createHooks({ - ctx, + ctx: input, pluginConfig, modelCacheState, backgroundManager: managers.backgroundManager, @@ -102,15 +97,8 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { availableSkills: toolsResult.availableSkills, }) - const dispose = createPluginDispose({ - backgroundManager: managers.backgroundManager, - skillMcpManager: managers.skillMcpManager, - lspManager, - disposeHooks: hooks.disposeHooks, - }) - const pluginInterface = createPluginInterface({ - ctx, + ctx: input, pluginConfig, firstMessageVariantGate, managers, @@ -118,30 +106,32 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { tools: toolsResult.filteredTools, }) - activePluginDispose = dispose - return { - name: "oh-my-openagent", ...pluginInterface, "experimental.session.compacting": async ( - _input: { sessionID: string }, + compactingInput: { sessionID: string }, output: { context: string[] }, ): Promise => { - await hooks.compactionContextInjector?.capture(_input.sessionID) - await hooks.compactionTodoPreserver?.capture(_input.sessionID) + await hooks.compactionContextInjector?.capture(compactingInput.sessionID) + await hooks.compactionTodoPreserver?.capture(compactingInput.sessionID) await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( - _input, + compactingInput, output, ) if (hooks.compactionContextInjector) { - output.context.push(hooks.compactionContextInjector.inject(_input.sessionID)) + output.context.push(hooks.compactionContextInjector.inject(compactingInput.sessionID)) } }, } } -export default OhMyOpenCodePlugin +const pluginModule: PluginModule = { + id: "oh-my-openagent", + server: serverPlugin, +} + +export default pluginModule export type { OhMyOpenCodeConfig, From cb8f44ed9592368cc6f380ca04c995d7960a38f3 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:42:01 +0900 Subject: [PATCH 032/146] refactor(ralph-loop test): clarify race-condition predicate naming Rename the local wait predicate to avoid confusion with deprecated auth-prompt condition fields. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/ralph-loop/reset-strategy-race-condition.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts b/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts index 5fcd35a2e..8f31f8ec2 100644 --- a/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts +++ b/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts @@ -21,9 +21,9 @@ function createDeferred(): { } } -async function waitUntil(condition: () => boolean): Promise { +async function waitUntil(shouldTrigger: () => boolean): Promise { for (let index = 0; index < 100; index++) { - if (condition()) { + if (shouldTrigger()) { return } From f94632ce649dfd296bc11b671d89723710a38901 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:43:08 +0900 Subject: [PATCH 033/146] refactor(skill-mcp): split tools.ts to comply with 200 LOC module rule Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../skill-mcp/parse-skill-mcp-arguments.ts | 25 +++++++++++++++++ src/tools/skill-mcp/tools.ts | 27 ++----------------- 2 files changed, 27 insertions(+), 25 deletions(-) create mode 100644 src/tools/skill-mcp/parse-skill-mcp-arguments.ts diff --git a/src/tools/skill-mcp/parse-skill-mcp-arguments.ts b/src/tools/skill-mcp/parse-skill-mcp-arguments.ts new file mode 100644 index 000000000..20e0b8158 --- /dev/null +++ b/src/tools/skill-mcp/parse-skill-mcp-arguments.ts @@ -0,0 +1,25 @@ +export function parseSkillMcpArguments( + argsJson: string | Record | undefined, +): Record { + if (!argsJson) return {} + if (typeof argsJson === "object" && argsJson !== null) { + return argsJson + } + + try { + const jsonString = argsJson.startsWith("'") && argsJson.endsWith("'") ? argsJson.slice(1, -1) : argsJson + const parsed = JSON.parse(jsonString) + if (typeof parsed !== "object" || parsed === null) { + throw new Error("Arguments must be a JSON object") + } + + return parsed as Record + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error) + throw new Error( + `Invalid arguments JSON: ${errorMessage}\n\n` + + `Expected a valid JSON object, e.g.: '{"key": "value"}'\n` + + `Received: ${argsJson}`, + ) + } +} diff --git a/src/tools/skill-mcp/tools.ts b/src/tools/skill-mcp/tools.ts index 2e1876575..25720baf8 100644 --- a/src/tools/skill-mcp/tools.ts +++ b/src/tools/skill-mcp/tools.ts @@ -1,6 +1,7 @@ import { tool, type ToolDefinition } from "@opencode-ai/plugin" import type { ToolContext } from "@opencode-ai/plugin/tool" import { BUILTIN_MCP_TOOL_HINTS, SKILL_MCP_DESCRIPTION } from "./constants" +import { parseSkillMcpArguments } from "./parse-skill-mcp-arguments" import type { SkillMcpArgs } from "./types" import type { SkillMcpManager, SkillMcpClientInfo, SkillMcpServerContext } from "../../features/skill-mcp-manager" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" @@ -82,30 +83,6 @@ function formatBuiltinMcpHint(mcpName: string): string | null { ) } -function parseArguments(argsJson: string | Record | undefined): Record { - if (!argsJson) return {} - if (typeof argsJson === "object" && argsJson !== null) { - return argsJson - } - try { - // Strip outer single quotes if present (common in LLM output) - const jsonStr = argsJson.startsWith("'") && argsJson.endsWith("'") ? argsJson.slice(1, -1) : argsJson - - const parsed = JSON.parse(jsonStr) - if (typeof parsed !== "object" || parsed === null) { - throw new Error("Arguments must be a JSON object") - } - return parsed as Record - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error) - throw new Error( - `Invalid arguments JSON: ${errorMessage}\n\n` + - `Expected a valid JSON object, e.g.: '{"key": "value"}'\n` + - `Received: ${argsJson}`, - ) - } -} - export function applyGrepFilter(output: string, pattern: string | undefined): string { if (!pattern) return output try { @@ -174,7 +151,7 @@ export function createSkillMcpTool(options: SkillMcpToolOptions): ToolDefinition skillName: found.skill.name, } - const parsedArgs = parseArguments(args.arguments) + const parsedArgs = parseSkillMcpArguments(args.arguments) let output: string switch (operation.type) { From 963355d2414d5431b4de100e70ffa483e9fda737 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:45:30 +0900 Subject: [PATCH 034/146] refactor(look-at): split tools.ts to comply with 200 LOC module rule Extract input preparation and image conversion handling into look-at-input-preparer.ts. Extract prompt construction and multimodal session execution into look-at-prompt.ts and look-at-session-runner.ts while keeping createLookAt stable. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/look-at/look-at-input-preparer.ts | 154 +++++++++++++ src/tools/look-at/look-at-prompt.ts | 18 ++ src/tools/look-at/look-at-session-runner.ts | 107 +++++++++ src/tools/look-at/tools.ts | 227 ++------------------ 4 files changed, 297 insertions(+), 209 deletions(-) create mode 100644 src/tools/look-at/look-at-input-preparer.ts create mode 100644 src/tools/look-at/look-at-prompt.ts create mode 100644 src/tools/look-at/look-at-session-runner.ts diff --git a/src/tools/look-at/look-at-input-preparer.ts b/src/tools/look-at/look-at-input-preparer.ts new file mode 100644 index 000000000..e0eef0099 --- /dev/null +++ b/src/tools/look-at/look-at-input-preparer.ts @@ -0,0 +1,154 @@ +import { basename } from "node:path" +import { pathToFileURL } from "node:url" +import type { LookAtArgs } from "./types" +import { + extractBase64Data, + inferMimeTypeFromBase64, + inferMimeTypeFromFilePath, +} from "./mime-type-inference" +import { + needsConversion, + convertImageToJpeg, + convertBase64ImageToJpeg, + cleanupConvertedImage, +} from "./image-converter" +import { log } from "../../shared" + +export interface LookAtFilePart { + type: "file" + mime: string + url: string + filename: string +} + +export interface PreparedLookAtInput { + readonly filePart: LookAtFilePart + readonly isBase64Input: boolean + readonly sourceDescription: string + cleanup(): void +} + +type PrepareLookAtInputResult = + | { ok: true; value: PreparedLookAtInput } + | { ok: false; error: string } + +function getTemporaryConversionPath(error: unknown): string | null { + if (!(error instanceof Error)) { + return null + } + + const temporaryOutputPath = Reflect.get(error, "temporaryOutputPath") + if (typeof temporaryOutputPath === "string" && temporaryOutputPath.length > 0) { + return temporaryOutputPath + } + + const temporaryDirectory = Reflect.get(error, "temporaryDirectory") + if (typeof temporaryDirectory === "string" && temporaryDirectory.length > 0) { + return temporaryDirectory + } + + return null +} + +export function prepareLookAtInput(args: LookAtArgs): PrepareLookAtInputResult { + const imageData = args.image_data + const filePath = args.file_path + + if (imageData) { + const mimeType = inferMimeTypeFromBase64(imageData) + + let finalBase64Data = extractBase64Data(imageData) + let finalMimeType = mimeType + let tempFilesToCleanup: string[] = [] + + if (needsConversion(mimeType)) { + log(`[look_at] Detected unsupported Base64 format: ${mimeType}, converting to JPEG...`) + try { + const { base64, tempFiles } = convertBase64ImageToJpeg(finalBase64Data, mimeType) + finalBase64Data = base64 + finalMimeType = "image/jpeg" + tempFilesToCleanup = tempFiles + log("[look_at] Base64 conversion successful") + } catch (conversionError) { + log(`[look_at] Base64 conversion failed: ${conversionError}`) + return { + ok: false, + error: `Error: Failed to convert Base64 image format. ${conversionError}`, + } + } + } + + return { + ok: true, + value: { + isBase64Input: true, + sourceDescription: "clipboard/pasted image", + filePart: { + type: "file", + mime: finalMimeType, + url: `data:${finalMimeType};base64,${finalBase64Data}`, + filename: `clipboard-image.${finalMimeType.split("/")[1] || "png"}`, + }, + cleanup() { + for (const temporaryFile of tempFilesToCleanup) { + cleanupConvertedImage(temporaryFile) + } + }, + }, + } + } + + if (filePath) { + let mimeType = inferMimeTypeFromFilePath(filePath) + let actualFilePath = filePath + let tempFilePath: string | null = null + let tempConversionPath: string | null = null + + if (needsConversion(mimeType)) { + log(`[look_at] Detected unsupported format: ${mimeType}, converting to JPEG...`) + try { + tempFilePath = convertImageToJpeg(filePath, mimeType) + tempConversionPath = tempFilePath + actualFilePath = tempFilePath + mimeType = "image/jpeg" + log(`[look_at] Conversion successful: ${tempFilePath}`) + } catch (conversionError) { + const failedConversionPath = getTemporaryConversionPath(conversionError) + if (failedConversionPath) { + tempConversionPath = failedConversionPath + } + log(`[look_at] Conversion failed: ${conversionError}`) + return { + ok: false, + error: `Error: Failed to convert image format. ${conversionError}`, + } + } + } + + return { + ok: true, + value: { + isBase64Input: false, + sourceDescription: filePath, + filePart: { + type: "file", + mime: mimeType, + url: pathToFileURL(actualFilePath).href, + filename: basename(actualFilePath), + }, + cleanup() { + if (tempConversionPath) { + cleanupConvertedImage(tempConversionPath) + } else if (tempFilePath) { + cleanupConvertedImage(tempFilePath) + } + }, + }, + } + } + + return { + ok: false, + error: "Error: Must provide either 'file_path' or 'image_data'.", + } +} diff --git a/src/tools/look-at/look-at-prompt.ts b/src/tools/look-at/look-at-prompt.ts new file mode 100644 index 000000000..585a8c38f --- /dev/null +++ b/src/tools/look-at/look-at-prompt.ts @@ -0,0 +1,18 @@ +export const READ_ENABLED = false + +export function buildLookAtPrompt(goal: string, isBase64Input: boolean): string { + const subjectNoun = isBase64Input ? "image" : "file" + const sourceClause = READ_ENABLED + ? "Use the Read tool on the provided file path to load its contents, then analyze it." + : `The ${subjectNoun} is already attached to this message. Analyze it directly from the attachment. Do NOT attempt to use the Read tool. The Read tool is disabled for this invocation and the ${subjectNoun} cannot be loaded by path.` + + return `Analyze the attached ${subjectNoun} and extract the requested information. + +${sourceClause} + +Goal: ${goal} + +Provide ONLY the extracted information that matches the goal. +Be thorough on what was requested, concise on everything else. +If the requested information is not found, clearly state what is missing.` +} diff --git a/src/tools/look-at/look-at-session-runner.ts b/src/tools/look-at/look-at-session-runner.ts new file mode 100644 index 000000000..5b87a7852 --- /dev/null +++ b/src/tools/look-at/look-at-session-runner.ts @@ -0,0 +1,107 @@ +import type { PluginInput } from "@opencode-ai/plugin" +import type { ToolContext } from "@opencode-ai/plugin/tool" +import { log, promptSyncWithModelSuggestionRetry } from "../../shared" +import { extractLatestAssistantText } from "./assistant-message-extractor" +import { MULTIMODAL_LOOKER_AGENT } from "./constants" +import { READ_ENABLED, buildLookAtPrompt } from "./look-at-prompt" +import type { LookAtFilePart } from "./look-at-input-preparer" +import { resolveMultimodalLookerAgentMetadata } from "./multimodal-agent-metadata" + +interface RunLookAtSessionInput { + ctx: PluginInput + toolContext: ToolContext + goal: string + filePart: LookAtFilePart + isBase64Input: boolean +} + +export async function runLookAtSession({ + ctx, + toolContext, + goal, + filePart, + isBase64Input, +}: RunLookAtSessionInput): Promise { + const prompt = buildLookAtPrompt(goal, isBase64Input) + const { agentModel, agentVariant } = await resolveMultimodalLookerAgentMetadata(ctx) + + log(`[look_at] Creating session with parent: ${toolContext.sessionID}`) + const parentSession = await ctx.client.session.get({ + path: { id: toolContext.sessionID }, + }).catch(() => null) + const parentDirectory = parentSession?.data?.directory ?? ctx.directory + + const createResult = await ctx.client.session.create({ + body: { + parentID: toolContext.sessionID, + title: `look_at: ${goal.substring(0, 50)}`, + }, + query: { directory: parentDirectory }, + }) + + if (createResult.error) { + log("[look_at] Session create error:", createResult.error) + const errorString = String(createResult.error) + if (errorString.toLowerCase().includes("unauthorized")) { + return `Error: Failed to create session (Unauthorized). This may be due to: +1. OAuth token restrictions (e.g., Claude Code credentials are restricted to Claude Code only) +2. Provider authentication issues +3. Session permission inheritance problems + +Try using a different provider or API key authentication. + +Original error: ${createResult.error}` + } + + return `Error: Failed to create session: ${createResult.error}` + } + + const sessionID = createResult.data.id + log(`[look_at] Created session: ${sessionID}`) + + log(`[look_at] Sending prompt with ${isBase64Input ? "base64 image" : "file"} to session ${sessionID}`) + try { + await promptSyncWithModelSuggestionRetry(ctx.client, { + path: { id: sessionID }, + body: { + agent: MULTIMODAL_LOOKER_AGENT, + tools: { + task: false, + call_omo_agent: false, + look_at: false, + read: READ_ENABLED, + }, + parts: [ + { type: "text", text: prompt }, + filePart, + ], + ...(agentModel ? { model: { providerID: agentModel.providerID, modelID: agentModel.modelID } } : {}), + ...(agentVariant ? { variant: agentVariant } : {}), + }, + }) + } catch (promptError) { + log("[look_at] Prompt error (ignored, will still fetch messages):", promptError) + } + + log(`[look_at] Fetching messages from session ${sessionID}...`) + const messagesResult = await ctx.client.session.messages({ + path: { id: sessionID }, + }) + + if (messagesResult.error) { + log("[look_at] Messages error:", messagesResult.error) + return `Error: Failed to get messages: ${messagesResult.error}` + } + + const messages = messagesResult.data + log(`[look_at] Got ${messages.length} messages`) + + const responseText = extractLatestAssistantText(messages) + if (!responseText) { + log("[look_at] No assistant message found") + return "Error: No response from multimodal-looker agent" + } + + log(`[look_at] Got response, length: ${responseText.length}`) + return responseText +} diff --git a/src/tools/look-at/tools.ts b/src/tools/look-at/tools.ts index 1296afd29..d6fbb3b01 100644 --- a/src/tools/look-at/tools.ts +++ b/src/tools/look-at/tools.ts @@ -1,43 +1,11 @@ -import { basename } from "node:path" -import { pathToFileURL } from "node:url" import { tool, type PluginInput, type ToolDefinition } from "@opencode-ai/plugin" -import { LOOK_AT_DESCRIPTION, MULTIMODAL_LOOKER_AGENT } from "./constants" +import { LOOK_AT_DESCRIPTION } from "./constants" import type { LookAtArgs } from "./types" -import { log, promptSyncWithModelSuggestionRetry } from "../../shared" -import { extractLatestAssistantText } from "./assistant-message-extractor" +import { log } from "../../shared" import type { LookAtArgsWithAlias } from "./look-at-arguments" import { normalizeArgs, validateArgs } from "./look-at-arguments" -import { - extractBase64Data, - inferMimeTypeFromBase64, - inferMimeTypeFromFilePath, -} from "./mime-type-inference" -import { resolveMultimodalLookerAgentMetadata } from "./multimodal-agent-metadata" -import { - needsConversion, - convertImageToJpeg, - convertBase64ImageToJpeg, - cleanupConvertedImage, -} from "./image-converter" - -function getTemporaryConversionPath(error: unknown): string | null { - if (!(error instanceof Error)) { - return null - } - - const temporaryOutputPath = Reflect.get(error, "temporaryOutputPath") - if (typeof temporaryOutputPath === "string" && temporaryOutputPath.length > 0) { - return temporaryOutputPath - } - - const temporaryDirectory = Reflect.get(error, "temporaryDirectory") - if (typeof temporaryDirectory === "string" && temporaryDirectory.length > 0) { - return temporaryDirectory - } - - return null -} - +import { prepareLookAtInput } from "./look-at-input-preparer" +import { runLookAtSession } from "./look-at-session-runner" export { normalizeArgs, validateArgs } from "./look-at-arguments" @@ -57,188 +25,29 @@ export function createLookAt(ctx: PluginInput): ToolDefinition { return validationError } - const isBase64Input = Boolean(args.image_data) - const sourceDescription = isBase64Input ? "clipboard/pasted image" : args.file_path + const preparedInputResult = prepareLookAtInput(args) + if (!preparedInputResult.ok) { + return preparedInputResult.error + } + + const preparedInput = preparedInputResult.value + const { isBase64Input, sourceDescription } = preparedInput log(`[look_at] Analyzing ${sourceDescription}, goal: ${args.goal}`) - const imageData = args.image_data - const filePath = args.file_path - - let mimeType: string - let filePart: { type: "file"; mime: string; url: string; filename: string } - let tempFilePath: string | null = null - let tempConversionPath: string | null = null - let tempFilesToCleanup: string[] = [] - try { - if (imageData) { - mimeType = inferMimeTypeFromBase64(imageData) - - let finalBase64Data = extractBase64Data(imageData) - let finalMimeType = mimeType - - if (needsConversion(mimeType)) { - log(`[look_at] Detected unsupported Base64 format: ${mimeType}, converting to JPEG...`) - try { - const { base64, tempFiles } = convertBase64ImageToJpeg(finalBase64Data, mimeType) - finalBase64Data = base64 - finalMimeType = "image/jpeg" - tempFilesToCleanup = tempFiles - log(`[look_at] Base64 conversion successful`) - } catch (conversionError) { - log(`[look_at] Base64 conversion failed: ${conversionError}`) - return `Error: Failed to convert Base64 image format. ${conversionError}` - } - } - - filePart = { - type: "file", - mime: finalMimeType, - url: `data:${finalMimeType};base64,${finalBase64Data}`, - filename: `clipboard-image.${finalMimeType.split("/")[1] || "png"}`, - } - } else if (filePath) { - mimeType = inferMimeTypeFromFilePath(filePath) - - let actualFilePath = filePath - if (needsConversion(mimeType)) { - log(`[look_at] Detected unsupported format: ${mimeType}, converting to JPEG...`) - try { - tempFilePath = convertImageToJpeg(filePath, mimeType) - tempConversionPath = tempFilePath - actualFilePath = tempFilePath - mimeType = "image/jpeg" - log(`[look_at] Conversion successful: ${tempFilePath}`) - } catch (conversionError) { - const failedConversionPath = getTemporaryConversionPath(conversionError) - if (failedConversionPath) { - tempConversionPath = failedConversionPath - } - log(`[look_at] Conversion failed: ${conversionError}`) - return `Error: Failed to convert image format. ${conversionError}` - } - } - - filePart = { - type: "file", - mime: mimeType, - url: pathToFileURL(actualFilePath).href, - filename: basename(actualFilePath), - } - } else { - return "Error: Must provide either 'file_path' or 'image_data'." - } - - const readEnabled = false - const subjectNoun = isBase64Input ? "image" : "file" - const sourceClause = readEnabled - ? `Use the Read tool on the provided file path to load its contents, then analyze it.` - : `The ${subjectNoun} is already attached to this message. Analyze it directly from the attachment. Do NOT attempt to use the Read tool. The Read tool is disabled for this invocation and the ${subjectNoun} cannot be loaded by path.` - - const prompt = `Analyze the attached ${subjectNoun} and extract the requested information. - -${sourceClause} - -Goal: ${args.goal} - -Provide ONLY the extracted information that matches the goal. -Be thorough on what was requested, concise on everything else. -If the requested information is not found, clearly state what is missing.` - - const { agentModel, agentVariant } = await resolveMultimodalLookerAgentMetadata(ctx) - - log(`[look_at] Creating session with parent: ${toolContext.sessionID}`) - const parentSession = await ctx.client.session.get({ - path: { id: toolContext.sessionID }, - }).catch(() => null) - const parentDirectory = parentSession?.data?.directory ?? ctx.directory - - const createResult = await ctx.client.session.create({ - body: { - parentID: toolContext.sessionID, - title: `look_at: ${args.goal.substring(0, 50)}`, - }, - query: { directory: parentDirectory }, - }) - - if (createResult.error) { - log(`[look_at] Session create error:`, createResult.error) - const errorStr = String(createResult.error) - if (errorStr.toLowerCase().includes("unauthorized")) { - return `Error: Failed to create session (Unauthorized). This may be due to: -1. OAuth token restrictions (e.g., Claude Code credentials are restricted to Claude Code only) -2. Provider authentication issues -3. Session permission inheritance problems - -Try using a different provider or API key authentication. - -Original error: ${createResult.error}` - } - return `Error: Failed to create session: ${createResult.error}` - } - - const sessionID = createResult.data.id - log(`[look_at] Created session: ${sessionID}`) - - log(`[look_at] Sending prompt with ${isBase64Input ? "base64 image" : "file"} to session ${sessionID}`) - try { - await promptSyncWithModelSuggestionRetry(ctx.client, { - path: { id: sessionID }, - body: { - agent: MULTIMODAL_LOOKER_AGENT, - tools: { - task: false, - call_omo_agent: false, - look_at: false, - read: readEnabled, - }, - parts: [ - { type: "text", text: prompt }, - filePart, - ], - ...(agentModel ? { model: { providerID: agentModel.providerID, modelID: agentModel.modelID } } : {}), - ...(agentVariant ? { variant: agentVariant } : {}), - }, + return await runLookAtSession({ + ctx, + toolContext, + goal: args.goal, + filePart: preparedInput.filePart, + isBase64Input, }) - } catch (promptError) { - log(`[look_at] Prompt error (ignored, will still fetch messages):`, promptError) - } - - log(`[look_at] Fetching messages from session ${sessionID}...`) - - const messagesResult = await ctx.client.session.messages({ - path: { id: sessionID }, - }) - - if (messagesResult.error) { - log(`[look_at] Messages error:`, messagesResult.error) - return `Error: Failed to get messages: ${messagesResult.error}` - } - - const messages = messagesResult.data - log(`[look_at] Got ${messages.length} messages`) - - const responseText = extractLatestAssistantText(messages) - if (!responseText) { - log("[look_at] No assistant message found") - return "Error: No response from multimodal-looker agent" - } - - log(`[look_at] Got response, length: ${responseText.length}`) - return responseText } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error) log(`[look_at] Unexpected error analyzing ${sourceDescription}:`, error) return `Error: Failed to analyze ${sourceDescription}: ${errorMessage}` } finally { - if (tempConversionPath) { - cleanupConvertedImage(tempConversionPath) - } else if (tempFilePath) { - cleanupConvertedImage(tempFilePath) - } - tempFilesToCleanup.forEach(file => { - cleanupConvertedImage(file) - }) + preparedInput.cleanup() } }, }) From 1aebf39d23d6131a3389b7c5e57c87098f0ddcf7 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:50:41 +0900 Subject: [PATCH 035/146] refactor(hooks): split preemptive-compaction.ts to comply with 200 LOC module rule Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/preemptive-compaction-trigger.ts | 131 ++++++++++++++++++ src/hooks/preemptive-compaction-types.ts | 41 ++++++ src/hooks/preemptive-compaction.ts | 149 +++------------------ 3 files changed, 189 insertions(+), 132 deletions(-) create mode 100644 src/hooks/preemptive-compaction-trigger.ts create mode 100644 src/hooks/preemptive-compaction-types.ts diff --git a/src/hooks/preemptive-compaction-trigger.ts b/src/hooks/preemptive-compaction-trigger.ts new file mode 100644 index 000000000..bbab74f76 --- /dev/null +++ b/src/hooks/preemptive-compaction-trigger.ts @@ -0,0 +1,131 @@ +import type { OhMyOpenCodeConfig } from "../config" +import { + resolveActualContextLimit, + type ContextLimitModelCacheState, +} from "../shared/context-limit-resolver" +import { log } from "../shared/logger" + +import { resolveCompactionModel } from "./shared/compaction-model-resolver" +import type { + CachedCompactionState, + PreemptiveCompactionContext, +} from "./preemptive-compaction-types" + +const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 60_000 +const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78 +const PREEMPTIVE_COMPACTION_COOLDOWN_MS = 60_000 + +declare function setTimeout(handler: () => void, timeout?: number): unknown +declare function clearTimeout(timeoutID: unknown): void + +async function withTimeout( + promise: Promise, + timeoutMs: number, + errorMessage: string, +): Promise { + let timeoutID: unknown + + const timeoutPromise = new Promise((_, reject) => { + timeoutID = setTimeout(() => { + reject(new Error(errorMessage)) + }, timeoutMs) + }) + + return await Promise.race([promise, timeoutPromise]).finally(() => { + clearTimeout(timeoutID) + }) +} + +export async function runPreemptiveCompactionIfNeeded(args: { + ctx: PreemptiveCompactionContext + pluginConfig: OhMyOpenCodeConfig + modelCacheState?: ContextLimitModelCacheState + sessionID: string + tokenCache: Map + compactionInProgress: Set + compactedSessions: Set + lastCompactionTime: Map +}): Promise { + const { + ctx, + pluginConfig, + modelCacheState, + sessionID, + tokenCache, + compactionInProgress, + compactedSessions, + lastCompactionTime, + } = args + + if (compactedSessions.has(sessionID) || compactionInProgress.has(sessionID)) return + + const lastTime = lastCompactionTime.get(sessionID) + if (lastTime && Date.now() - lastTime < PREEMPTIVE_COMPACTION_COOLDOWN_MS) return + + const cached = tokenCache.get(sessionID) + if (!cached) return + + const actualLimit = resolveActualContextLimit( + cached.providerID, + cached.modelID, + modelCacheState, + ) + + if (actualLimit === null) { + log("[preemptive-compaction] Skipping preemptive compaction: unknown context limit for model", { + providerID: cached.providerID, + modelID: cached.modelID, + }) + return + } + + const totalInputTokens = (cached.tokens.input ?? 0) + (cached.tokens.cache?.read ?? 0) + const usageRatio = totalInputTokens / actualLimit + if (usageRatio < PREEMPTIVE_COMPACTION_THRESHOLD || !cached.modelID) return + + compactionInProgress.add(sessionID) + lastCompactionTime.set(sessionID, Date.now()) + + try { + const { providerID: targetProviderID, modelID: targetModelID } = resolveCompactionModel( + pluginConfig, + sessionID, + cached.providerID, + cached.modelID, + ) + + await withTimeout( + ctx.client.session.summarize({ + path: { id: sessionID }, + body: { providerID: targetProviderID, modelID: targetModelID, auto: true }, + query: { directory: ctx.directory }, + }), + PREEMPTIVE_COMPACTION_TIMEOUT_MS, + `Compaction summarize timed out after ${PREEMPTIVE_COMPACTION_TIMEOUT_MS}ms`, + ) + + compactedSessions.add(sessionID) + } catch (error) { + log("[preemptive-compaction] Compaction failed", { + sessionID, + providerID: cached.providerID, + modelID: cached.modelID, + error: String(error), + }) + ctx.client.tui.showToast({ + body: { + title: "Preemptive compaction failed", + message: `Context window is above ${Math.round(PREEMPTIVE_COMPACTION_THRESHOLD * 100)}% and auto-compaction could not run. The session may grow large. Error: ${String(error)}`, + variant: "warning", + duration: 10000, + }, + }).catch((toastError: unknown) => { + log("[preemptive-compaction] Failed to show toast", { + sessionID, + toastError: String(toastError), + }) + }) + } finally { + compactionInProgress.delete(sessionID) + } +} diff --git a/src/hooks/preemptive-compaction-types.ts b/src/hooks/preemptive-compaction-types.ts new file mode 100644 index 000000000..77efed575 --- /dev/null +++ b/src/hooks/preemptive-compaction-types.ts @@ -0,0 +1,41 @@ +export interface TokenInfo { + input: number + output: number + reasoning: number + cache: { read: number; write: number } +} + +export interface CachedCompactionState { + providerID: string + modelID: string + tokens: TokenInfo +} + +export interface PreemptiveCompactionClient { + session: { + messages: (input: { + path: { id: string } + query?: { directory: string } + }) => Promise + summarize: (input: { + path: { id: string } + body: { providerID: string; modelID: string; auto?: boolean } + query: { directory: string } + }) => Promise + } + tui: { + showToast: (input: { + body: { + title: string + message: string + variant: "warning" + duration: number + } + }) => Promise + } +} + +export interface PreemptiveCompactionContext { + client: PreemptiveCompactionClient + directory: string +} diff --git a/src/hooks/preemptive-compaction.ts b/src/hooks/preemptive-compaction.ts index ecab70676..7b4828dcb 100644 --- a/src/hooks/preemptive-compaction.ts +++ b/src/hooks/preemptive-compaction.ts @@ -1,69 +1,16 @@ -import { log } from "../shared/logger" import type { OhMyOpenCodeConfig } from "../config" -import { - resolveActualContextLimit, - type ContextLimitModelCacheState, -} from "../shared/context-limit-resolver" +import type { ContextLimitModelCacheState } from "../shared/context-limit-resolver" -import { resolveCompactionModel } from "./shared/compaction-model-resolver" import { createPostCompactionDegradationMonitor } from "./preemptive-compaction-degradation-monitor" - -const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 60_000 -const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78 -const PREEMPTIVE_COMPACTION_COOLDOWN_MS = 60_000 - -declare function setTimeout(handler: () => void, timeout?: number): unknown -declare function clearTimeout(timeoutID: unknown): void - -interface TokenInfo { - input: number - output: number - reasoning: number - cache: { read: number; write: number } -} - -interface CachedCompactionState { - providerID: string - modelID: string - tokens: TokenInfo -} - -async function withTimeout( - promise: Promise, - timeoutMs: number, - errorMessage: string, -): Promise { - let timeoutID: unknown - - const timeoutPromise = new Promise((_, reject) => { - timeoutID = setTimeout(() => { - reject(new Error(errorMessage)) - }, timeoutMs) - }) - - return await Promise.race([promise, timeoutPromise]).finally(() => { - clearTimeout(timeoutID) - }) -} - -type PluginInput = { - client: { - session: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - messages: (...args: any[]) => any - // eslint-disable-next-line @typescript-eslint/no-explicit-any - summarize: (...args: any[]) => any - } - tui: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - showToast: (...args: any[]) => any - } - } - directory: string -} +import { runPreemptiveCompactionIfNeeded } from "./preemptive-compaction-trigger" +import type { + CachedCompactionState, + PreemptiveCompactionContext, + TokenInfo, +} from "./preemptive-compaction-types" export function createPreemptiveCompactionHook( - ctx: PluginInput, + ctx: PreemptiveCompactionContext, pluginConfig: OhMyOpenCodeConfig, modelCacheState?: ContextLimitModelCacheState, ) { @@ -84,78 +31,16 @@ export function createPreemptiveCompactionHook( input: { tool: string; sessionID: string; callID: string }, _output: { title: string; output: string; metadata: unknown } ) => { - const { sessionID } = input - if (compactedSessions.has(sessionID) || compactionInProgress.has(sessionID)) return - - const lastTime = lastCompactionTime.get(sessionID) - if (lastTime && Date.now() - lastTime < PREEMPTIVE_COMPACTION_COOLDOWN_MS) return - - const cached = tokenCache.get(sessionID) - if (!cached) return - - const actualLimit = resolveActualContextLimit( - cached.providerID, - cached.modelID, + await runPreemptiveCompactionIfNeeded({ + ctx, + pluginConfig, modelCacheState, - ) - - if (actualLimit === null) { - log("[preemptive-compaction] Skipping preemptive compaction: unknown context limit for model", { - providerID: cached.providerID, - modelID: cached.modelID, - }) - return - } - - const totalInputTokens = (cached.tokens.input ?? 0) + (cached.tokens.cache?.read ?? 0) - const usageRatio = totalInputTokens / actualLimit - if (usageRatio < PREEMPTIVE_COMPACTION_THRESHOLD || !cached.modelID) return - - compactionInProgress.add(sessionID) - lastCompactionTime.set(sessionID, Date.now()) - - try { - const { providerID: targetProviderID, modelID: targetModelID } = resolveCompactionModel( - pluginConfig, - sessionID, - cached.providerID, - cached.modelID, - ) - - await withTimeout( - ctx.client.session.summarize({ - path: { id: sessionID }, - body: { providerID: targetProviderID, modelID: targetModelID, auto: true } as never, - query: { directory: ctx.directory }, - }), - PREEMPTIVE_COMPACTION_TIMEOUT_MS, - `Compaction summarize timed out after ${PREEMPTIVE_COMPACTION_TIMEOUT_MS}ms`, - ) - - compactedSessions.add(sessionID) - } catch (error) { - log("[preemptive-compaction] Compaction failed", { - sessionID, - providerID: cached.providerID, - modelID: cached.modelID, - error: String(error), - }) - ctx.client.tui.showToast({ - body: { - title: "Preemptive compaction failed", - message: `Context window is above ${Math.round(PREEMPTIVE_COMPACTION_THRESHOLD * 100)}% and auto-compaction could not run. The session may grow large. Error: ${String(error)}`, - variant: "warning", - duration: 10000, - }, - }).catch((toastError: unknown) => { - log("[preemptive-compaction] Failed to show toast", { - sessionID, - toastError: String(toastError), - }) - }) - } finally { - compactionInProgress.delete(sessionID) - } + sessionID: input.sessionID, + tokenCache, + compactionInProgress, + compactedSessions, + lastCompactionTime, + }) } const eventHandler = async ({ event }: { event: { type: string; properties?: unknown } }) => { From db056346d2a6905b43b68d671ea5238048e11d60 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:51:26 +0900 Subject: [PATCH 036/146] refactor(shared): move parseModelString out of delegate-task to break cross-tool coupling Move parseModelString into src/shared so callers can depend on a neutral module instead of reaching into delegate-task internals. Cross-tool coupling violates module boundaries, and this keeps call-omo-agent plus runtime-fallback from importing through a sibling tool. --- src/hooks/runtime-fallback/retry-model-payload.ts | 2 +- src/shared/index.ts | 1 + src/{tools/delegate-task => shared}/model-string-parser.ts | 0 src/tools/call-omo-agent/tools.ts | 4 ++-- src/tools/delegate-task/category-resolver.ts | 2 +- src/tools/delegate-task/model-selection.ts | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) rename src/{tools/delegate-task => shared}/model-string-parser.ts (100%) diff --git a/src/hooks/runtime-fallback/retry-model-payload.ts b/src/hooks/runtime-fallback/retry-model-payload.ts index 0c9ed0c9a..d5f59b74c 100644 --- a/src/hooks/runtime-fallback/retry-model-payload.ts +++ b/src/hooks/runtime-fallback/retry-model-payload.ts @@ -1,4 +1,4 @@ -import { parseModelString } from "../../tools/delegate-task/model-string-parser" +import { parseModelString } from "../../shared/model-string-parser" export function buildRetryModelPayload( model: string, diff --git a/src/shared/index.ts b/src/shared/index.ts index 80ffa751b..140f88192 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -78,3 +78,4 @@ export * from "./plugin-identity" export * from "./log-legacy-plugin-startup-warning" export * from "./task-system-enabled" export * from "./parse-tools-config" +export { parseModelString } from "./model-string-parser" diff --git a/src/tools/delegate-task/model-string-parser.ts b/src/shared/model-string-parser.ts similarity index 100% rename from src/tools/delegate-task/model-string-parser.ts rename to src/shared/model-string-parser.ts diff --git a/src/tools/call-omo-agent/tools.ts b/src/tools/call-omo-agent/tools.ts index 802ac0ba0..839f5abe8 100644 --- a/src/tools/call-omo-agent/tools.ts +++ b/src/tools/call-omo-agent/tools.ts @@ -1,6 +1,6 @@ import { tool, type PluginInput, type ToolDefinition } from "@opencode-ai/plugin" import { ALLOWED_AGENTS, CALL_OMO_AGENT_DESCRIPTION } from "./constants" -import type { AllowedAgentType, CallOmoAgentArgs, ToolContextWithMetadata } from "./types" +import type { CallOmoAgentArgs, ToolContextWithMetadata } from "./types" import type { BackgroundManager } from "../../features/background-agent" import type { CategoriesConfig, AgentOverrides } from "../../config/schema" import type { DelegatedModelConfig } from "../../shared/model-resolution-types" @@ -11,7 +11,7 @@ import { normalizeFallbackModels } from "../../shared/model-resolver" import { buildFallbackChainFromModels } from "../../shared/fallback-chain-from-models" import { log } from "../../shared" import { CONFIG_BASENAME } from "../../shared/plugin-identity" -import { parseModelString } from "../delegate-task/model-string-parser" +import { parseModelString } from "../../shared" import { executeBackground } from "./background-executor" import { executeSync } from "./sync-executor" import { resolveCallableAgents } from "./agent-resolver" diff --git a/src/tools/delegate-task/category-resolver.ts b/src/tools/delegate-task/category-resolver.ts index bfc4d1896..25f4e8a37 100644 --- a/src/tools/delegate-task/category-resolver.ts +++ b/src/tools/delegate-task/category-resolver.ts @@ -5,7 +5,7 @@ import type { FallbackEntry } from "../../shared/model-requirements" import { mergeCategories } from "../../shared/merge-categories" import { SISYPHUS_JUNIOR_AGENT } from "./sisyphus-junior-agent" import { resolveCategoryConfig } from "./categories" -import { parseModelString } from "./model-string-parser" +import { parseModelString } from "../../shared/model-string-parser" import { CATEGORY_MODEL_REQUIREMENTS } from "../../shared/model-requirements" import { normalizeFallbackModels, flattenToFallbackModelStrings } from "../../shared/model-resolver" import { buildFallbackChainFromModels, findMostSpecificFallbackEntry } from "../../shared/fallback-chain-from-models" diff --git a/src/tools/delegate-task/model-selection.ts b/src/tools/delegate-task/model-selection.ts index cef7df752..43fa4741b 100644 --- a/src/tools/delegate-task/model-selection.ts +++ b/src/tools/delegate-task/model-selection.ts @@ -4,7 +4,7 @@ import { fuzzyMatchModel } from "../../shared/model-availability" import { transformModelForProvider } from "../../shared/provider-model-id-transform" import { hasConnectedProvidersCache, hasProviderModelsCache, readConnectedProvidersCache } from "../../shared/connected-providers-cache" import { log } from "../../shared/logger" -import { parseModelString, parseVariantFromModelID } from "./model-string-parser" +import { parseModelString, parseVariantFromModelID } from "../../shared/model-string-parser" function isExplicitHighModel(model: string): boolean { return /(?:^|\/)[^/]+-high$/.test(model) From 0f1b16567af737067466577005cdb858f76a5de4 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:52:12 +0900 Subject: [PATCH 037/146] refactor(delegate-task): split tools.ts to comply with 200 LOC module rule Extract the tool description/category metadata into tool-description.ts and move argument normalization plus validation into tool-argument-preparation.ts. This keeps createDelegateTask focused on orchestration while preserving behavior and bringing tools.ts under the module LOC rule. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../tool-argument-preparation.ts | 80 ++++++++ src/tools/delegate-task/tool-description.ts | 88 +++++++++ src/tools/delegate-task/tools.ts | 175 ++++-------------- 3 files changed, 206 insertions(+), 137 deletions(-) create mode 100644 src/tools/delegate-task/tool-argument-preparation.ts create mode 100644 src/tools/delegate-task/tool-description.ts diff --git a/src/tools/delegate-task/tool-argument-preparation.ts b/src/tools/delegate-task/tool-argument-preparation.ts new file mode 100644 index 000000000..d54b12ca6 --- /dev/null +++ b/src/tools/delegate-task/tool-argument-preparation.ts @@ -0,0 +1,80 @@ +import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" +import { SISYPHUS_JUNIOR_AGENT } from "./sisyphus-junior-agent" +import { log } from "../../shared/logger" + +export async function prepareDelegateTaskArgs(args: Record, ctx: ToolContextWithMetadata): Promise { + const category = typeof args.category === "string" ? args.category : undefined + const prompt = typeof args.prompt === "string" ? args.prompt : "" + const originalSubagentType = typeof args.subagent_type === "string" ? args.subagent_type : undefined + let subagentType = originalSubagentType + + if (category) { + if (subagentType && subagentType !== SISYPHUS_JUNIOR_AGENT) { + log("[task] category provided - overriding subagent_type to sisyphus-junior", { + category, + subagent_type: subagentType, + }) + } + subagentType = SISYPHUS_JUNIOR_AGENT + } + + let description = typeof args.description === "string" ? args.description : undefined + if (!description || description.trim() === "") { + const words = prompt.trim().split(/\s+/) + description = words.slice(0, 4).join(" ") || "Delegated task" + } + + await ctx.metadata?.({ + title: description, + }) + + const runInBackground = args.run_in_background + if (runInBackground === undefined) { + throw new Error("Invalid arguments: 'run_in_background' parameter is REQUIRED. Specify run_in_background=false for task delegation, or run_in_background=true for parallel exploration.") + } + + let loadSkills = args.load_skills + if (typeof loadSkills === "string") { + try { + const parsed = JSON.parse(loadSkills) + loadSkills = Array.isArray(parsed) ? parsed : [] + } catch { + loadSkills = [] + } + } + + if (loadSkills === undefined) { + throw new Error("Invalid arguments: 'load_skills' parameter is REQUIRED. Pass [] if no skills needed.") + } + + if (loadSkills === null) { + throw new Error("Invalid arguments: load_skills=null is not allowed. Pass [] if no skills needed.") + } + + const normalizedLoadSkills = Array.isArray(loadSkills) + ? loadSkills.filter((value): value is string => typeof value === "string") + : [] + + const taskID = typeof args.task_id === "string" ? args.task_id : undefined + const command = typeof args.command === "string" ? args.command : undefined + + args.category = category + args.subagent_type = subagentType + args.description = description + args.prompt = prompt + args.run_in_background = runInBackground + args.task_id = taskID + args.command = command + args.load_skills = normalizedLoadSkills + + return { + category, + subagent_type: subagentType, + description, + prompt, + run_in_background: runInBackground === true, + task_id: taskID, + command, + load_skills: normalizedLoadSkills, + } +} diff --git a/src/tools/delegate-task/tool-description.ts b/src/tools/delegate-task/tool-description.ts new file mode 100644 index 000000000..48bebc58d --- /dev/null +++ b/src/tools/delegate-task/tool-description.ts @@ -0,0 +1,88 @@ +import type { AvailableCategory, AvailableSkill } from "../../agents/dynamic-agent-prompt-builder" +import { mergeCategories } from "../../shared/merge-categories" +import { CATEGORY_DESCRIPTIONS } from "./constants" +import type { DelegateTaskToolOptions } from "./types" + +export interface DelegateTaskPresentation { + availableCategories: AvailableCategory[] + availableSkills: AvailableSkill[] + categoryExamples: string + description: string +} + +export function createDelegateTaskPresentation(options: DelegateTaskToolOptions): DelegateTaskPresentation { + const { userCategories } = options + const allCategories = mergeCategories(userCategories) + const categoryNames = Object.keys(allCategories) + const categoryExamples = categoryNames.join(", ") + + const availableCategories: AvailableCategory[] = options.availableCategories + ?? Object.entries(allCategories).map(([name, categoryConfig]) => { + const userDescription = userCategories?.[name]?.description + const builtinDescription = CATEGORY_DESCRIPTIONS[name] + const description = userDescription || builtinDescription || "General tasks" + + return { + name, + description, + model: categoryConfig.model, + } + }) + + const availableSkills: AvailableSkill[] = options.availableSkills ?? [] + + const categoryList = categoryNames.map(name => { + const userDescription = userCategories?.[name]?.description + const builtinDescription = CATEGORY_DESCRIPTIONS[name] + const description = userDescription || builtinDescription + return description ? ` - ${name}: ${description}` : ` - ${name}` + }).join("\n") + + const description = `Spawn agent task with category-based or direct agent selection. + + ⚠️ CRITICAL: You MUST provide EITHER category OR subagent_type. Omitting BOTH will FAIL. + + **COMMON MISTAKE (DO NOT DO THIS):** + \`\`\` + task(description="...", prompt="...", run_in_background=false) // ❌ FAILS - missing category AND subagent_type + \`\`\` + + **CORRECT - Using category:** + \`\`\` + task(category="quick", load_skills=[], description="Fix type error", prompt="...", run_in_background=false) + \`\`\` + + **CORRECT - Using subagent_type:** + \`\`\` + task(subagent_type="explore", load_skills=[], description="Find patterns", prompt="...", run_in_background=true) + \`\`\` + + REQUIRED: Provide ONE of: + - category: For task delegation (uses Sisyphus-Junior with category-optimized model) + - subagent_type: For direct agent invocation (explore, librarian, oracle, etc.) + + **DO NOT provide both.** If category is provided, subagent_type is ignored. + + - load_skills: ALWAYS REQUIRED. Pass [] if no skills needed, or ["skill-1", "skill-2"] for category tasks. + - category: Use predefined category → Spawns Sisyphus-Junior with category config + Available categories: + ${categoryList} + - subagent_type: Use specific agent directly (explore, librarian, oracle, metis, momus) + - run_in_background: REQUIRED. true=async (returns task_id), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries. + - task_id: Existing task to continue (from previous task output). Continues the same subagent session with FULL CONTEXT PRESERVED. + - command: The command that triggered this task (optional, for slash command tracking). + + **WHEN TO USE task_id:** + - Task failed/incomplete → task_id with "fix: [specific issue]" + - Need follow-up on previous result → task_id with additional question + - Multi-turn conversation with same agent → always task_id instead of new task + + Prompts MUST be in English.` + + return { + availableCategories, + availableSkills, + categoryExamples, + description, + } +} diff --git a/src/tools/delegate-task/tools.ts b/src/tools/delegate-task/tools.ts index 397048aa1..b0820f73b 100644 --- a/src/tools/delegate-task/tools.ts +++ b/src/tools/delegate-task/tools.ts @@ -1,14 +1,7 @@ import { tool, type ToolDefinition } from "@opencode-ai/plugin" -import type { DelegateTaskArgs, DelegatedModelConfig, ToolContextWithMetadata, DelegateTaskToolOptions } from "./types" -import { CATEGORY_DESCRIPTIONS } from "./constants" -import { SISYPHUS_JUNIOR_AGENT } from "./sisyphus-junior-agent" -import { mergeCategories } from "../../shared/merge-categories" +import type { DelegatedModelConfig, ToolContextWithMetadata, DelegateTaskToolOptions } from "./types" import { log } from "../../shared/logger" import { buildSystemContent } from "./prompt-builder" -import type { - AvailableCategory, - AvailableSkill, -} from "../../agents/dynamic-agent-prompt-builder" import { resolveSkillContent, resolveParentContext, @@ -20,133 +13,37 @@ import { executeBackgroundTask, executeSyncTask, } from "./executor" +import { prepareDelegateTaskArgs } from "./tool-argument-preparation" +import { createDelegateTaskPresentation } from "./tool-description" export { resolveCategoryConfig } from "./categories" export type { SyncSessionCreatedEvent, DelegateTaskToolOptions, BuildSystemContentInput } from "./types" export { buildSystemContent, buildTaskPrompt } from "./prompt-builder" +const delegateTaskArgsSchema = { + load_skills: tool.schema.array(tool.schema.string()).describe("Skill names to inject. REQUIRED - pass [] if no skills needed."), + description: tool.schema.string().optional().describe("Short task description (3-5 words). Auto-generated from prompt if omitted."), + prompt: tool.schema.string().describe("Full detailed prompt for the agent"), + run_in_background: tool.schema.boolean().describe("REQUIRED. true=async (returns task_id), false=sync (waits). Use false for task delegation, true ONLY for parallel exploration."), + category: tool.schema.string().optional().describe("REQUIRED if subagent_type not provided. Do NOT provide both category and subagent_type."), + subagent_type: tool.schema.string().optional().describe("REQUIRED if category not provided. Do NOT provide both category and subagent_type."), + task_id: tool.schema.string().optional().describe("Existing task to continue. Canonical resume identifier."), + command: tool.schema.string().optional().describe("The command that triggered this task"), +} + export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefinition { - const { userCategories } = options - - const allCategories = mergeCategories(userCategories) - const categoryNames = Object.keys(allCategories) - const categoryExamples = categoryNames.join(", ") - - const availableCategories: AvailableCategory[] = options.availableCategories - ?? Object.entries(allCategories).map(([name, categoryConfig]) => { - const userDesc = userCategories?.[name]?.description - const builtinDesc = CATEGORY_DESCRIPTIONS[name] - const description = userDesc || builtinDesc || "General tasks" - return { - name, - description, - model: categoryConfig.model, - } - }) - - const availableSkills: AvailableSkill[] = options.availableSkills ?? [] - - const categoryList = categoryNames.map(name => { - const userDesc = userCategories?.[name]?.description - const builtinDesc = CATEGORY_DESCRIPTIONS[name] - const desc = userDesc || builtinDesc - return desc ? ` - ${name}: ${desc}` : ` - ${name}` - }).join("\n") - - const description = `Spawn agent task with category-based or direct agent selection. - - ⚠️ CRITICAL: You MUST provide EITHER category OR subagent_type. Omitting BOTH will FAIL. - - **COMMON MISTAKE (DO NOT DO THIS):** - \`\`\` - task(description="...", prompt="...", run_in_background=false) // ❌ FAILS - missing category AND subagent_type - \`\`\` - - **CORRECT - Using category:** - \`\`\` - task(category="quick", load_skills=[], description="Fix type error", prompt="...", run_in_background=false) - \`\`\` - - **CORRECT - Using subagent_type:** - \`\`\` - task(subagent_type="explore", load_skills=[], description="Find patterns", prompt="...", run_in_background=true) - \`\`\` - - REQUIRED: Provide ONE of: - - category: For task delegation (uses Sisyphus-Junior with category-optimized model) - - subagent_type: For direct agent invocation (explore, librarian, oracle, etc.) - - **DO NOT provide both.** If category is provided, subagent_type is ignored. - - - load_skills: ALWAYS REQUIRED. Pass [] if no skills needed, or ["skill-1", "skill-2"] for category tasks. - - category: Use predefined category → Spawns Sisyphus-Junior with category config - Available categories: - ${categoryList} - - subagent_type: Use specific agent directly (explore, librarian, oracle, metis, momus) - - run_in_background: REQUIRED. true=async (returns task_id), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries. - - task_id: Existing task to continue (from previous task output). Continues the same subagent session with FULL CONTEXT PRESERVED. - - command: The command that triggered this task (optional, for slash command tracking). - - **WHEN TO USE task_id:** - - Task failed/incomplete → task_id with "fix: [specific issue]" - - Need follow-up on previous result → task_id with additional question - - Multi-turn conversation with same agent → always task_id instead of new task - - Prompts MUST be in English.` + const { availableCategories, availableSkills, categoryExamples, description } = createDelegateTaskPresentation(options) return tool({ description, - args: { - load_skills: tool.schema.array(tool.schema.string()).describe("Skill names to inject. REQUIRED - pass [] if no skills needed."), - description: tool.schema.string().optional().describe("Short task description (3-5 words). Auto-generated from prompt if omitted."), - prompt: tool.schema.string().describe("Full detailed prompt for the agent"), - run_in_background: tool.schema.boolean().describe("REQUIRED. true=async (returns task_id), false=sync (waits). Use false for task delegation, true ONLY for parallel exploration."), - category: tool.schema.string().optional().describe(`REQUIRED if subagent_type not provided. Do NOT provide both category and subagent_type.`), - subagent_type: tool.schema.string().optional().describe("REQUIRED if category not provided. Do NOT provide both category and subagent_type."), - task_id: tool.schema.string().optional().describe("Existing task to continue. Canonical resume identifier."), - command: tool.schema.string().optional().describe("The command that triggered this task"), - }, - async execute(args: DelegateTaskArgs, toolContext) { + args: delegateTaskArgsSchema, + async execute(args, toolContext) { const ctx = toolContext as ToolContextWithMetadata + const delegateTaskArgs = await prepareDelegateTaskArgs(args, ctx) - if (args.category) { - if (args.subagent_type && args.subagent_type !== SISYPHUS_JUNIOR_AGENT) { - log("[task] category provided - overriding subagent_type to sisyphus-junior", { - category: args.category, - subagent_type: args.subagent_type, - }) - } - args.subagent_type = SISYPHUS_JUNIOR_AGENT - } - // Auto-generate description from prompt when missing or empty - if (!args.description || typeof args.description !== "string" || args.description.trim() === "") { - const words = (args.prompt || "").trim().split(/\s+/) - args.description = words.slice(0, 4).join(" ") || "Delegated task" - } - await ctx.metadata?.({ - title: args.description, - }) - if (args.run_in_background === undefined) { - throw new Error(`Invalid arguments: 'run_in_background' parameter is REQUIRED. Specify run_in_background=false for task delegation, or run_in_background=true for parallel exploration.`) - } - if (typeof args.load_skills === "string") { - try { - const parsed = JSON.parse(args.load_skills) - args.load_skills = Array.isArray(parsed) ? parsed : [] - } catch { - args.load_skills = [] - } - } - if (args.load_skills === undefined) { - throw new Error(`Invalid arguments: 'load_skills' parameter is REQUIRED. Pass [] if no skills needed.`) - } - if (args.load_skills === null) { - throw new Error(`Invalid arguments: load_skills=null is not allowed. Pass [] if no skills needed.`) - } + const runInBackground = delegateTaskArgs.run_in_background === true - const runInBackground = args.run_in_background === true - - const { content: skillContent, contents: skillContents, error: skillError } = await resolveSkillContent(args.load_skills, { + const { content: skillContent, contents: skillContents, error: skillError } = await resolveSkillContent(delegateTaskArgs.load_skills, { gitMasterConfig: options.gitMasterConfig, browserProvider: options.browserProvider, disabledSkills: options.disabledSkills, @@ -158,14 +55,14 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini const parentContext = await resolveParentContext(ctx, options.client) - if (args.task_id) { + if (delegateTaskArgs.task_id) { if (runInBackground) { - return executeBackgroundContinuation(args, ctx, options, parentContext) + return executeBackgroundContinuation(delegateTaskArgs, ctx, options, parentContext) } - return executeSyncContinuation(args, ctx, options, parentContext) + return executeSyncContinuation(delegateTaskArgs, ctx, options, parentContext) } - if (!args.category && !args.subagent_type) { + if (!delegateTaskArgs.category && !delegateTaskArgs.subagent_type) { return `Invalid arguments: Must provide either category or subagent_type.` } @@ -190,8 +87,8 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini let fallbackChain: import("../../shared/model-requirements").FallbackEntry[] | undefined let maxPromptTokens: number | undefined - if (args.category) { - const resolution = await resolveCategoryExecution(args, options, inheritedModel, systemDefaultModel) + if (delegateTaskArgs.category) { + const resolution = await resolveCategoryExecution(delegateTaskArgs, options, inheritedModel, systemDefaultModel) if (resolution.error) { return resolution.error } @@ -204,14 +101,14 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini fallbackChain = resolution.fallbackChain maxPromptTokens = resolution.maxPromptTokens - const isRunInBackgroundExplicitlyFalse = args.run_in_background === false || args.run_in_background === "false" as unknown as boolean + const isRunInBackgroundExplicitlyFalse = isExplicitSyncRun(delegateTaskArgs.run_in_background) log("[task] unstable agent detection", { - category: args.category, + category: delegateTaskArgs.category, actualModel, isUnstableAgent, - run_in_background_value: args.run_in_background, - run_in_background_type: typeof args.run_in_background, + run_in_background_value: delegateTaskArgs.run_in_background, + run_in_background_type: typeof delegateTaskArgs.run_in_background, isRunInBackgroundExplicitlyFalse, willForceBackground: isUnstableAgent && isRunInBackgroundExplicitlyFalse, }) @@ -227,10 +124,10 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini availableCategories, availableSkills, }) - return executeUnstableAgentTask(args, ctx, options, parentContext, agentToUse, categoryModel, systemContent, actualModel) + return executeUnstableAgentTask(delegateTaskArgs, ctx, options, parentContext, agentToUse, categoryModel, systemContent, actualModel) } } else { - const resolution = await resolveSubagentExecution(args, options, parentContext.agent, categoryExamples) + const resolution = await resolveSubagentExecution(delegateTaskArgs, options, parentContext.agent, categoryExamples) if (resolution.error) { return resolution.error } @@ -251,10 +148,14 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini }) if (runInBackground) { - return executeBackgroundTask(args, ctx, options, parentContext, agentToUse, categoryModel, systemContent, fallbackChain) + return executeBackgroundTask(delegateTaskArgs, ctx, options, parentContext, agentToUse, categoryModel, systemContent, fallbackChain) } - return executeSyncTask(args, ctx, options, parentContext, agentToUse, categoryModel, systemContent, modelInfo, fallbackChain) + return executeSyncTask(delegateTaskArgs, ctx, options, parentContext, agentToUse, categoryModel, systemContent, modelInfo, fallbackChain) }, }) } + +function isExplicitSyncRun(runInBackground: unknown): boolean { + return runInBackground === false || runInBackground === "false" +} From 0d10498a1188537820498ee0321ceb2d0720e83b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:52:26 +0900 Subject: [PATCH 038/146] refactor(hooks): split session-notification.ts to comply with 200 LOC module rule Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../session-notification-event-properties.ts | 51 +++++++++++++++++++ src/hooks/session-notification.ts | 42 ++------------- 2 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 src/hooks/session-notification-event-properties.ts diff --git a/src/hooks/session-notification-event-properties.ts b/src/hooks/session-notification-event-properties.ts new file mode 100644 index 000000000..b51edf81b --- /dev/null +++ b/src/hooks/session-notification-event-properties.ts @@ -0,0 +1,51 @@ +type EventProperties = Record | undefined + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + +function getEventInfo(properties: EventProperties): Record | undefined { + const info = properties?.info + return isRecord(info) ? info : undefined +} + +export function getSessionID(properties: EventProperties): string | undefined { + const sessionID = properties?.sessionID + if (typeof sessionID === "string" && sessionID.length > 0) return sessionID + + const sessionId = properties?.sessionId + if (typeof sessionId === "string" && sessionId.length > 0) return sessionId + + const info = getEventInfo(properties) + const infoSessionID = info?.sessionID + if (typeof infoSessionID === "string" && infoSessionID.length > 0) return infoSessionID + + const infoSessionId = info?.sessionId + if (typeof infoSessionId === "string" && infoSessionId.length > 0) return infoSessionId + + return undefined +} + +export function getEventToolName(properties: EventProperties): string | undefined { + const tool = properties?.tool + if (typeof tool === "string" && tool.length > 0) return tool + + const name = properties?.name + if (typeof name === "string" && name.length > 0) return name + + return undefined +} + +export function getQuestionText(properties: EventProperties): string { + const args = properties?.args + if (!isRecord(args)) return "" + + const questions = args.questions + if (!Array.isArray(questions) || questions.length === 0) return "" + + const firstQuestion = questions[0] + if (!isRecord(firstQuestion)) return "" + + const questionText = firstQuestion.question + return typeof questionText === "string" ? questionText : "" +} diff --git a/src/hooks/session-notification.ts b/src/hooks/session-notification.ts index d54d38c61..dc83d3643 100644 --- a/src/hooks/session-notification.ts +++ b/src/hooks/session-notification.ts @@ -8,6 +8,11 @@ import { type Platform, } from "./session-notification-sender" import * as sessionNotificationSender from "./session-notification-sender" +import { + getEventToolName, + getQuestionText, + getSessionID, +} from "./session-notification-event-properties" import { hasIncompleteTodos } from "./session-todo-status" import { createIdleNotificationScheduler } from "./session-notification-scheduler" @@ -85,23 +90,6 @@ export function createSessionNotification( const PERMISSION_EVENTS = new Set(["permission.ask", "permission.asked", "permission.updated", "permission.requested"]) const PERMISSION_HINT_PATTERN = /\b(permission|approve|approval|allow|deny|consent)\b/i - const getSessionID = (properties: Record | undefined): string | undefined => { - const sessionID = properties?.sessionID - if (typeof sessionID === "string" && sessionID.length > 0) return sessionID - - const sessionId = properties?.sessionId - if (typeof sessionId === "string" && sessionId.length > 0) return sessionId - - const info = properties?.info as Record | undefined - const infoSessionID = info?.sessionID - if (typeof infoSessionID === "string" && infoSessionID.length > 0) return infoSessionID - - const infoSessionId = info?.sessionId - if (typeof infoSessionId === "string" && infoSessionId.length > 0) return infoSessionId - - return undefined - } - const shouldNotifyForSession = (sessionID: string): boolean => { if (subagentSessions.has(sessionID)) return false @@ -113,26 +101,6 @@ export function createSessionNotification( return true } - const getEventToolName = (properties: Record | undefined): string | undefined => { - const tool = properties?.tool - if (typeof tool === "string" && tool.length > 0) return tool - - const name = properties?.name - if (typeof name === "string" && name.length > 0) return name - - return undefined - } - - const getQuestionText = (properties: Record | undefined): string => { - const args = properties?.args as Record | undefined - const questions = args?.questions - if (!Array.isArray(questions) || questions.length === 0) return "" - - const firstQuestion = questions[0] as Record | undefined - const questionText = firstQuestion?.question - return typeof questionText === "string" ? questionText : "" - } - return async ({ event }: { event: { type: string; properties?: unknown } }) => { if (currentPlatform === "unsupported") return From 81b68d828cfa50910750efdc6180b2c75f314c1f Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:53:03 +0900 Subject: [PATCH 039/146] refactor(model-fallback): move fallback state into factory closure and split hook.ts Move the pending fallback, toast, and session-chain maps behind a shared controller initialized from the hook factory. This preserves the existing singleton semantics because exported helpers and hook instances still resolve the same lazily initialized controller while hook.ts stays under the 200-line limit. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../fallback-state-controller.ts | 135 +++++++++++++++++ src/hooks/model-fallback/hook.ts | 137 ++++++------------ 2 files changed, 179 insertions(+), 93 deletions(-) create mode 100644 src/hooks/model-fallback/fallback-state-controller.ts diff --git a/src/hooks/model-fallback/fallback-state-controller.ts b/src/hooks/model-fallback/fallback-state-controller.ts new file mode 100644 index 000000000..b2e6831a0 --- /dev/null +++ b/src/hooks/model-fallback/fallback-state-controller.ts @@ -0,0 +1,135 @@ +import type { FallbackEntry } from "../../shared/model-requirements" +import { getAgentConfigKey } from "../../shared/agent-display-names" +import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements" +import { log } from "../../shared/logger" +import { getNextReachableFallback } from "./next-fallback" + +type ModelFallbackStateLike = { + providerID: string + modelID: string + fallbackChain: FallbackEntry[] + attemptCount: number + pending: boolean +} + +export type ModelFallbackStateController = { + lastToastKey: Map + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => void + clearSessionFallbackChain: (sessionID: string) => void + setPendingModelFallback: ( + sessionID: string, + agentName: string, + currentProviderID: string, + currentModelID: string, + ) => boolean + getNextFallback: (sessionID: string) => ReturnType + clearPendingModelFallback: (sessionID: string) => void + hasPendingModelFallback: (sessionID: string) => boolean + getFallbackState: (sessionID: string) => ModelFallbackStateLike | undefined + reset: () => void +} + +export function createModelFallbackStateController(input: { + pendingModelFallbacks: Map + lastToastKey: Map + sessionFallbackChains: Map +}): ModelFallbackStateController { + const { pendingModelFallbacks, lastToastKey, sessionFallbackChains } = input + + function setSessionFallbackChain(sessionID: string, fallbackChain: FallbackEntry[] | undefined): void { + if (!sessionID) return + sessionFallbackChains.set(sessionID, fallbackChain?.length ? fallbackChain : []) + } + + function clearSessionFallbackChain(sessionID: string): void { + sessionFallbackChains.delete(sessionID) + } + + function setPendingModelFallback( + sessionID: string, + agentName: string, + currentProviderID: string, + currentModelID: string, + ): boolean { + const agentKey = getAgentConfigKey(agentName) + const requirements = AGENT_MODEL_REQUIREMENTS[agentKey] + const fallbackChain = sessionFallbackChains.has(sessionID) + ? sessionFallbackChains.get(sessionID) + : requirements?.fallbackChain + + if (!fallbackChain?.length) { + log("[model-fallback] No fallback chain for agent: " + agentName + " (key: " + agentKey + ")") + return false + } + + const existing = pendingModelFallbacks.get(sessionID) + if (existing) { + if (existing.pending) { + log("[model-fallback] Pending fallback already armed for session: " + sessionID) + return false + } + existing.providerID = currentProviderID + existing.modelID = currentModelID + existing.pending = true + if (existing.attemptCount >= existing.fallbackChain.length) { + log("[model-fallback] Fallback chain exhausted for session: " + sessionID) + return false + } + log("[model-fallback] Re-armed pending fallback for session: " + sessionID) + return true + } + + pendingModelFallbacks.set(sessionID, { + providerID: currentProviderID, + modelID: currentModelID, + fallbackChain, + attemptCount: 0, + pending: true, + }) + log("[model-fallback] Set pending fallback for session: " + sessionID + ", agent: " + agentName) + return true + } + + function getNextFallback(sessionID: string): ReturnType { + const state = pendingModelFallbacks.get(sessionID) + if (!state?.pending) return null + + const fallback = getNextReachableFallback(sessionID, state) + if (fallback) return fallback + + log("[model-fallback] No more fallbacks for session: " + sessionID) + pendingModelFallbacks.delete(sessionID) + return null + } + + function clearPendingModelFallback(sessionID: string): void { + pendingModelFallbacks.delete(sessionID) + lastToastKey.delete(sessionID) + } + + function hasPendingModelFallback(sessionID: string): boolean { + return pendingModelFallbacks.get(sessionID)?.pending === true + } + + function getFallbackState(sessionID: string): ModelFallbackStateLike | undefined { + return pendingModelFallbacks.get(sessionID) + } + + function reset(): void { + pendingModelFallbacks.clear() + lastToastKey.clear() + sessionFallbackChains.clear() + } + + return { + lastToastKey, + setSessionFallbackChain, + clearSessionFallbackChain, + setPendingModelFallback, + getNextFallback, + clearPendingModelFallback, + hasPendingModelFallback, + getFallbackState, + reset, + } +} diff --git a/src/hooks/model-fallback/hook.ts b/src/hooks/model-fallback/hook.ts index b188bd48d..191a58e3a 100644 --- a/src/hooks/model-fallback/hook.ts +++ b/src/hooks/model-fallback/hook.ts @@ -1,13 +1,10 @@ import type { FallbackEntry } from "../../shared/model-requirements" -import { getAgentConfigKey } from "../../shared/agent-display-names" -import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements" -import { readConnectedProvidersCache, readProviderModelsCache } from "../../shared/connected-providers-cache" -import { selectFallbackProvider } from "../../shared/model-error-classifier" -import { transformModelForProvider } from "../../shared/provider-model-id-transform" -import { log } from "../../shared/logger" import type { ChatMessageInput, ChatMessageHandlerOutput } from "../../plugin/chat-message" import { applyFallbackToChatMessage } from "./chat-message-fallback-handler" -import { getNextReachableFallback } from "./next-fallback" +import { + createModelFallbackStateController, + type ModelFallbackStateController, +} from "./fallback-state-controller" type FallbackToast = (input: { title: string @@ -31,30 +28,26 @@ export type ModelFallbackState = { pending: boolean } -/** - * Map of sessionID -> pending model fallback state - * When a model error occurs, we store the fallback info here. - * The next chat.message call will use this to switch to the fallback model. - */ -const pendingModelFallbacks = new Map() -const lastToastKey = new Map() -const sessionFallbackChains = new Map() +const modelFallbackControllerRef: { current?: ModelFallbackStateController } = {} + +function getOrCreateModelFallbackController(): ModelFallbackStateController { + if (!modelFallbackControllerRef.current) { + createModelFallbackHook() + } + + const controller = modelFallbackControllerRef.current + if (!controller) { + throw new Error("Model fallback controller should be initialized") + } + return controller +} export function setSessionFallbackChain(sessionID: string, fallbackChain: FallbackEntry[] | undefined): void { - if (!sessionID) return - if (!fallbackChain) { - sessionFallbackChains.set(sessionID, []) - return - } - if (fallbackChain.length === 0) { - sessionFallbackChains.set(sessionID, []) - return - } - sessionFallbackChains.set(sessionID, fallbackChain) + getOrCreateModelFallbackController().setSessionFallbackChain(sessionID, fallbackChain) } export function clearSessionFallbackChain(sessionID: string): void { - sessionFallbackChains.delete(sessionID) + getOrCreateModelFallbackController().clearSessionFallbackChain(sessionID) } /** @@ -67,51 +60,12 @@ export function setPendingModelFallback( currentProviderID: string, currentModelID: string, ): boolean { - const agentKey = getAgentConfigKey(agentName) - const requirements = AGENT_MODEL_REQUIREMENTS[agentKey] - const hasSessionFallback = sessionFallbackChains.has(sessionID) - const sessionFallback = sessionFallbackChains.get(sessionID) - const fallbackChain = hasSessionFallback - ? sessionFallback - : requirements?.fallbackChain - - if (!fallbackChain || fallbackChain.length === 0) { - log("[model-fallback] No fallback chain for agent: " + agentName + " (key: " + agentKey + ")") - return false - } - - const existing = pendingModelFallbacks.get(sessionID) - - if (existing) { - if (existing.pending) { - log("[model-fallback] Pending fallback already armed for session: " + sessionID) - return false - } - - // Preserve progression across repeated session.error retries in same session. - // We only mark the next turn as pending fallback application. - existing.providerID = currentProviderID - existing.modelID = currentModelID - existing.pending = true - if (existing.attemptCount >= existing.fallbackChain.length) { - log("[model-fallback] Fallback chain exhausted for session: " + sessionID) - return false - } - log("[model-fallback] Re-armed pending fallback for session: " + sessionID) - return true - } - - const state: ModelFallbackState = { - providerID: currentProviderID, - modelID: currentModelID, - fallbackChain, - attemptCount: 0, - pending: true, - } - - pendingModelFallbacks.set(sessionID, state) - log("[model-fallback] Set pending fallback for session: " + sessionID + ", agent: " + agentName) - return true + return getOrCreateModelFallbackController().setPendingModelFallback( + sessionID, + agentName, + currentProviderID, + currentModelID, + ) } /** @@ -121,19 +75,7 @@ export function setPendingModelFallback( export function getNextFallback( sessionID: string, ): { providerID: string; modelID: string; variant?: string } | null { - const state = pendingModelFallbacks.get(sessionID) - if (!state) return null - - if (!state.pending) return null - - const fallback = getNextReachableFallback(sessionID, state) - if (fallback) { - return fallback - } - - log("[model-fallback] No more fallbacks for session: " + sessionID) - pendingModelFallbacks.delete(sessionID) - return null + return getOrCreateModelFallbackController().getNextFallback(sessionID) } /** @@ -141,29 +83,40 @@ export function getNextFallback( * Called after fallback is successfully applied. */ export function clearPendingModelFallback(sessionID: string): void { - pendingModelFallbacks.delete(sessionID) - lastToastKey.delete(sessionID) + getOrCreateModelFallbackController().clearPendingModelFallback(sessionID) } /** * Checks if there's a pending fallback for a session. */ export function hasPendingModelFallback(sessionID: string): boolean { - const state = pendingModelFallbacks.get(sessionID) - return state?.pending === true + return getOrCreateModelFallbackController().hasPendingModelFallback(sessionID) } /** * Gets the current fallback state for a session (for debugging). */ export function getFallbackState(sessionID: string): ModelFallbackState | undefined { - return pendingModelFallbacks.get(sessionID) + return getOrCreateModelFallbackController().getFallbackState(sessionID) } /** * Creates a chat.message hook that applies model fallbacks when pending. */ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplied?: FallbackCallback }) { + if (!modelFallbackControllerRef.current) { + const pendingModelFallbacks = new Map() + const lastToastKey = new Map() + const sessionFallbackChains = new Map() + + modelFallbackControllerRef.current = createModelFallbackStateController({ + pendingModelFallbacks, + lastToastKey, + sessionFallbackChains, + }) + } + + const controller = getOrCreateModelFallbackController() const toast = args?.toast const onApplied = args?.onApplied @@ -184,7 +137,7 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie fallback, toast, onApplied, - lastToastKey, + lastToastKey: controller.lastToastKey, }) }, } @@ -195,7 +148,5 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie * Clears pending fallbacks, toast keys, and session chains. */ export function _resetForTesting(): void { - pendingModelFallbacks.clear() - lastToastKey.clear() - sessionFallbackChains.clear() + getOrCreateModelFallbackController().reset() } From f56e3934d8767124778aef1bd2e39f7daefc65ab Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 02:17:25 +0900 Subject: [PATCH 040/146] docs: update plugin entry references to V1 PluginModule shape Sync the stale plugin entry docs with the shipped V1 PluginModule default export and remove the removed callable symbol references.\n\nUltraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)\nCo-authored-by: Sisyphus --- AGENTS.md | 4 ++-- CONTRIBUTING.md | 2 +- src/AGENTS.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 64bed7618..458e7a9f0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ OpenCode plugin (npm: `oh-my-opencode`) extending Claude Code with multi-agent o ``` oh-my-opencode/ ├── src/ -│ ├── index.ts # Plugin entry: loadConfig → createManagers → createTools → createHooks → createPluginInterface +│ ├── index.ts # Plugin entry: default export `pluginModule`, shape `{ id, server }` │ ├── plugin-config.ts # JSONC multi-level config: user → project → defaults (Zod v4) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── hooks/ # 52 lifecycle hooks across dedicated modules and standalone files @@ -33,7 +33,7 @@ oh-my-opencode/ ## INITIALIZATION FLOW ``` -OhMyOpenCodePlugin(ctx) +pluginModule.server(input, options) ├─→ loadPluginConfig() # JSONC parse → project/user merge → Zod validate → migrate ├─→ createManagers() # TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler ├─→ createTools() # SkillContext + AvailableCategories + ToolRegistry (26 tools) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f1ae6e419..f1ded421d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,7 +109,7 @@ After making changes, you can test your local build in OpenCode: ``` oh-my-opencode/ ├── src/ -│ ├── index.ts # Plugin entry (OhMyOpenCodePlugin) +│ ├── index.ts # Plugin entry (V1 PluginModule, default export) │ ├── plugin-config.ts # JSONC multi-level config (Zod v4) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── hooks/ # 52 lifecycle hooks across 55 dedicated modules diff --git a/src/AGENTS.md b/src/AGENTS.md index 255bd8ea6..aa0bbd6f3 100644 --- a/src/AGENTS.md +++ b/src/AGENTS.md @@ -10,7 +10,7 @@ Entry point `index.ts` orchestrates 5-step initialization: loadConfig → create | File | Purpose | |------|---------| -| `index.ts` | Plugin entry, exports `OhMyOpenCodePlugin` | +| `index.ts` | Plugin entry, default-exports `pluginModule: PluginModule` with `{ id, server }` | | `plugin-config.ts` | JSONC parse, multi-level merge, Zod v4 validation | | `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler | | `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry (26 tools) | From e2f5c0d3616b4c227da76f775d4b0c8b95d42fb7 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 02:23:55 +0900 Subject: [PATCH 041/146] refactor(plugin): remove orphaned createPluginDispose + stale test mocks Remove the dead plugin-dispose module and its dedicated test now that V1 plugin migration removed the last production call site. Clean the remaining bootstrap test mocks so src no longer references createPluginDispose. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/index.compacting.test.ts | 136 ++++++++++++++++ src/index.conditional-tools.test.ts | 85 ++++++++++ src/index.telemetry.test.ts | 4 - src/index.test.ts | 224 -------------------------- src/plugin-dispose.test.ts | 237 ---------------------------- src/plugin-dispose.ts | 51 ------ 6 files changed, 221 insertions(+), 516 deletions(-) create mode 100644 src/index.compacting.test.ts create mode 100644 src/index.conditional-tools.test.ts delete mode 100644 src/plugin-dispose.test.ts delete mode 100644 src/plugin-dispose.ts diff --git a/src/index.compacting.test.ts b/src/index.compacting.test.ts new file mode 100644 index 000000000..46434d8cb --- /dev/null +++ b/src/index.compacting.test.ts @@ -0,0 +1,136 @@ +import { describe, expect, it, mock } from "bun:test" + +function createCompactingHandler(hooks: { + compactionContextInjector?: { + capture: (sessionID: string) => Promise + inject: (sessionID: string) => string + } + compactionTodoPreserver?: { capture: (sessionID: string) => Promise } + claudeCodeHooks?: { + "experimental.session.compacting"?: ( + input: { sessionID: string }, + output: { context: string[] }, + ) => Promise + } +}) { + return async ( + input: { sessionID: string }, + output: { context: string[] }, + ): Promise => { + await hooks.compactionContextInjector?.capture(input.sessionID) + await hooks.compactionTodoPreserver?.capture(input.sessionID) + await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( + input, + output, + ) + if (hooks.compactionContextInjector) { + output.context.push(hooks.compactionContextInjector.inject(input.sessionID)) + } + } +} + +describe("experimental.session.compacting handler", () => { + //#given all three hooks are present + //#when compacting handler is invoked + //#then all hooks are called in order: capture → PreCompact → contextInjector + it("calls claudeCodeHooks PreCompact alongside other hooks", async () => { + const callOrder: string[] = [] + + const handler = createCompactingHandler({ + compactionContextInjector: { + capture: mock(async () => { + callOrder.push("checkpointCapture") + }), + inject: mock((sessionID: string) => { + callOrder.push("contextInjector") + return `context-for-${sessionID}` + }), + }, + compactionTodoPreserver: { + capture: mock(async () => { + callOrder.push("capture") + }), + }, + claudeCodeHooks: { + "experimental.session.compacting": mock(async () => { + callOrder.push("preCompact") + }), + }, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(callOrder).toEqual([ + "checkpointCapture", + "capture", + "preCompact", + "contextInjector", + ]) + expect(output.context).toEqual(["context-for-ses_test"]) + }) + + //#given claudeCodeHooks injects context during PreCompact + //#when compacting handler is invoked + //#then injected context from PreCompact is preserved in output + it("preserves context injected by PreCompact hooks", async () => { + const handler = createCompactingHandler({ + claudeCodeHooks: { + "experimental.session.compacting": async (_input, output) => { + output.context.push("precompact-injected-context") + }, + }, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(output.context).toContain("precompact-injected-context") + }) + + //#given claudeCodeHooks is null (no claude code hooks configured) + //#when compacting handler is invoked + //#then handler completes without error and other hooks still run + it("handles null claudeCodeHooks gracefully", async () => { + const captureMock = mock(async () => {}) + const checkpointCaptureMock = mock(async () => {}) + const contextMock = mock(() => "injected-context") + + const handler = createCompactingHandler({ + compactionContextInjector: { + capture: checkpointCaptureMock, + inject: contextMock, + }, + compactionTodoPreserver: { capture: captureMock }, + claudeCodeHooks: undefined, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(checkpointCaptureMock).toHaveBeenCalledWith("ses_test") + expect(captureMock).toHaveBeenCalledWith("ses_test") + expect(contextMock).toHaveBeenCalledWith("ses_test") + expect(output.context).toEqual(["injected-context"]) + }) + + //#given compactionContextInjector is null + //#when compacting handler is invoked + //#then handler does not early-return, PreCompact hooks still execute + it("does not early-return when compactionContextInjector is null", async () => { + const preCompactMock = mock(async () => {}) + + const handler = createCompactingHandler({ + claudeCodeHooks: { + "experimental.session.compacting": preCompactMock, + }, + compactionContextInjector: undefined, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(preCompactMock).toHaveBeenCalled() + expect(output.context).toEqual([]) + }) +}) diff --git a/src/index.conditional-tools.test.ts b/src/index.conditional-tools.test.ts new file mode 100644 index 000000000..96c955c4b --- /dev/null +++ b/src/index.conditional-tools.test.ts @@ -0,0 +1,85 @@ +import { describe, expect, it } from "bun:test" + +describe("look_at tool conditional registration", () => { + describe("isMultimodalLookerEnabled logic", () => { + // given multimodal-looker is in disabled_agents + // when checking if agent is enabled + // then should return false (disabled) + it("returns false when multimodal-looker is disabled (exact case)", () => { + const disabledAgents: string[] = ["multimodal-looker"] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(false) + }) + + // given multimodal-looker is in disabled_agents with different case + // when checking if agent is enabled + // then should return false (case-insensitive match) + it("returns false when multimodal-looker is disabled (case-insensitive)", () => { + const disabledAgents: string[] = ["Multimodal-Looker"] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(false) + }) + + // given multimodal-looker is NOT in disabled_agents + // when checking if agent is enabled + // then should return true (enabled) + it("returns true when multimodal-looker is not disabled", () => { + const disabledAgents: string[] = ["oracle", "librarian"] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(true) + }) + + // given disabled_agents is empty + // when checking if agent is enabled + // then should return true (enabled by default) + it("returns true when disabled_agents is empty", () => { + const disabledAgents: string[] = [] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(true) + }) + + // given disabled_agents is undefined (simulated as empty array) + // when checking if agent is enabled + // then should return true (enabled by default) + it("returns true when disabled_agents is undefined (fallback to empty)", () => { + const disabledAgents: string[] | undefined = undefined + const list: string[] = disabledAgents ?? [] + const isEnabled = !list.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(true) + }) + }) + + describe("conditional tool spread pattern", () => { + // given lookAt is not null (agent enabled) + // when spreading into tool object + // then look_at should be included + it("includes look_at when lookAt is not null", () => { + const lookAt = { execute: () => {} } + const tools = { + ...(lookAt ? { look_at: lookAt } : {}), + } + expect(tools).toHaveProperty("look_at") + }) + + // given lookAt is null (agent disabled) + // when spreading into tool object + // then look_at should NOT be included + it("excludes look_at when lookAt is null", () => { + const lookAt = null + const tools = { + ...(lookAt ? { look_at: lookAt } : {}), + } + expect(tools).not.toHaveProperty("look_at") + }) + }) +}) diff --git a/src/index.telemetry.test.ts b/src/index.telemetry.test.ts index 1f552f7eb..7f751f594 100644 --- a/src/index.telemetry.test.ts +++ b/src/index.telemetry.test.ts @@ -29,7 +29,6 @@ const mockCreateHooks = mock(() => ({ compactionTodoPreserver: undefined, claudeCodeHooks: undefined, })) -const mockCreatePluginDispose = mock(() => async () => {}) const mockCreatePluginInterface = mock(() => ({})) const mockCreatePluginPostHog = mock(() => ({ trackActive: () => { @@ -70,9 +69,6 @@ function installModuleMocks(): void { mock.module("./create-hooks", () => ({ createHooks: mockCreateHooks, })) - mock.module("./plugin-dispose", () => ({ - createPluginDispose: mockCreatePluginDispose, - })) mock.module("./plugin-interface", () => ({ createPluginInterface: mockCreatePluginInterface, })) diff --git a/src/index.test.ts b/src/index.test.ts index 00af70bb9..335562cd0 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,223 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" -describe("experimental.session.compacting handler", () => { - function createCompactingHandler(hooks: { - compactionContextInjector?: { - capture: (sessionID: string) => Promise - inject: (sessionID: string) => string - } - compactionTodoPreserver?: { capture: (sessionID: string) => Promise } - claudeCodeHooks?: { - "experimental.session.compacting"?: ( - input: { sessionID: string }, - output: { context: string[] }, - ) => Promise - } - }) { - return async ( - _input: { sessionID: string }, - output: { context: string[] }, - ): Promise => { - await hooks.compactionContextInjector?.capture(_input.sessionID) - await hooks.compactionTodoPreserver?.capture(_input.sessionID) - await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( - _input, - output, - ) - if (hooks.compactionContextInjector) { - output.context.push(hooks.compactionContextInjector.inject(_input.sessionID)) - } - } - } - - //#given all three hooks are present - //#when compacting handler is invoked - //#then all hooks are called in order: capture → PreCompact → contextInjector - it("calls claudeCodeHooks PreCompact alongside other hooks", async () => { - const callOrder: string[] = [] - - const handler = createCompactingHandler({ - compactionContextInjector: { - capture: mock(async () => { - callOrder.push("checkpointCapture") - }), - inject: mock((sessionID: string) => { - callOrder.push("contextInjector") - return `context-for-${sessionID}` - }), - }, - compactionTodoPreserver: { - capture: mock(async () => { callOrder.push("capture") }), - }, - claudeCodeHooks: { - "experimental.session.compacting": mock(async () => { - callOrder.push("preCompact") - }), - }, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(callOrder).toEqual(["checkpointCapture", "capture", "preCompact", "contextInjector"]) - expect(output.context).toEqual(["context-for-ses_test"]) - }) - - //#given claudeCodeHooks injects context during PreCompact - //#when compacting handler is invoked - //#then injected context from PreCompact is preserved in output - it("preserves context injected by PreCompact hooks", async () => { - const handler = createCompactingHandler({ - claudeCodeHooks: { - "experimental.session.compacting": async (_input, output) => { - output.context.push("precompact-injected-context") - }, - }, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(output.context).toContain("precompact-injected-context") - }) - - //#given claudeCodeHooks is null (no claude code hooks configured) - //#when compacting handler is invoked - //#then handler completes without error and other hooks still run - it("handles null claudeCodeHooks gracefully", async () => { - const captureMock = mock(async () => {}) - const checkpointCaptureMock = mock(async () => {}) - const contextMock = mock(() => "injected-context") - - const handler = createCompactingHandler({ - compactionContextInjector: { - capture: checkpointCaptureMock, - inject: contextMock, - }, - compactionTodoPreserver: { capture: captureMock }, - claudeCodeHooks: undefined, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(checkpointCaptureMock).toHaveBeenCalledWith("ses_test") - expect(captureMock).toHaveBeenCalledWith("ses_test") - expect(contextMock).toHaveBeenCalledWith("ses_test") - expect(output.context).toEqual(["injected-context"]) - }) - - //#given compactionContextInjector is null - //#when compacting handler is invoked - //#then handler does not early-return, PreCompact hooks still execute - it("does not early-return when compactionContextInjector is null", async () => { - const preCompactMock = mock(async () => {}) - - const handler = createCompactingHandler({ - claudeCodeHooks: { - "experimental.session.compacting": preCompactMock, - }, - compactionContextInjector: undefined, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(preCompactMock).toHaveBeenCalled() - expect(output.context).toEqual([]) - }) -}) - -/** - * Tests for conditional tool registration logic in index.ts - * - * The actual plugin initialization is complex to test directly, - * so we test the underlying logic that determines tool registration. - */ -describe("look_at tool conditional registration", () => { - describe("isMultimodalLookerEnabled logic", () => { - // given multimodal-looker is in disabled_agents - // when checking if agent is enabled - // then should return false (disabled) - it("returns false when multimodal-looker is disabled (exact case)", () => { - const disabledAgents: string[] = ["multimodal-looker"] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(false) - }) - - // given multimodal-looker is in disabled_agents with different case - // when checking if agent is enabled - // then should return false (case-insensitive match) - it("returns false when multimodal-looker is disabled (case-insensitive)", () => { - const disabledAgents: string[] = ["Multimodal-Looker"] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(false) - }) - - // given multimodal-looker is NOT in disabled_agents - // when checking if agent is enabled - // then should return true (enabled) - it("returns true when multimodal-looker is not disabled", () => { - const disabledAgents: string[] = ["oracle", "librarian"] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(true) - }) - - // given disabled_agents is empty - // when checking if agent is enabled - // then should return true (enabled by default) - it("returns true when disabled_agents is empty", () => { - const disabledAgents: string[] = [] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(true) - }) - - // given disabled_agents is undefined (simulated as empty array) - // when checking if agent is enabled - // then should return true (enabled by default) - it("returns true when disabled_agents is undefined (fallback to empty)", () => { - const disabledAgents: string[] | undefined = undefined - const list: string[] = disabledAgents ?? [] - const isEnabled = !list.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(true) - }) - }) - - describe("conditional tool spread pattern", () => { - // given lookAt is not null (agent enabled) - // when spreading into tool object - // then look_at should be included - it("includes look_at when lookAt is not null", () => { - const lookAt = { execute: () => {} } // mock tool - const tools = { - ...(lookAt ? { look_at: lookAt } : {}), - } - expect(tools).toHaveProperty("look_at") - }) - - // given lookAt is null (agent disabled) - // when spreading into tool object - // then look_at should NOT be included - it("excludes look_at when lookAt is null", () => { - const lookAt = null - const tools = { - ...(lookAt ? { look_at: lookAt } : {}), - } - expect(tools).not.toHaveProperty("look_at") - }) - }) -}) - const mockInitConfigContext = mock(() => {}) const mockDetectExternalSkillPlugin = mock(() => ({ detected: false, pluginName: null })) const mockGetSkillPluginConflictWarning = mock(() => "") @@ -252,7 +34,6 @@ const mockCreateHooks = mock(() => ({ compactionTodoPreserver: undefined, claudeCodeHooks: undefined, })) -const mockCreatePluginDispose = mock(() => async () => {}) const mockCreatePluginInterface = mock(() => ({})) const mockInitializeOpenClaw = mock(async () => {}) const mockStartTmuxCheck = mock(() => {}) @@ -297,10 +78,6 @@ function installIndexModuleMocks(): void { createHooks: mockCreateHooks, })) - mock.module("./plugin-dispose", () => ({ - createPluginDispose: mockCreatePluginDispose, - })) - mock.module("./plugin-interface", () => ({ createPluginInterface: mockCreatePluginInterface, })) @@ -350,7 +127,6 @@ describe("OhMyOpenCodePlugin", () => { mockCreateManagers.mockClear() mockCreateTools.mockClear() mockCreateHooks.mockClear() - mockCreatePluginDispose.mockClear() mockCreatePluginInterface.mockClear() mockInitializeOpenClaw.mockClear() mockStartTmuxCheck.mockClear() diff --git a/src/plugin-dispose.test.ts b/src/plugin-dispose.test.ts deleted file mode 100644 index d0dd0285b..000000000 --- a/src/plugin-dispose.test.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { describe, expect, spyOn, test } from "bun:test" - -import { disposeCreatedHooks } from "./create-hooks" -import { createPluginDispose } from "./plugin-dispose" - -describe("createPluginDispose", () => { - test("#given plugin with active managers and hooks #when dispose() is called #then backgroundManager.shutdown() is called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const shutdownSpy = spyOn(backgroundManager, "shutdown") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => {}, - }) - - // when - await dispose() - - // then - expect(shutdownSpy).toHaveBeenCalledTimes(1) - }) - - test("#given plugin with active MCP connections #when dispose() is called #then skillMcpManager.disconnectAll() is called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disconnectAllSpy = spyOn(skillMcpManager, "disconnectAll") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => {}, - }) - - // when - await dispose() - - // then - expect(disconnectAllSpy).toHaveBeenCalledTimes(1) - }) - - test("#given plugin with hooks that have dispose #when dispose() is called #then each hook's dispose is called", async () => { - // given - const claudeCodeHooks = { - dispose: (): void => {}, - } - const commentChecker = { - dispose: (): void => {}, - } - const runtimeFallback = { - dispose: (): void => {}, - } - const todoContinuationEnforcer = { - dispose: (): void => {}, - } - const autoSlashCommand = { - dispose: (): void => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const claudeCodeHooksDisposeSpy = spyOn(claudeCodeHooks, "dispose") - const commentCheckerDisposeSpy = spyOn(commentChecker, "dispose") - const runtimeFallbackDisposeSpy = spyOn(runtimeFallback, "dispose") - const todoContinuationEnforcerDisposeSpy = spyOn(todoContinuationEnforcer, "dispose") - const autoSlashCommandDisposeSpy = spyOn(autoSlashCommand, "dispose") - const dispose = createPluginDispose({ - backgroundManager: { - shutdown: async (): Promise => {}, - }, - skillMcpManager: { - disconnectAll: async (): Promise => {}, - }, - lspManager, - disposeHooks: (): void => { - disposeCreatedHooks({ - claudeCodeHooks, - commentChecker, - runtimeFallback, - todoContinuationEnforcer, - autoSlashCommand, - }) - }, - }) - - // when - await dispose() - - // then - expect(claudeCodeHooksDisposeSpy).toHaveBeenCalledTimes(1) - expect(commentCheckerDisposeSpy).toHaveBeenCalledTimes(1) - expect(runtimeFallbackDisposeSpy).toHaveBeenCalledTimes(1) - expect(todoContinuationEnforcerDisposeSpy).toHaveBeenCalledTimes(1) - expect(autoSlashCommandDisposeSpy).toHaveBeenCalledTimes(1) - }) - - test("#given dispose already called #when dispose() called again #then no errors", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disposeHooks = { - run: (): void => {}, - } - const shutdownSpy = spyOn(backgroundManager, "shutdown") - const disconnectAllSpy = spyOn(skillMcpManager, "disconnectAll") - const stopAllSpy = spyOn(lspManager, "stopAll") - const disposeHooksSpy = spyOn(disposeHooks, "run") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: disposeHooks.run, - }) - - // when - await dispose() - await dispose() - - // then - expect(shutdownSpy).toHaveBeenCalledTimes(1) - expect(disconnectAllSpy).toHaveBeenCalledTimes(1) - expect(stopAllSpy).toHaveBeenCalledTimes(1) - expect(disposeHooksSpy).toHaveBeenCalledTimes(1) - }) - - test("#given backgroundManager.shutdown() throws #when dispose() is called #then skillMcpManager.disconnectAll() and disposeHooks() are still called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => { - throw new Error("shutdown failed") - }, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disposeHooksCalls: number[] = [] - const disconnectAllSpy = spyOn(skillMcpManager, "disconnectAll") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => { - disposeHooksCalls.push(1) - }, - }) - - // when - await dispose() - - // then - expect(disconnectAllSpy).toHaveBeenCalledTimes(1) - expect(disposeHooksCalls).toHaveLength(1) - }) - - test("#given skillMcpManager.disconnectAll() throws #when dispose() is called #then disposeHooks() is still called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => { - throw new Error("disconnectAll failed") - }, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disposeHooksCalls: number[] = [] - const shutdownSpy = spyOn(backgroundManager, "shutdown") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => { - disposeHooksCalls.push(1) - }, - }) - - // when - await dispose() - - // then - expect(shutdownSpy).toHaveBeenCalledTimes(1) - expect(disposeHooksCalls).toHaveLength(1) - }) - - test("#given active LSP clients #when dispose runs #then lsp manager is stopped", async () => { - // given - const lspManager = { - stopAll: async (): Promise => {}, - } - const stopAllSpy = spyOn(lspManager, "stopAll") - const dispose = createPluginDispose({ - backgroundManager: { - shutdown: async (): Promise => {}, - }, - skillMcpManager: { - disconnectAll: async (): Promise => {}, - }, - lspManager, - disposeHooks: (): void => {}, - }) - - // when - await dispose() - - // then - expect(stopAllSpy).toHaveBeenCalledTimes(1) - }) -}) diff --git a/src/plugin-dispose.ts b/src/plugin-dispose.ts deleted file mode 100644 index 998fd28eb..000000000 --- a/src/plugin-dispose.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { log } from "./shared" - -export type PluginDispose = () => Promise - -export function createPluginDispose(args: { - backgroundManager: { - shutdown: () => void | Promise - } - skillMcpManager: { - disconnectAll: () => Promise - } - lspManager: { - stopAll: () => Promise - } - disposeHooks: () => void -}): PluginDispose { - const { backgroundManager, skillMcpManager, lspManager, disposeHooks } = args - let disposePromise: Promise | null = null - - return async (): Promise => { - if (disposePromise) { - await disposePromise - return - } - - disposePromise = (async (): Promise => { - try { - await backgroundManager.shutdown() - } catch (error) { - log("[plugin-dispose] backgroundManager.shutdown() error:", error) - } - try { - await skillMcpManager.disconnectAll() - } catch (error) { - log("[plugin-dispose] skillMcpManager.disconnectAll() error:", error) - } - try { - await lspManager.stopAll() - } catch (error) { - log("[plugin-dispose] lspManager.stopAll() error:", error) - } - try { - disposeHooks() - } catch (error) { - log("[plugin-dispose] disposeHooks() error:", error) - } - })() - - await disposePromise - } -} From 5e4102566cd7a53c3cc7fed49ee2a85e90211595 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 02:35:46 +0900 Subject: [PATCH 042/146] refactor(model-fallback): fully encapsulate session state in factory closure Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/create-hooks.ts | 4 + src/create-managers.ts | 5 + src/create-tools.ts | 2 +- src/hooks/index.ts | 8 +- .../model-fallback/controller-accessor.ts | 30 +++++ src/hooks/model-fallback/hook.test.ts | 77 +++++++----- src/hooks/model-fallback/hook.ts | 117 ++++++++++++------ src/hooks/model-fallback/index.ts | 2 + src/index.ts | 1 + src/plugin/event.model-fallback-2941.test.ts | 21 ++-- src/plugin/event.model-fallback.test.ts | 13 +- src/plugin/event.test.ts | 3 +- src/plugin/event.ts | 31 +++-- .../fallback.cliproxyapi-matrix.test.ts | 2 - src/plugin/hooks/create-core-hooks.ts | 5 +- src/plugin/hooks/create-session-hooks.ts | 5 +- src/plugin/tool-registry.ts | 4 +- src/tools/call-omo-agent/sync-executor.ts | 9 +- src/tools/call-omo-agent/tools.ts | 39 +++++- src/tools/delegate-task/background-task.ts | 7 +- src/tools/delegate-task/executor-types.ts | 2 + src/tools/delegate-task/sync-task.ts | 5 +- src/tools/delegate-task/types.ts | 2 + 23 files changed, 271 insertions(+), 123 deletions(-) create mode 100644 src/hooks/model-fallback/controller-accessor.ts create mode 100644 src/hooks/model-fallback/index.ts diff --git a/src/create-hooks.ts b/src/create-hooks.ts index 0e40ad480..436f8e2b9 100644 --- a/src/create-hooks.ts +++ b/src/create-hooks.ts @@ -2,6 +2,7 @@ import type { AvailableSkill } from "./agents/dynamic-agent-prompt-builder" import type { HookName, OhMyOpenCodeConfig } from "./config" import type { LoadedSkill } from "./features/opencode-skill-loader/types" import type { BackgroundManager } from "./features/background-agent" +import type { ModelFallbackControllerAccessor } from "./hooks/model-fallback" import type { PluginContext } from "./plugin/types" import type { ModelCacheState } from "./plugin-state" @@ -36,6 +37,7 @@ export function createHooks(args: { pluginConfig: OhMyOpenCodeConfig modelCacheState: ModelCacheState backgroundManager: BackgroundManager + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean mergedSkills: LoadedSkill[] @@ -46,6 +48,7 @@ export function createHooks(args: { pluginConfig, modelCacheState, backgroundManager, + modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, mergedSkills, @@ -56,6 +59,7 @@ export function createHooks(args: { ctx, pluginConfig, modelCacheState, + modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, }) diff --git a/src/create-managers.ts b/src/create-managers.ts index d40896343..9c0013fd4 100644 --- a/src/create-managers.ts +++ b/src/create-managers.ts @@ -5,6 +5,7 @@ import type { PluginContext, TmuxConfig } from "./plugin/types" import type { SubagentSessionCreatedEvent } from "./features/background-agent" import { BackgroundManager } from "./features/background-agent" import { SkillMcpManager } from "./features/skill-mcp-manager" +import { createModelFallbackControllerAccessor } from "./hooks/model-fallback" import { initTaskToastManager } from "./features/task-toast-manager" import { TmuxSessionManager } from "./features/tmux-subagent" import * as openclawRuntimeDispatch from "./openclaw/runtime-dispatch" @@ -12,6 +13,7 @@ import { registerManagerForCleanup } from "./features/background-agent/process-c import { createConfigHandler } from "./plugin-handlers" import { log } from "./shared" import { markServerRunningInProcess } from "./shared/tmux/tmux-utils/server-health" +import type { ModelFallbackControllerAccessor } from "./hooks/model-fallback" type CreateManagersDeps = { BackgroundManagerClass: typeof BackgroundManager @@ -38,6 +40,7 @@ export type Managers = { backgroundManager: BackgroundManager skillMcpManager: SkillMcpManager configHandler: ReturnType + modelFallbackControllerAccessor: ModelFallbackControllerAccessor } export function createManagers(args: { @@ -119,11 +122,13 @@ export function createManagers(args: { pluginConfig, modelCacheState, }) + const modelFallbackControllerAccessor = createModelFallbackControllerAccessor() return { tmuxSessionManager, backgroundManager, skillMcpManager, configHandler, + modelFallbackControllerAccessor, } } diff --git a/src/create-tools.ts b/src/create-tools.ts index 5ac5a7e2f..6a9bc3941 100644 --- a/src/create-tools.ts +++ b/src/create-tools.ts @@ -22,7 +22,7 @@ type CreateToolsResult = { export async function createTools(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig - managers: Pick + managers: Pick }): Promise { const { ctx, pluginConfig, managers } = args diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 051cbd12a..8fd15af2f 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -14,7 +14,13 @@ export { createEmptyTaskResponseDetectorHook } from "./empty-task-response-detec export { createAnthropicContextWindowLimitRecoveryHook, type AnthropicContextWindowLimitRecoveryOptions } from "./anthropic-context-window-limit-recovery"; export { createThinkModeHook } from "./think-mode"; -export { createModelFallbackHook, setPendingModelFallback, clearPendingModelFallback, type ModelFallbackState } from "./model-fallback/hook"; +export { + createModelFallbackHook, + setPendingModelFallback, + clearPendingModelFallback, + type ModelFallbackHook, + type ModelFallbackState, +} from "./model-fallback/hook"; export { createClaudeCodeHooksHook } from "./claude-code-hooks"; export { createRulesInjectorHook } from "./rules-injector"; export { createBackgroundNotificationHook } from "./background-notification" diff --git a/src/hooks/model-fallback/controller-accessor.ts b/src/hooks/model-fallback/controller-accessor.ts new file mode 100644 index 000000000..281ae9931 --- /dev/null +++ b/src/hooks/model-fallback/controller-accessor.ts @@ -0,0 +1,30 @@ +import type { FallbackEntry } from "../../shared/model-requirements" +import type { ModelFallbackStateController } from "./fallback-state-controller" + +export type ModelFallbackControllerAccessor = { + register: (controller: ModelFallbackStateController) => void + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => void + clearSessionFallbackChain: (sessionID: string) => void +} + +export function createModelFallbackControllerAccessor(): ModelFallbackControllerAccessor { + let controller: ModelFallbackStateController | null = null + + function register(nextController: ModelFallbackStateController): void { + controller = nextController + } + + function setSessionFallbackChain(sessionID: string, fallbackChain: FallbackEntry[] | undefined): void { + controller?.setSessionFallbackChain(sessionID, fallbackChain) + } + + function clearSessionFallbackChain(sessionID: string): void { + controller?.clearSessionFallbackChain(sessionID) + } + + return { + register, + setSessionFallbackChain, + clearSessionFallbackChain, + } +} diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index 14b3ff6bb..de9e66fd7 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -70,22 +70,23 @@ const { setPendingModelFallback, } = await importFreshModelFallbackHookModule() +type ModelFallbackHook = ReturnType + describe("model fallback hook", () => { + let modelFallback: ModelFallbackHook + beforeEach(() => { + modelFallback = createModelFallbackHook() readConnectedProvidersCacheMock.mockReturnValue(null) readProviderModelsCacheMock.mockReturnValue(null) readConnectedProvidersCacheMock.mockClear() readProviderModelsCacheMock.mockClear() selectFallbackProviderMock.mockClear() - - clearPendingModelFallback("ses_model_fallback_main") - clearPendingModelFallback("ses_model_fallback_ghcp") - clearPendingModelFallback("ses_model_fallback_google") }) test("applies pending fallback on chat.message by overriding model", async () => { //#given - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -93,6 +94,7 @@ describe("model fallback hook", () => { } const set = setPendingModelFallback( + modelFallback, "ses_model_fallback_main", "Sisyphus - Ultraworker", "anthropic", @@ -123,7 +125,7 @@ describe("model fallback hook", () => { test("preserves fallback progression across repeated session.error retries", async () => { //#given - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -132,7 +134,7 @@ describe("model fallback hook", () => { const sessionID = "ses_model_fallback_main" expect( - setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7-thinking"), + setPendingModelFallback(modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7-thinking"), ).toBe(true) const firstOutput = { @@ -154,7 +156,7 @@ describe("model fallback hook", () => { //#when - second error re-arms fallback and should advance to next entry expect( - setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7"), + setPendingModelFallback(modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7"), ).toBe(true) const secondOutput = { @@ -176,16 +178,18 @@ describe("model fallback hook", () => { test("does not re-arm fallback when one is already pending", () => { //#given const sessionID = "ses_model_fallback_pending_guard" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) //#when const firstSet = setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7-thinking", ) const secondSet = setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", @@ -195,28 +199,29 @@ describe("model fallback hook", () => { //#then expect(firstSet).toBe(true) expect(secondSet).toBe(false) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("skips no-op fallback entries that resolve to same provider/model", async () => { //#given const sessionID = "ses_model_fallback_noop_skip" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, ) => Promise } - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["anthropic"], model: "claude-opus-4-7" }, { providers: ["opencode"], model: "kimi-k2.5-free" }, ]) expect( setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", @@ -239,28 +244,29 @@ describe("model fallback hook", () => { providerID: "opencode", modelID: "kimi-k2.5-free", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("skips no-op fallback entries even when variant differs", async () => { //#given const sessionID = "ses_model_fallback_noop_variant_skip" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, ) => Promise } - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["quotio"], model: "claude-opus-4-7", variant: "max" }, { providers: ["quotio"], model: "gpt-5.2" }, ]) expect( setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "quotio", @@ -285,28 +291,29 @@ describe("model fallback hook", () => { modelID: "gpt-5.2", }) expect(output.message["variant"]).toBeUndefined() - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("uses connected preferred provider when fallback entry providers are disconnected", async () => { //#given const sessionID = "ses_model_fallback_preferred_provider" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) readConnectedProvidersCacheMock.mockReturnValue(["provider-x"]) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, ) => Promise } - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["provider-y"], model: "fallback-model" }, ]) expect( setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "provider-x", @@ -329,17 +336,18 @@ describe("model fallback hook", () => { providerID: "provider-x", modelID: "fallback-model", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("does not fall back to hardcoded agent chain when session explicitly stores no fallback chain [regression #2941]", () => { //#given const sessionID = "ses_model_fallback_explicit_none" - clearPendingModelFallback(sessionID) - setSessionFallbackChain(sessionID, undefined) + clearPendingModelFallback(modelFallback, sessionID) + setSessionFallbackChain(modelFallback, sessionID, undefined) //#when const set = setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Junior", "anthropic", @@ -348,7 +356,7 @@ describe("model fallback hook", () => { //#then expect(set).toBe(false) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("shows toast when fallback is applied", async () => { @@ -366,6 +374,7 @@ describe("model fallback hook", () => { } const set = setPendingModelFallback( + hook, "ses_model_fallback_toast", "Sisyphus - Ultraworker", "anthropic", @@ -392,9 +401,9 @@ describe("model fallback hook", () => { test("transforms model names for github-copilot provider via fallback chain", async () => { //#given const sessionID = "ses_model_fallback_ghcp" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -402,11 +411,12 @@ describe("model fallback hook", () => { } // Set a custom fallback chain that routes through github-copilot - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["github-copilot"], model: "claude-sonnet-4-6" }, ]) const set = setPendingModelFallback( + modelFallback, sessionID, "Atlas - Plan Executor", "github-copilot", @@ -430,15 +440,15 @@ describe("model fallback hook", () => { modelID: "claude-sonnet-4.6", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("preserves canonical google preview model names via fallback chain", async () => { //#given const sessionID = "ses_model_fallback_google" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -446,11 +456,12 @@ describe("model fallback hook", () => { } // Set a custom fallback chain that routes through google - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["google"], model: "gemini-3.1-pro-preview" }, ]) const set = setPendingModelFallback( + modelFallback, sessionID, "Oracle", "google", @@ -474,7 +485,7 @@ describe("model fallback hook", () => { modelID: "gemini-3.1-pro-preview", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) }) diff --git a/src/hooks/model-fallback/hook.ts b/src/hooks/model-fallback/hook.ts index 191a58e3a..fee130ed8 100644 --- a/src/hooks/model-fallback/hook.ts +++ b/src/hooks/model-fallback/hook.ts @@ -5,6 +5,7 @@ import { createModelFallbackStateController, type ModelFallbackStateController, } from "./fallback-state-controller" +import type { ModelFallbackControllerAccessor } from "./controller-accessor" type FallbackToast = (input: { title: string @@ -28,26 +29,45 @@ export type ModelFallbackState = { pending: boolean } -const modelFallbackControllerRef: { current?: ModelFallbackStateController } = {} +type ModelFallbackControllerWithState = Pick< + ModelFallbackStateController, + | "lastToastKey" + | "setSessionFallbackChain" + | "clearSessionFallbackChain" + | "setPendingModelFallback" + | "getNextFallback" + | "clearPendingModelFallback" + | "hasPendingModelFallback" + | "getFallbackState" + | "reset" +> -function getOrCreateModelFallbackController(): ModelFallbackStateController { - if (!modelFallbackControllerRef.current) { - createModelFallbackHook() - } - - const controller = modelFallbackControllerRef.current - if (!controller) { - throw new Error("Model fallback controller should be initialized") - } - return controller +export type ModelFallbackHook = ModelFallbackControllerWithState & { + "chat.message": ( + input: ChatMessageInput, + output: ChatMessageHandlerOutput, + ) => Promise } -export function setSessionFallbackChain(sessionID: string, fallbackChain: FallbackEntry[] | undefined): void { - getOrCreateModelFallbackController().setSessionFallbackChain(sessionID, fallbackChain) +type ModelFallbackHookArgs = { + toast?: FallbackToast + onApplied?: FallbackCallback + controllerAccessor?: ModelFallbackControllerAccessor } -export function clearSessionFallbackChain(sessionID: string): void { - getOrCreateModelFallbackController().clearSessionFallbackChain(sessionID) +export function setSessionFallbackChain( + controller: Pick, + sessionID: string, + fallbackChain: FallbackEntry[] | undefined, +): void { + controller.setSessionFallbackChain(sessionID, fallbackChain) +} + +export function clearSessionFallbackChain( + controller: Pick, + sessionID: string, +): void { + controller.clearSessionFallbackChain(sessionID) } /** @@ -55,12 +75,13 @@ export function clearSessionFallbackChain(sessionID: string): void { * Called when a model error is detected in session.error handler. */ export function setPendingModelFallback( + controller: Pick, sessionID: string, agentName: string, currentProviderID: string, currentModelID: string, ): boolean { - return getOrCreateModelFallbackController().setPendingModelFallback( + return controller.setPendingModelFallback( sessionID, agentName, currentProviderID, @@ -73,54 +94,71 @@ export function setPendingModelFallback( * Increments attemptCount each time called. */ export function getNextFallback( + controller: Pick, sessionID: string, ): { providerID: string; modelID: string; variant?: string } | null { - return getOrCreateModelFallbackController().getNextFallback(sessionID) + return controller.getNextFallback(sessionID) } /** * Clears the pending fallback for a session. * Called after fallback is successfully applied. */ -export function clearPendingModelFallback(sessionID: string): void { - getOrCreateModelFallbackController().clearPendingModelFallback(sessionID) +export function clearPendingModelFallback( + controller: Pick, + sessionID: string, +): void { + controller.clearPendingModelFallback(sessionID) } /** * Checks if there's a pending fallback for a session. */ -export function hasPendingModelFallback(sessionID: string): boolean { - return getOrCreateModelFallbackController().hasPendingModelFallback(sessionID) +export function hasPendingModelFallback( + controller: Pick, + sessionID: string, +): boolean { + return controller.hasPendingModelFallback(sessionID) } /** * Gets the current fallback state for a session (for debugging). */ -export function getFallbackState(sessionID: string): ModelFallbackState | undefined { - return getOrCreateModelFallbackController().getFallbackState(sessionID) +export function getFallbackState( + controller: Pick, + sessionID: string, +): ModelFallbackState | undefined { + return controller.getFallbackState(sessionID) } /** * Creates a chat.message hook that applies model fallbacks when pending. */ -export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplied?: FallbackCallback }) { - if (!modelFallbackControllerRef.current) { - const pendingModelFallbacks = new Map() - const lastToastKey = new Map() - const sessionFallbackChains = new Map() +export function createModelFallbackHook(args?: ModelFallbackHookArgs): ModelFallbackHook { + const pendingModelFallbacks = new Map() + const lastToastKey = new Map() + const sessionFallbackChains = new Map() + const controller = createModelFallbackStateController({ + pendingModelFallbacks, + lastToastKey, + sessionFallbackChains, + }) - modelFallbackControllerRef.current = createModelFallbackStateController({ - pendingModelFallbacks, - lastToastKey, - sessionFallbackChains, - }) - } + args?.controllerAccessor?.register(controller) - const controller = getOrCreateModelFallbackController() const toast = args?.toast const onApplied = args?.onApplied return { + lastToastKey: controller.lastToastKey, + setSessionFallbackChain: controller.setSessionFallbackChain, + clearSessionFallbackChain: controller.clearSessionFallbackChain, + setPendingModelFallback: controller.setPendingModelFallback, + getNextFallback: controller.getNextFallback, + clearPendingModelFallback: controller.clearPendingModelFallback, + hasPendingModelFallback: controller.hasPendingModelFallback, + getFallbackState: controller.getFallbackState, + reset: controller.reset, "chat.message": async ( input: ChatMessageInput, output: ChatMessageHandlerOutput, @@ -128,7 +166,7 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie const { sessionID } = input if (!sessionID) return - const fallback = getNextFallback(sessionID) + const fallback = getNextFallback(controller, sessionID) if (!fallback) return await applyFallbackToChatMessage({ @@ -144,9 +182,8 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie } /** - * Resets all module-global state for testing. - * Clears pending fallbacks, toast keys, and session chains. + * Resets hook-owned state for testing. */ -export function _resetForTesting(): void { - getOrCreateModelFallbackController().reset() +export function _resetForTesting(controller?: Pick): void { + controller?.reset() } diff --git a/src/hooks/model-fallback/index.ts b/src/hooks/model-fallback/index.ts new file mode 100644 index 000000000..08e4c0dd7 --- /dev/null +++ b/src/hooks/model-fallback/index.ts @@ -0,0 +1,2 @@ +export { createModelFallbackControllerAccessor } from "./controller-accessor" +export type { ModelFallbackControllerAccessor } from "./controller-accessor" diff --git a/src/index.ts b/src/index.ts index b41f611e1..2c24e003e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -91,6 +91,7 @@ const serverPlugin: Plugin = async (input, _options): Promise => { pluginConfig, modelCacheState, backgroundManager: managers.backgroundManager, + modelFallbackControllerAccessor: managers.modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, mergedSkills: toolsResult.mergedSkills, diff --git a/src/plugin/event.model-fallback-2941.test.ts b/src/plugin/event.model-fallback-2941.test.ts index 46765a5d9..2b97d2cb7 100644 --- a/src/plugin/event.model-fallback-2941.test.ts +++ b/src/plugin/event.model-fallback-2941.test.ts @@ -65,13 +65,13 @@ function createChatMessageHandlerHooks(modelFallback: ReturnType void } | undefined let readProviderModelsCacheSpy: { mockRestore: () => void } | undefined -afterEach(() => { - readConnectedProvidersCacheSpy?.mockRestore() - readProviderModelsCacheSpy?.mockRestore() - readConnectedProvidersCacheSpy = undefined - readProviderModelsCacheSpy = undefined - _resetForTesting() -}) + afterEach(() => { + readConnectedProvidersCacheSpy?.mockRestore() + readProviderModelsCacheSpy?.mockRestore() + readConnectedProvidersCacheSpy = undefined + readProviderModelsCacheSpy = undefined + _resetForTesting() + }) describe("createEventHandler - category runtime fallback suppression", () => { test("does not arm retry fallback when category session explicitly stores no fallback chain [regression #2941]", async () => { @@ -83,11 +83,10 @@ describe("createEventHandler - category runtime fallback suppression", () => { readConnectedProvidersCacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) readProviderModelsCacheSpy = spyOn(connectedProvidersCache, "readProviderModelsCache").mockReturnValue(null) - clearPendingModelFallback(sessionID) - setSessionAgent(sessionID, "sisyphus-junior") - setSessionFallbackChain(sessionID, undefined) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) + setSessionAgent(sessionID, "sisyphus-junior") + setSessionFallbackChain(modelFallback, sessionID, undefined) const eventHandler = createEventHandler({ ctx: asEventHandlerContext({ directory: "/tmp", diff --git a/src/plugin/event.model-fallback.test.ts b/src/plugin/event.model-fallback.test.ts index 3e82817ff..967608f09 100644 --- a/src/plugin/event.model-fallback.test.ts +++ b/src/plugin/event.model-fallback.test.ts @@ -142,9 +142,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_fallback" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const { handler, abortCalls, promptCalls } = createHandler({ hooks: { modelFallback } }) @@ -232,8 +231,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_dedup" setMainSession(sessionID) - clearPendingModelFallback(sessionID) const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const { handler, abortCalls, promptCalls } = createHandler({ hooks: { modelFallback } }) await handler({ @@ -293,8 +292,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_runtime_enabled" setMainSession(sessionID) - clearPendingModelFallback(sessionID) const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const runtimeFallback = { event: async () => {}, "chat.message": async () => {}, @@ -346,9 +345,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_user_fallback" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const pluginConfig = { agents: { sisyphus: { @@ -446,9 +444,8 @@ describe("createEventHandler - model fallback", () => { const toastCalls: string[] = [] const sessionID = "ses_main_fallback_chain" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) setupConnectedProviderCacheMocks() const eventHandler = createEventHandler({ diff --git a/src/plugin/event.test.ts b/src/plugin/event.test.ts index cb87efff4..ea880c145 100644 --- a/src/plugin/event.test.ts +++ b/src/plugin/event.test.ts @@ -761,11 +761,10 @@ describe("createEventHandler - retry dedupe lifecycle", () => { //#given const sessionID = "ses_retry_recovery_rearm" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const abortCalls: string[] = [] const promptCalls: string[] = [] const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const eventHandler = createEventHandler({ ctx: asEventHandlerContext({ diff --git a/src/plugin/event.ts b/src/plugin/event.ts index 6d70d7951..5a5f177b6 100644 --- a/src/plugin/event.ts +++ b/src/plugin/event.ts @@ -15,6 +15,7 @@ import { clearSessionFallbackChain, setSessionFallbackChain, setPendingModelFallback, + type ModelFallbackHook, } from "../hooks/model-fallback/hook"; import { getRawFallbackModels } from "../hooks/runtime-fallback/fallback-models"; import { @@ -111,6 +112,7 @@ function extractProviderModelFromErrorMessage(message: string): { providerID?: s return {}; } function applyUserConfiguredFallbackChain( + modelFallback: Pick | null | undefined, sessionID: string, agentName: string, currentProviderID: string, @@ -123,7 +125,9 @@ function applyUserConfiguredFallbackChain( const fallbackChain = buildFallbackChainFromModels(rawFallbackModels, currentProviderID); if (fallbackChain && fallbackChain.length > 0) { - setSessionFallbackChain(sessionID, fallbackChain); + if (modelFallback) { + setSessionFallbackChain(modelFallback, sessionID, fallbackChain); + } } } @@ -170,6 +174,7 @@ export function createEventHandler(args: { const isModelFallbackEnabled = hooks.modelFallback !== null && hooks.modelFallback !== undefined; + const modelFallback = hooks.modelFallback; // Avoid triggering multiple abort+continue cycles for the same failing assistant message. const lastHandledModelErrorMessageID = new Map(); @@ -408,8 +413,10 @@ export function createEventHandler(args: { lastHandledModelErrorMessageID.delete(sessionInfo.id); lastHandledRetryStatusKey.delete(sessionInfo.id); lastKnownModelBySession.delete(sessionInfo.id); - clearPendingModelFallback(sessionInfo.id); - clearSessionFallbackChain(sessionInfo.id); + if (modelFallback) { + clearPendingModelFallback(modelFallback, sessionInfo.id); + clearSessionFallbackChain(modelFallback, sessionInfo.id); + } resetMessageCursor(sessionInfo.id); clearBackgroundOutputConsumptionsForParentSession(sessionInfo.id); clearBackgroundOutputConsumptionsForTaskSession(sessionInfo.id); @@ -517,9 +524,11 @@ export function createEventHandler(args: { ); const rawModel = (info?.modelID as string | undefined) ?? "claude-opus-4-7"; const currentModel = normalizeFallbackModelID(rawModel); - applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); + applyUserConfiguredFallbackChain(modelFallback, sessionID, agentName, currentProvider, args.pluginConfig); - const setFallback = setPendingModelFallback(sessionID, agentName, currentProvider, currentModel); + const setFallback = modelFallback + ? setPendingModelFallback(modelFallback, sessionID, agentName, currentProvider, currentModel) + : false; if ( setFallback && @@ -580,9 +589,11 @@ export function createEventHandler(args: { const currentProvider = resolveFallbackProviderID(sessionID, parsed.providerID); let currentModel = parsed.modelID ?? lastKnown?.modelID ?? "claude-opus-4-7"; currentModel = normalizeFallbackModelID(currentModel); - applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); + applyUserConfiguredFallbackChain(modelFallback, sessionID, agentName, currentProvider, args.pluginConfig); - const setFallback = setPendingModelFallback(sessionID, agentName, currentProvider, currentModel); + const setFallback = modelFallback + ? setPendingModelFallback(modelFallback, sessionID, agentName, currentProvider, currentModel) + : false; if ( setFallback && @@ -666,9 +677,11 @@ export function createEventHandler(args: { ); let currentModel = (props?.modelID as string) || parsed.modelID || "claude-opus-4-7"; currentModel = normalizeFallbackModelID(currentModel); - applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); + applyUserConfiguredFallbackChain(modelFallback, sessionID, agentName, currentProvider, args.pluginConfig); - const setFallback = setPendingModelFallback(sessionID, agentName, currentProvider, currentModel); + const setFallback = modelFallback + ? setPendingModelFallback(modelFallback, sessionID, agentName, currentProvider, currentModel) + : false; if ( setFallback && diff --git a/src/plugin/fallback.cliproxyapi-matrix.test.ts b/src/plugin/fallback.cliproxyapi-matrix.test.ts index d5e810745..3d1b5fd4c 100644 --- a/src/plugin/fallback.cliproxyapi-matrix.test.ts +++ b/src/plugin/fallback.cliproxyapi-matrix.test.ts @@ -9,7 +9,6 @@ import { createModelFallbackHook } from "../hooks/model-fallback/hook" import { createRuntimeFallbackHook } from "../hooks/runtime-fallback" import type { RuntimeFallbackPluginInput } from "../hooks/runtime-fallback/types" import { _resetForTesting } from "../features/claude-code-session-state" -import { _resetForTesting as _resetModelFallbackForTesting } from "../hooks/model-fallback/hook" import { SessionCategoryRegistry } from "../shared/session-category-registry" import * as connectedProvidersCache from "../shared/connected-providers-cache" @@ -369,7 +368,6 @@ function setupConnectedProviderCacheMocks(): void { afterEach(() => { _resetForTesting() - _resetModelFallbackForTesting() SessionCategoryRegistry.clear() }) diff --git a/src/plugin/hooks/create-core-hooks.ts b/src/plugin/hooks/create-core-hooks.ts index 4da2b5085..5a36aa026 100644 --- a/src/plugin/hooks/create-core-hooks.ts +++ b/src/plugin/hooks/create-core-hooks.ts @@ -1,4 +1,5 @@ import type { HookName, OhMyOpenCodeConfig } from "../../config" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { PluginContext } from "../types" import type { ModelCacheState } from "../../plugin-state" @@ -10,15 +11,17 @@ export function createCoreHooks(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig modelCacheState: ModelCacheState + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean }) { - const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args + const { ctx, pluginConfig, modelCacheState, modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled } = args const session = createSessionHooks({ ctx, pluginConfig, modelCacheState, + modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, }) diff --git a/src/plugin/hooks/create-session-hooks.ts b/src/plugin/hooks/create-session-hooks.ts index af87bd366..9d437bc75 100644 --- a/src/plugin/hooks/create-session-hooks.ts +++ b/src/plugin/hooks/create-session-hooks.ts @@ -1,4 +1,5 @@ import type { OhMyOpenCodeConfig, HookName } from "../../config" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { ModelCacheState } from "../../plugin-state" import type { PluginContext } from "../types" @@ -69,10 +70,11 @@ export function createSessionHooks(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig modelCacheState: ModelCacheState + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean }): SessionHooks { - const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args + const { ctx, pluginConfig, modelCacheState, modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled } = args const safeHook = (hookName: HookName, factory: () => T): T | null => safeCreateHook(hookName, factory, { enabled: safeHookEnabled }) @@ -171,6 +173,7 @@ export function createSessionHooks(args: { .catch(() => {}) }, onApplied: enableFallbackTitle ? updateFallbackTitle : undefined, + controllerAccessor: modelFallbackControllerAccessor, })) : null diff --git a/src/plugin/tool-registry.ts b/src/plugin/tool-registry.ts index 6d04e7e1c..a3e46185a 100644 --- a/src/plugin/tool-registry.ts +++ b/src/plugin/tool-registry.ts @@ -144,7 +144,7 @@ export function trimToolsToCap(filteredTools: ToolsRecord, maxTools: number): vo export function createToolRegistry(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig - managers: Pick + managers: Pick skillContext: SkillContext availableCategories: AvailableCategory[] interactiveBashEnabled?: boolean @@ -170,6 +170,7 @@ export function createToolRegistry(args: { pluginConfig.disabled_agents ?? [], pluginConfig.agents, pluginConfig.categories, + managers.modelFallbackControllerAccessor, ) const isMultimodalLookerEnabled = !(pluginConfig.disabled_agents ?? []).some( @@ -191,6 +192,7 @@ export function createToolRegistry(args: { availableSkills: skillContext.availableSkills, sisyphusAgentConfig: pluginConfig.sisyphus_agent, syncPollTimeoutMs: pluginConfig.background_task?.syncPollTimeoutMs, + modelFallbackControllerAccessor: managers.modelFallbackControllerAccessor, onSyncSessionCreated: async (event) => { log("[index] onSyncSessionCreated callback", { sessionID: event.sessionID, diff --git a/src/tools/call-omo-agent/sync-executor.ts b/src/tools/call-omo-agent/sync-executor.ts index 23089d8ea..56e22a80a 100644 --- a/src/tools/call-omo-agent/sync-executor.ts +++ b/src/tools/call-omo-agent/sync-executor.ts @@ -1,7 +1,6 @@ import type { CallOmoAgentArgs } from "./types" import type { PluginInput } from "@opencode-ai/plugin" import { subagentSessions, syncSubagentSessions } from "../../features/claude-code-session-state" -import { clearSessionFallbackChain, setSessionFallbackChain } from "../../hooks/model-fallback/hook" import { getAgentToolRestrictions, log } from "../../shared" import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers" import type { DelegatedModelConfig } from "../../shared/model-resolution-types" @@ -19,8 +18,8 @@ type ExecuteSyncDeps = { createOrGetSession: typeof createOrGetSession waitForCompletion: typeof waitForCompletion processMessages: typeof processMessages - setSessionFallbackChain: typeof setSessionFallbackChain - clearSessionFallbackChain: typeof clearSessionFallbackChain + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => void + clearSessionFallbackChain: (sessionID: string) => void } type SpawnReservation = { @@ -32,8 +31,8 @@ const defaultDeps: ExecuteSyncDeps = { createOrGetSession, waitForCompletion, processMessages, - setSessionFallbackChain, - clearSessionFallbackChain, + setSessionFallbackChain: () => {}, + clearSessionFallbackChain: () => {}, } function buildPromptGenerationParams(model: DelegatedModelConfig | undefined): Record { diff --git a/src/tools/call-omo-agent/tools.ts b/src/tools/call-omo-agent/tools.ts index 839f5abe8..51ea8730c 100644 --- a/src/tools/call-omo-agent/tools.ts +++ b/src/tools/call-omo-agent/tools.ts @@ -2,6 +2,7 @@ import { tool, type PluginInput, type ToolDefinition } from "@opencode-ai/plugin import { ALLOWED_AGENTS, CALL_OMO_AGENT_DESCRIPTION } from "./constants" import type { CallOmoAgentArgs, ToolContextWithMetadata } from "./types" import type { BackgroundManager } from "../../features/background-agent" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { CategoriesConfig, AgentOverrides } from "../../config/schema" import type { DelegatedModelConfig } from "../../shared/model-resolution-types" import type { FallbackEntry } from "../../shared/model-requirements" @@ -15,6 +16,23 @@ import { parseModelString } from "../../shared" import { executeBackground } from "./background-executor" import { executeSync } from "./sync-executor" import { resolveCallableAgents } from "./agent-resolver" +import { createOrGetSession } from "./session-creator" +import { processMessages } from "./message-processor" +import { waitForCompletion } from "./completion-poller" + +function createSyncExecutorDeps(modelFallbackControllerAccessor?: ModelFallbackControllerAccessor) { + return { + createOrGetSession, + waitForCompletion, + processMessages, + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => { + modelFallbackControllerAccessor?.setSessionFallbackChain(sessionID, fallbackChain) + }, + clearSessionFallbackChain: (sessionID: string) => { + modelFallbackControllerAccessor?.clearSessionFallbackChain(sessionID) + }, + } +} function resolveModelAndFallbackChain(args: { subagentType: string @@ -82,6 +100,7 @@ export function createCallOmoAgent( disabledAgents: string[] = [], agentOverrides?: AgentOverrides, userCategories?: CategoriesConfig, + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor, ): ToolDefinition { const agentDescriptions = ALLOWED_AGENTS.map( (name) => `- ${name}: Specialized agent for ${name} tasks`, @@ -158,14 +177,30 @@ export function createCallOmoAgent( let spawnReservation: Awaited> | undefined try { spawnReservation = await backgroundManager.reserveSubagentSpawn(toolCtx.sessionID) - return await executeSync(args, toolCtx, ctx, undefined, fallbackChain, spawnReservation, resolvedModel) + return await executeSync( + args, + toolCtx, + ctx, + createSyncExecutorDeps(modelFallbackControllerAccessor), + fallbackChain, + spawnReservation, + resolvedModel, + ) } catch (error) { spawnReservation?.rollback() return `Error: ${error instanceof Error ? error.message : String(error)}` } } - return await executeSync(args, toolCtx, ctx, undefined, fallbackChain, undefined, resolvedModel) + return await executeSync( + args, + toolCtx, + ctx, + createSyncExecutorDeps(modelFallbackControllerAccessor), + fallbackChain, + undefined, + resolvedModel, + ) }, }); } diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 6d982992b..d5c4adf5d 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -8,7 +8,6 @@ import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" import { SessionCategoryRegistry } from "../../shared/session-category-registry" import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied-session-permission" -import { setSessionFallbackChain } from "../../hooks/model-fallback/hook" import { stripAgentListSortPrefix } from "../../shared/agent-display-names" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" import { resolveMetadataModel } from "./resolve-metadata-model" @@ -19,6 +18,7 @@ function continueSessionSetup(args: { timing: ReturnType fallbackChain?: FallbackEntry[] category?: string + modelFallbackControllerAccessor?: ExecutorContext["modelFallbackControllerAccessor"] }): void { if (!args.fallbackChain && !args.category) { return @@ -41,7 +41,7 @@ function continueSessionSetup(args: { continue } - setSessionFallbackChain(sessionId, args.fallbackChain) + args.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, args.fallbackChain) if (args.category) { SessionCategoryRegistry.register(sessionId, args.category) } @@ -106,6 +106,7 @@ export async function executeBackgroundTask( timing, fallbackChain, category: args.category, + modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor, }) break } @@ -113,7 +114,7 @@ export async function executeBackgroundTask( } if (sessionId) { - setSessionFallbackChain(sessionId, fallbackChain) + executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, fallbackChain) } if (args.category && sessionId) { SessionCategoryRegistry.register(sessionId, args.category) diff --git a/src/tools/delegate-task/executor-types.ts b/src/tools/delegate-task/executor-types.ts index bfa7fc70b..8b430c9ce 100644 --- a/src/tools/delegate-task/executor-types.ts +++ b/src/tools/delegate-task/executor-types.ts @@ -1,5 +1,6 @@ import type { BackgroundManager } from "../../features/background-agent" import type { CategoriesConfig, GitMasterConfig, BrowserAutomationProvider, AgentOverrides, SisyphusAgentConfig } from "../../config/schema" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { OpencodeClient } from "./types" export interface ExecutorContext { @@ -12,6 +13,7 @@ export interface ExecutorContext { browserProvider?: BrowserAutomationProvider agentOverrides?: AgentOverrides sisyphusAgentConfig?: SisyphusAgentConfig + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor onSyncSessionCreated?: (event: { sessionID: string; parentID: string; title: string }) => Promise syncPollTimeoutMs?: number } diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 111371a51..034c0e199 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -9,7 +9,6 @@ import { SessionCategoryRegistry } from "../../shared/session-category-registry" import { formatDuration } from "./time-formatter" import { formatDetailedError } from "./error-formatting" import { syncTaskDeps, type SyncTaskDeps } from "./sync-task-deps" -import { setSessionFallbackChain, clearSessionFallbackChain } from "../../hooks/model-fallback/hook" import { retrySyncPromptWithFallbacks } from "./sync-task-fallback" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" import { resolveMetadataModel } from "./resolve-metadata-model" @@ -81,7 +80,7 @@ export async function executeSyncTask( subagentSessions.add(sessionID) syncSubagentSessions.add(sessionID) setSessionAgent(sessionID, agentToUse) - setSessionFallbackChain(sessionID, fallbackChain) + executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionID, fallbackChain) if (args.category) { SessionCategoryRegistry.register(sessionID, args.category) @@ -237,7 +236,7 @@ ${buildTaskMetadataBlock({ if (syncSessionID) { subagentSessions.delete(syncSessionID) syncSubagentSessions.delete(syncSessionID) - clearSessionFallbackChain(syncSessionID) + executorCtx.modelFallbackControllerAccessor?.clearSessionFallbackChain(syncSessionID) SessionCategoryRegistry.remove(syncSessionID) } } diff --git a/src/tools/delegate-task/types.ts b/src/tools/delegate-task/types.ts index 987e821a2..9eff782ce 100644 --- a/src/tools/delegate-task/types.ts +++ b/src/tools/delegate-task/types.ts @@ -1,6 +1,7 @@ import type { PluginInput } from "@opencode-ai/plugin" import type { BackgroundManager } from "../../features/background-agent" import type { CategoriesConfig, GitMasterConfig, BrowserAutomationProvider, AgentOverrides, SisyphusAgentConfig } from "../../config/schema" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { AvailableCategory, AvailableSkill, @@ -68,6 +69,7 @@ export interface DelegateTaskToolOptions { availableSkills?: AvailableSkill[] agentOverrides?: AgentOverrides sisyphusAgentConfig?: SisyphusAgentConfig + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor onSyncSessionCreated?: (event: SyncSessionCreatedEvent) => Promise syncPollTimeoutMs?: number } From e6f84f713b09156885556faf615befd9c89c33bc Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 02:37:57 +0900 Subject: [PATCH 043/146] refactor(tools): break glob->grep sibling-tool coupling Hoist shared ripgrep CLI resolution helpers (resolveGrepCli, resolveGrepCliWithAutoInstall, GrepBackend, DEFAULT_RG_THREADS, ResolvedCli) out of src/tools/grep/constants.ts into src/shared/ripgrep-cli.ts so they no longer straddle two sibling tool directories. Before: src/tools/glob/constants.ts re-exported from src/tools/grep/constants.ts, violating the project's "tools should not import from sibling tools" rule enforced by .sisyphus/rules/modular-code-enforcement.md. After: both src/tools/glob/ and src/tools/grep/ consume the shared helpers from src/shared/ripgrep-cli.ts. src/tools/grep/constants.ts keeps only the grep-specific UI-exposed constants. --- src/shared/ripgrep-cli.ts | 124 ++++++++++++++++++++++++++++++++++++ src/tools/glob/constants.ts | 2 +- src/tools/grep/cli.ts | 4 +- src/tools/grep/constants.ts | 124 ------------------------------------ src/tools/grep/tools.ts | 2 +- 5 files changed, 129 insertions(+), 127 deletions(-) create mode 100644 src/shared/ripgrep-cli.ts diff --git a/src/shared/ripgrep-cli.ts b/src/shared/ripgrep-cli.ts new file mode 100644 index 000000000..38eaff703 --- /dev/null +++ b/src/shared/ripgrep-cli.ts @@ -0,0 +1,124 @@ +import { spawnSync } from "node:child_process" +import { existsSync } from "node:fs" +import { dirname, join } from "node:path" +import { downloadAndInstallRipgrep, getInstalledRipgrepPath } from "../tools/grep/downloader" +import { getDataDir } from "./data-path" +import { log } from "./logger" +import { PUBLISHED_PACKAGE_NAME } from "./plugin-identity" + +export type GrepBackend = "rg" | "grep" + +export interface ResolvedCli { + path: string + backend: GrepBackend +} + +export const DEFAULT_RG_THREADS = 4 + +let cachedCli: ResolvedCli | null = null +let autoInstallAttempted = false + +function findExecutable(name: string): string | null { + const isWindows = process.platform === "win32" + const cmd = isWindows ? "where" : "which" + + try { + const result = spawnSync(cmd, [name], { encoding: "utf-8", timeout: 5000 }) + if (result.status === 0 && result.stdout.trim()) { + return result.stdout.trim().split("\n")[0] + } + } catch { + // Command execution failed + } + return null +} + +function getOpenCodeBundledRg(): string | null { + const execPath = process.execPath + const execDir = dirname(execPath) + + const isWindows = process.platform === "win32" + const rgName = isWindows ? "rg.exe" : "rg" + + const candidates = [ + join(getDataDir(), "opencode", "bin", rgName), + join(execDir, rgName), + join(execDir, "bin", rgName), + join(execDir, "..", "bin", rgName), + join(execDir, "..", "libexec", rgName), + ] + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate + } + } + + return null +} + +export function resolveGrepCli(): ResolvedCli { + if (cachedCli) { + return cachedCli + } + + const bundledRg = getOpenCodeBundledRg() + if (bundledRg) { + cachedCli = { path: bundledRg, backend: "rg" } + return cachedCli + } + + const systemRg = findExecutable("rg") + if (systemRg) { + cachedCli = { path: systemRg, backend: "rg" } + return cachedCli + } + + const installedRg = getInstalledRipgrepPath() + if (installedRg) { + cachedCli = { path: installedRg, backend: "rg" } + return cachedCli + } + + const grep = findExecutable("grep") + if (grep) { + cachedCli = { path: grep, backend: "grep" } + return cachedCli + } + + cachedCli = { path: "rg", backend: "rg" } + return cachedCli +} + +export async function resolveGrepCliWithAutoInstall(): Promise { + const current = resolveGrepCli() + + if (current.backend === "rg" && current.path !== "rg") { + return current + } + + if (autoInstallAttempted) { + return current + } + + autoInstallAttempted = true + + try { + const rgPath = await downloadAndInstallRipgrep() + cachedCli = { path: rgPath, backend: "rg" } + return cachedCli + } catch (error) { + if (current.backend === "grep") { + log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep. Falling back to GNU grep.`, { + error: error instanceof Error ? error.message : String(error), + grep_path: current.path, + }) + } else { + log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep and GNU grep was not found.`, { + error: error instanceof Error ? error.message : String(error), + }) + } + + return current + } +} diff --git a/src/tools/glob/constants.ts b/src/tools/glob/constants.ts index 05b5f85f1..8284b3681 100644 --- a/src/tools/glob/constants.ts +++ b/src/tools/glob/constants.ts @@ -1,4 +1,4 @@ -export { resolveGrepCli, resolveGrepCliWithAutoInstall, type GrepBackend, DEFAULT_RG_THREADS } from "../grep/constants" +export { resolveGrepCli, resolveGrepCliWithAutoInstall, type GrepBackend, DEFAULT_RG_THREADS } from "../../shared/ripgrep-cli" export const DEFAULT_TIMEOUT_MS = 60_000 export const DEFAULT_LIMIT = 100 diff --git a/src/tools/grep/cli.ts b/src/tools/grep/cli.ts index bcec98aaa..9f55b1d27 100644 --- a/src/tools/grep/cli.ts +++ b/src/tools/grep/cli.ts @@ -3,13 +3,15 @@ import { resolveGrepCli, type ResolvedCli, type GrepBackend, + DEFAULT_RG_THREADS, +} from "../../shared/ripgrep-cli" +import { DEFAULT_MAX_DEPTH, DEFAULT_MAX_FILESIZE, DEFAULT_MAX_COUNT, DEFAULT_MAX_COLUMNS, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_OUTPUT_BYTES, - DEFAULT_RG_THREADS, RG_SAFETY_FLAGS, GREP_SAFETY_FLAGS, } from "./constants" diff --git a/src/tools/grep/constants.ts b/src/tools/grep/constants.ts index 79db24c6b..f6c913303 100644 --- a/src/tools/grep/constants.ts +++ b/src/tools/grep/constants.ts @@ -1,126 +1,3 @@ -import { existsSync } from "node:fs" -import { join, dirname } from "node:path" -import { spawnSync } from "node:child_process" -import { getInstalledRipgrepPath, downloadAndInstallRipgrep } from "./downloader" -import { getDataDir } from "../../shared/data-path" -import { log } from "../../shared/logger" -import { PUBLISHED_PACKAGE_NAME } from "../../shared/plugin-identity" - -export type GrepBackend = "rg" | "grep" - -export interface ResolvedCli { - path: string - backend: GrepBackend -} - -let cachedCli: ResolvedCli | null = null -let autoInstallAttempted = false - -function findExecutable(name: string): string | null { - const isWindows = process.platform === "win32" - const cmd = isWindows ? "where" : "which" - - try { - const result = spawnSync(cmd, [name], { encoding: "utf-8", timeout: 5000 }) - if (result.status === 0 && result.stdout.trim()) { - return result.stdout.trim().split("\n")[0] - } - } catch { - // Command execution failed - } - return null -} - -function getOpenCodeBundledRg(): string | null { - const execPath = process.execPath - const execDir = dirname(execPath) - - const isWindows = process.platform === "win32" - const rgName = isWindows ? "rg.exe" : "rg" - - const candidates = [ - // OpenCode XDG data path (highest priority - where OpenCode installs rg) - join(getDataDir(), "opencode", "bin", rgName), - // Legacy paths relative to execPath - join(execDir, rgName), - join(execDir, "bin", rgName), - join(execDir, "..", "bin", rgName), - join(execDir, "..", "libexec", rgName), - ] - - for (const candidate of candidates) { - if (existsSync(candidate)) { - return candidate - } - } - - return null -} - -export function resolveGrepCli(): ResolvedCli { - if (cachedCli) return cachedCli - - const bundledRg = getOpenCodeBundledRg() - if (bundledRg) { - cachedCli = { path: bundledRg, backend: "rg" } - return cachedCli - } - - const systemRg = findExecutable("rg") - if (systemRg) { - cachedCli = { path: systemRg, backend: "rg" } - return cachedCli - } - - const installedRg = getInstalledRipgrepPath() - if (installedRg) { - cachedCli = { path: installedRg, backend: "rg" } - return cachedCli - } - - const grep = findExecutable("grep") - if (grep) { - cachedCli = { path: grep, backend: "grep" } - return cachedCli - } - - cachedCli = { path: "rg", backend: "rg" } - return cachedCli -} - -export async function resolveGrepCliWithAutoInstall(): Promise { - const current = resolveGrepCli() - - if (current.backend === "rg" && current.path !== "rg") { - return current - } - - if (autoInstallAttempted) { - return current - } - - autoInstallAttempted = true - - try { - const rgPath = await downloadAndInstallRipgrep() - cachedCli = { path: rgPath, backend: "rg" } - return cachedCli - } catch (error) { - if (current.backend === "grep") { - log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep. Falling back to GNU grep.`, { - error: error instanceof Error ? error.message : String(error), - grep_path: current.path, - }) - } else { - log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep and GNU grep was not found.`, { - error: error instanceof Error ? error.message : String(error), - }) - } - - return current - } -} - export const DEFAULT_MAX_DEPTH = 20 export const DEFAULT_MAX_FILESIZE = "10M" export const DEFAULT_MAX_COUNT = 500 @@ -128,7 +5,6 @@ export const DEFAULT_MAX_COLUMNS = 1000 export const DEFAULT_CONTEXT = 2 export const DEFAULT_TIMEOUT_MS = 60_000 export const DEFAULT_MAX_OUTPUT_BYTES = 256 * 1024 -export const DEFAULT_RG_THREADS = 4 export const RG_SAFETY_FLAGS = [ "--no-follow", diff --git a/src/tools/grep/tools.ts b/src/tools/grep/tools.ts index eaf8a3972..c40193c56 100644 --- a/src/tools/grep/tools.ts +++ b/src/tools/grep/tools.ts @@ -1,8 +1,8 @@ import { resolve } from "node:path" import type { PluginInput } from "@opencode-ai/plugin" import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool" +import { resolveGrepCliWithAutoInstall } from "../../shared/ripgrep-cli" import { runRg, runRgCount } from "./cli" -import { resolveGrepCliWithAutoInstall } from "./constants" import { formatGrepResult, formatCountResult } from "./result-formatter" export function createGrepTools(ctx: PluginInput): Record { From 81b37dd2ccf0ef92986dcdde00bef7a2ea40d4ed Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 02:52:10 +0900 Subject: [PATCH 044/146] refactor: remove cosmetic OhMyOpenCodePlugin references Post-V1-migration cleanup of the removed symbol's ghost references: - src/index.ts: log prefix '[OhMyOpenCodePlugin]' -> '[oh-my-openagent]' - src/index.test.ts: describe label 'OhMyOpenCodePlugin' -> 'oh-my-openagent plugin module' - src/index.telemetry.test.ts: describe label 'OhMyOpenCodePlugin telemetry isolation' -> 'oh-my-openagent telemetry isolation' - src/shared/log-legacy-plugin-startup-warning.ts: log prefix '[OhMyOpenCodePlugin]' -> '[legacy-migration]' (plus matching test assertion) After these renames 'grep -rn OhMyOpenCodePlugin src/' returns zero matches. Pure cosmetic rename, no behavior change. --- src/index.telemetry.test.ts | 2 +- src/index.test.ts | 2 +- src/index.ts | 2 +- src/shared/log-legacy-plugin-startup-warning.test.ts | 2 +- src/shared/log-legacy-plugin-startup-warning.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.telemetry.test.ts b/src/index.telemetry.test.ts index 7f751f594..924a7db2c 100644 --- a/src/index.telemetry.test.ts +++ b/src/index.telemetry.test.ts @@ -106,7 +106,7 @@ function installModuleMocks(): void { })) } -describe("OhMyOpenCodePlugin telemetry isolation", () => { +describe("oh-my-openagent telemetry isolation", () => { beforeEach(() => { mock.restore() installModuleMocks() diff --git a/src/index.test.ts b/src/index.test.ts index 335562cd0..ba7be1363 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -110,7 +110,7 @@ async function importFreshIndexModule(): Promise { return import(`./index?test=${Date.now()}-${Math.random()}`) } -describe("OhMyOpenCodePlugin", () => { +describe("oh-my-openagent plugin module", () => { beforeEach(async () => { mock.restore() installIndexModuleMocks() diff --git a/src/index.ts b/src/index.ts index 2c24e003e..6778427d0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,7 @@ import { createPluginPostHog, getPostHogDistinctId } from "./shared/posthog" const serverPlugin: Plugin = async (input, _options): Promise => { initConfigContext("opencode", null) - log("[OhMyOpenCodePlugin] ENTRY - plugin loading", { + log("[oh-my-openagent] ENTRY - plugin loading", { directory: input.directory, }) logLegacyPluginStartupWarning() diff --git a/src/shared/log-legacy-plugin-startup-warning.test.ts b/src/shared/log-legacy-plugin-startup-warning.test.ts index 917f40927..76ec3541f 100644 --- a/src/shared/log-legacy-plugin-startup-warning.test.ts +++ b/src/shared/log-legacy-plugin-startup-warning.test.ts @@ -63,7 +63,7 @@ describe("logLegacyPluginStartupWarning", () => { //#then expect(mockLog).toHaveBeenCalledTimes(1) expect(mockLog).toHaveBeenCalledWith( - "[OhMyOpenCodePlugin] Legacy plugin entry detected in OpenCode config", + "[legacy-migration] Legacy plugin entry detected in OpenCode config", { legacyEntries: ["oh-my-opencode", "oh-my-opencode@3.13.1"], suggestedEntries: ["oh-my-openagent", "oh-my-openagent@3.13.1"], diff --git a/src/shared/log-legacy-plugin-startup-warning.ts b/src/shared/log-legacy-plugin-startup-warning.ts index cc8be67e2..d1151b122 100644 --- a/src/shared/log-legacy-plugin-startup-warning.ts +++ b/src/shared/log-legacy-plugin-startup-warning.ts @@ -22,7 +22,7 @@ export function logLegacyPluginStartupWarning(deps: LogLegacyPluginStartupWarnin const suggestedEntries = result.legacyEntries.map(toCanonicalEntry) - logFn("[OhMyOpenCodePlugin] Legacy plugin entry detected in OpenCode config", { + logFn("[legacy-migration] Legacy plugin entry detected in OpenCode config", { legacyEntries: result.legacyEntries, suggestedEntries, hasCanonicalEntry: result.hasCanonicalEntry, From 70ddc01e1050601e4199334e6d5a68f85dfbf589 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 03:01:51 +0900 Subject: [PATCH 045/146] refactor: remove AI slop from refactored files Behavior-preserving cleanup of AI-generated code smells in 5 files authored/moved by this PR: - src/hooks/model-fallback/fallback-state-controller.ts (-47/+47 net reorganization, redundant defensiveness removed) - src/shared/model-string-parser.ts (-4 LOC obvious-comment cleanup) - src/shared/ripgrep-cli.ts (-13 LOC obvious comments + redundant defensive checks) - src/tools/delegate-task/tool-description.ts (-6 LOC) - src/tools/look-at/look-at-input-preparer.ts (-6 LOC) Targets: obvious comments that restate code, over-defensive null checks on guaranteed values, redundant existence checks. No public API signatures changed, no type hints removed, no new abstractions introduced. Full test suite still passes. --- .../fallback-state-controller.ts | 47 +++++++++---------- src/shared/model-string-parser.ts | 8 ++-- src/shared/ripgrep-cli.ts | 26 ++++------ src/tools/delegate-task/tool-description.ts | 20 ++++---- src/tools/look-at/look-at-input-preparer.ts | 11 ++--- 5 files changed, 48 insertions(+), 64 deletions(-) diff --git a/src/hooks/model-fallback/fallback-state-controller.ts b/src/hooks/model-fallback/fallback-state-controller.ts index b2e6831a0..4230bfb0a 100644 --- a/src/hooks/model-fallback/fallback-state-controller.ts +++ b/src/hooks/model-fallback/fallback-state-controller.ts @@ -53,9 +53,7 @@ export function createModelFallbackStateController(input: { ): boolean { const agentKey = getAgentConfigKey(agentName) const requirements = AGENT_MODEL_REQUIREMENTS[agentKey] - const fallbackChain = sessionFallbackChains.has(sessionID) - ? sessionFallbackChains.get(sessionID) - : requirements?.fallbackChain + const fallbackChain = sessionFallbackChains.get(sessionID) ?? requirements?.fallbackChain if (!fallbackChain?.length) { log("[model-fallback] No fallback chain for agent: " + agentName + " (key: " + agentKey + ")") @@ -63,30 +61,31 @@ export function createModelFallbackStateController(input: { } const existing = pendingModelFallbacks.get(sessionID) - if (existing) { - if (existing.pending) { - log("[model-fallback] Pending fallback already armed for session: " + sessionID) - return false - } - existing.providerID = currentProviderID - existing.modelID = currentModelID - existing.pending = true - if (existing.attemptCount >= existing.fallbackChain.length) { - log("[model-fallback] Fallback chain exhausted for session: " + sessionID) - return false - } - log("[model-fallback] Re-armed pending fallback for session: " + sessionID) + if (!existing) { + pendingModelFallbacks.set(sessionID, { + providerID: currentProviderID, + modelID: currentModelID, + fallbackChain, + attemptCount: 0, + pending: true, + }) + log("[model-fallback] Set pending fallback for session: " + sessionID + ", agent: " + agentName) return true } - pendingModelFallbacks.set(sessionID, { - providerID: currentProviderID, - modelID: currentModelID, - fallbackChain, - attemptCount: 0, - pending: true, - }) - log("[model-fallback] Set pending fallback for session: " + sessionID + ", agent: " + agentName) + if (existing.pending) { + log("[model-fallback] Pending fallback already armed for session: " + sessionID) + return false + } + + existing.providerID = currentProviderID + existing.modelID = currentModelID + existing.pending = true + if (existing.attemptCount >= existing.fallbackChain.length) { + log("[model-fallback] Fallback chain exhausted for session: " + sessionID) + return false + } + log("[model-fallback] Re-armed pending fallback for session: " + sessionID) return true } diff --git a/src/shared/model-string-parser.ts b/src/shared/model-string-parser.ts index 820bb3cc3..220bbd880 100644 --- a/src/shared/model-string-parser.ts +++ b/src/shared/model-string-parser.ts @@ -41,13 +41,13 @@ export function parseModelString( const trimmedModel = model.trim() if (!trimmedModel) return undefined - const parts = trimmedModel.split("/") - if (parts.length < 2) { + const separatorIndex = trimmedModel.indexOf("/") + if (separatorIndex === -1) { return undefined } - const providerID = parts[0]?.trim() - const rawModelID = parts.slice(1).join("/").trim() + const providerID = trimmedModel.slice(0, separatorIndex).trim() + const rawModelID = trimmedModel.slice(separatorIndex + 1).trim() if (!providerID || !rawModelID) { return undefined } diff --git a/src/shared/ripgrep-cli.ts b/src/shared/ripgrep-cli.ts index 38eaff703..5f62b3ad7 100644 --- a/src/shared/ripgrep-cli.ts +++ b/src/shared/ripgrep-cli.ts @@ -28,7 +28,7 @@ function findExecutable(name: string): string | null { return result.stdout.trim().split("\n")[0] } } catch { - // Command execution failed + return null } return null } @@ -62,21 +62,9 @@ export function resolveGrepCli(): ResolvedCli { return cachedCli } - const bundledRg = getOpenCodeBundledRg() - if (bundledRg) { - cachedCli = { path: bundledRg, backend: "rg" } - return cachedCli - } - - const systemRg = findExecutable("rg") - if (systemRg) { - cachedCli = { path: systemRg, backend: "rg" } - return cachedCli - } - - const installedRg = getInstalledRipgrepPath() - if (installedRg) { - cachedCli = { path: installedRg, backend: "rg" } + const rgPath = getOpenCodeBundledRg() ?? findExecutable("rg") ?? getInstalledRipgrepPath() + if (rgPath) { + cachedCli = { path: rgPath, backend: "rg" } return cachedCli } @@ -108,14 +96,16 @@ export async function resolveGrepCliWithAutoInstall(): Promise { cachedCli = { path: rgPath, backend: "rg" } return cachedCli } catch (error) { + const message = error instanceof Error ? error.message : String(error) + if (current.backend === "grep") { log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep. Falling back to GNU grep.`, { - error: error instanceof Error ? error.message : String(error), + error: message, grep_path: current.path, }) } else { log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep and GNU grep was not found.`, { - error: error instanceof Error ? error.message : String(error), + error: message, }) } diff --git a/src/tools/delegate-task/tool-description.ts b/src/tools/delegate-task/tool-description.ts index 48bebc58d..0b2717a82 100644 --- a/src/tools/delegate-task/tool-description.ts +++ b/src/tools/delegate-task/tool-description.ts @@ -13,28 +13,26 @@ export interface DelegateTaskPresentation { export function createDelegateTaskPresentation(options: DelegateTaskToolOptions): DelegateTaskPresentation { const { userCategories } = options const allCategories = mergeCategories(userCategories) - const categoryNames = Object.keys(allCategories) + const categoryEntries = Object.entries(allCategories).map(([name, categoryConfig]) => ({ + name, + categoryConfig, + description: userCategories?.[name]?.description || CATEGORY_DESCRIPTIONS[name], + })) + const categoryNames = categoryEntries.map(({ name }) => name) const categoryExamples = categoryNames.join(", ") const availableCategories: AvailableCategory[] = options.availableCategories - ?? Object.entries(allCategories).map(([name, categoryConfig]) => { - const userDescription = userCategories?.[name]?.description - const builtinDescription = CATEGORY_DESCRIPTIONS[name] - const description = userDescription || builtinDescription || "General tasks" - + ?? categoryEntries.map(({ name, categoryConfig, description }) => { return { name, - description, + description: description || "General tasks", model: categoryConfig.model, } }) const availableSkills: AvailableSkill[] = options.availableSkills ?? [] - const categoryList = categoryNames.map(name => { - const userDescription = userCategories?.[name]?.description - const builtinDescription = CATEGORY_DESCRIPTIONS[name] - const description = userDescription || builtinDescription + const categoryList = categoryEntries.map(({ name, description }) => { return description ? ` - ${name}: ${description}` : ` - ${name}` }).join("\n") diff --git a/src/tools/look-at/look-at-input-preparer.ts b/src/tools/look-at/look-at-input-preparer.ts index e0eef0099..4901eb00f 100644 --- a/src/tools/look-at/look-at-input-preparer.ts +++ b/src/tools/look-at/look-at-input-preparer.ts @@ -101,17 +101,16 @@ export function prepareLookAtInput(args: LookAtArgs): PrepareLookAtInputResult { if (filePath) { let mimeType = inferMimeTypeFromFilePath(filePath) let actualFilePath = filePath - let tempFilePath: string | null = null let tempConversionPath: string | null = null if (needsConversion(mimeType)) { log(`[look_at] Detected unsupported format: ${mimeType}, converting to JPEG...`) try { - tempFilePath = convertImageToJpeg(filePath, mimeType) - tempConversionPath = tempFilePath - actualFilePath = tempFilePath + const convertedFilePath = convertImageToJpeg(filePath, mimeType) + tempConversionPath = convertedFilePath + actualFilePath = convertedFilePath mimeType = "image/jpeg" - log(`[look_at] Conversion successful: ${tempFilePath}`) + log(`[look_at] Conversion successful: ${convertedFilePath}`) } catch (conversionError) { const failedConversionPath = getTemporaryConversionPath(conversionError) if (failedConversionPath) { @@ -139,8 +138,6 @@ export function prepareLookAtInput(args: LookAtArgs): PrepareLookAtInputResult { cleanup() { if (tempConversionPath) { cleanupConvertedImage(tempConversionPath) - } else if (tempFilePath) { - cleanupConvertedImage(tempFilePath) } }, }, From b00e22c2b86c938ee542d7f2002239dbe266577b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 01:39:45 +0900 Subject: [PATCH 046/146] feat(team-mode): add core types (discriminatedUnion for members, D-41/D-42) Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../task-2-category-prompt-required.txt | 7 + .../evidence/team-mode/task-2-disc-both.txt | 7 + .../team-mode/task-2-disc-category.txt | 7 + .../team-mode/task-2-eligibility-registry.txt | 7 + .sisyphus/notepads/team-mode/learnings.md | 5 + src/features/team-mode/index.ts | 1 + src/features/team-mode/types.test.ts | 96 +++++++++ src/features/team-mode/types.ts | 190 ++++++++++++++++++ 8 files changed, 320 insertions(+) create mode 100644 .sisyphus/evidence/team-mode/task-2-category-prompt-required.txt create mode 100644 .sisyphus/evidence/team-mode/task-2-disc-both.txt create mode 100644 .sisyphus/evidence/team-mode/task-2-disc-category.txt create mode 100644 .sisyphus/evidence/team-mode/task-2-eligibility-registry.txt create mode 100644 .sisyphus/notepads/team-mode/learnings.md create mode 100644 src/features/team-mode/index.ts create mode 100644 src/features/team-mode/types.test.ts create mode 100644 src/features/team-mode/types.ts diff --git a/.sisyphus/evidence/team-mode/task-2-category-prompt-required.txt b/.sisyphus/evidence/team-mode/task-2-category-prompt-required.txt new file mode 100644 index 000000000..d3f55481c --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-category-prompt-required.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 1 expect() calls +Ran 1 test across 1 file. [64.00ms] diff --git a/.sisyphus/evidence/team-mode/task-2-disc-both.txt b/.sisyphus/evidence/team-mode/task-2-disc-both.txt new file mode 100644 index 000000000..1174095e7 --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-disc-both.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 1 expect() calls +Ran 1 test across 1 file. [65.00ms] diff --git a/.sisyphus/evidence/team-mode/task-2-disc-category.txt b/.sisyphus/evidence/team-mode/task-2-disc-category.txt new file mode 100644 index 000000000..7aed175f2 --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-disc-category.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 3 expect() calls +Ran 1 test across 1 file. [69.00ms] diff --git a/.sisyphus/evidence/team-mode/task-2-eligibility-registry.txt b/.sisyphus/evidence/team-mode/task-2-eligibility-registry.txt new file mode 100644 index 000000000..749f3d548 --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-eligibility-registry.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 12 expect() calls +Ran 1 test across 1 file. [61.00ms] diff --git a/.sisyphus/notepads/team-mode/learnings.md b/.sisyphus/notepads/team-mode/learnings.md new file mode 100644 index 000000000..5349aca4e --- /dev/null +++ b/.sisyphus/notepads/team-mode/learnings.md @@ -0,0 +1,5 @@ +## 2026-04-18 Task 2: types module + +- `MemberSchema` needs `.strict()` on the base shape so the discriminatedUnion rejects members that mix `category` and `subagent_type`. +- `backendType` and `isActive` defaults are part of the schema contract, so tests should use `toMatchObject` instead of exact object equality. +- The eligibility registry must preserve the plan strings verbatim, especially the hard-reject messages for Momus verification. diff --git a/src/features/team-mode/index.ts b/src/features/team-mode/index.ts new file mode 100644 index 000000000..51f739d01 --- /dev/null +++ b/src/features/team-mode/index.ts @@ -0,0 +1 @@ +export * from "./types" diff --git a/src/features/team-mode/types.test.ts b/src/features/team-mode/types.test.ts new file mode 100644 index 000000000..042f220e5 --- /dev/null +++ b/src/features/team-mode/types.test.ts @@ -0,0 +1,96 @@ +import { describe, expect, test } from "bun:test" +import { + AGENT_ELIGIBILITY_REGISTRY, + CategoryMemberSchema, + MemberSchema, + SubagentMemberSchema, +} from "./types" + +describe("team-mode types", () => { + test("member category branch parses and narrows", () => { + // given + const member = { kind: "category", name: "m1", category: "deep", prompt: "impl X" } + + // when + const result = MemberSchema.safeParse(member) + + // then + expect(result.success).toBe(true) + if (result.success) { + expect(result.data).toMatchObject(member) + expect(result.data).toMatchObject({ kind: "category", category: "deep" }) + } + }) + + test("both kinds rejected", () => { + // given + const member = { + kind: "category", + name: "m1", + category: "deep", + subagent_type: "sisyphus", + prompt: "impl X", + } + + // when + const result = MemberSchema.safeParse(member) + + // then + expect(result.success).toBe(false) + }) + + test("category requires prompt", () => { + // given + const member = { kind: "category", name: "m1", category: "deep" } + + // when + const result = CategoryMemberSchema.safeParse(member) + + // then + expect(result.success).toBe(false) + }) + + test("eligibility registry shape", () => { + // given + const entries = Object.entries(AGENT_ELIGIBILITY_REGISTRY) + + // when + const verdictCounts = entries.reduce( + (counts, [, value]) => { + counts[value.verdict] += 1 + return counts + }, + { eligible: 0, conditional: 0, "hard-reject": 0 }, + ) + + // then + expect(entries).toHaveLength(11) + expect(verdictCounts).toEqual({ eligible: 3, conditional: 1, "hard-reject": 7 }) + expect(AGENT_ELIGIBILITY_REGISTRY.hephaestus.rejectionMessage).toBe( + "Agent 'hephaestus' lacks teammate permission. Either apply D-36 (add teammate: \"allow\" in tool-config-handler.ts) or use subagent_type: \"sisyphus\" instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.oracle.rejectionMessage).toBe( + "Agent 'oracle' is read-only (cannot write files). Team members must write to mailbox inbox files. Use delegate-task with subagent_type: 'oracle' for read-only analysis instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.librarian.rejectionMessage).toBe( + "Agent 'librarian' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for research queries instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.explore.rejectionMessage).toBe( + "Agent 'explore' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for codebase exploration instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY["multimodal-looker"].rejectionMessage).toBe( + "Agent 'multimodal-looker' has read-only tool access (only 'read' allowed). Cannot write to mailbox as team member.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.metis.rejectionMessage).toBe( + "Agent 'metis' is read-only (pre-planning consultant). Cannot write to mailbox as team member. Use delegate-task for pre-planning analysis instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.momus.rejectionMessage).toBe( + "Agent 'momus' is read-only (plan reviewer). Cannot write to mailbox as team member. Use delegate-task for plan review instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.prometheus.rejectionMessage).toBe( + "Agent 'prometheus' is plan-mode-only; can only write to .sisyphus/*.md (enforced by prometheusMdOnly hook). Cannot write to team mailbox. Use category: 'plan' instead.", + ) + expect(CategoryMemberSchema).toBeDefined() + expect(SubagentMemberSchema).toBeDefined() + }) +}) diff --git a/src/features/team-mode/types.ts b/src/features/team-mode/types.ts new file mode 100644 index 000000000..2b2da3f2a --- /dev/null +++ b/src/features/team-mode/types.ts @@ -0,0 +1,190 @@ +import { z } from "zod" + +export const MESSAGE_KINDS = [ + "message", + "shutdown_request", + "shutdown_approved", + "shutdown_rejected", + "announcement", +] as const + +export const MEMBER_KINDS = ["category", "subagent_type"] as const + +export const TASK_STATUSES = ["pending", "claimed", "in_progress", "completed", "deleted"] as const + +export const RUNTIME_STATUSES = [ + "creating", + "active", + "shutdown_requested", + "deleting", + "deleted", + "failed", + "orphaned", +] as const + +const MemberBaseSchema = z.object({ + name: z.string().min(1).regex(/^[a-z0-9-]+$/), + cwd: z.string().optional(), + worktreePath: z.string().optional(), + subscriptions: z.array(z.string()).optional(), + backendType: z.enum(["in-process", "tmux"]).default("in-process"), + color: z.string().optional(), + isActive: z.boolean().default(true), +}).strict() + +export const CategoryMemberSchema = MemberBaseSchema.extend({ + kind: z.literal("category"), + category: z.string().min(1), + prompt: z.string().min(1), +}) + +export const SubagentMemberSchema = MemberBaseSchema.extend({ + kind: z.literal("subagent_type"), + subagent_type: z.string().min(1), + prompt: z.string().optional(), +}) + +export const MemberSchema = z.discriminatedUnion("kind", [CategoryMemberSchema, SubagentMemberSchema]) + +const TeamReferenceSchema = z.object({ + path: z.string(), + description: z.string().optional(), +}).strict() + +export const TeamSpecSchema = z.object({ + version: z.literal(1), + name: z.string().min(1).regex(/^[a-z0-9-]+$/), + description: z.string().optional(), + createdAt: z.number().int().positive(), + leadAgentId: z.string(), + teamAllowedPaths: z.array(z.string()).optional(), + sessionPermission: z.string().optional(), + members: z.array(MemberSchema).min(1).max(8), +}) + +export const MessageSchema = z.object({ + version: z.literal(1), + messageId: z.string().uuid(), + from: z.string(), + to: z.string(), + kind: z.enum(MESSAGE_KINDS), + body: z.string().max(32 * 1024), + summary: z.string().optional(), + references: z.array(TeamReferenceSchema).optional(), + timestamp: z.number().int().positive(), + correlationId: z.string().uuid().optional(), + color: z.string().optional(), +}) + +export const TaskSchema = z.object({ + version: z.literal(1), + id: z.string(), + subject: z.string(), + description: z.string(), + activeForm: z.string().optional(), + status: z.enum(TASK_STATUSES), + owner: z.string().optional(), + blocks: z.array(z.string()).default([]), + blockedBy: z.array(z.string()).default([]), + metadata: z.record(z.string(), z.unknown()).optional(), + createdAt: z.number().int().positive(), + updatedAt: z.number().int().positive(), + claimedAt: z.number().int().positive().optional(), +}) + +const RuntimeStateMemberSchema = z.object({ + name: z.string(), + sessionId: z.string().optional(), + tmuxPaneId: z.string().optional(), + agentType: z.enum(["leader", "general-purpose"]), + status: z.enum(["pending", "running", "idle", "errored", "completed", "shutdown_approved"]), + color: z.string().optional(), + worktreePath: z.string().optional(), + lastInjectedTurnMarker: z.string().optional(), + pendingInjectedMessageIds: z.array(z.string()).default([]), +}).strict() + +const RuntimeBoundsSchema = z.object({ + maxMembers: z.number().int().default(8), + maxParallelMembers: z.number().int().default(4), + maxMessagesPerRun: z.number().int().default(10000), + maxWallClockMinutes: z.number().int().default(120), + maxMemberTurns: z.number().int().default(500), +}).strict() + +const ShutdownRequestSchema = z.object({ + memberId: z.string(), + requestedAt: z.number().int().positive(), + approvedAt: z.number().int().positive().optional(), + rejectedReason: z.string().optional(), +}).strict() + +export const RuntimeStateSchema = z.object({ + version: z.literal(1), + teamRunId: z.string().uuid(), + teamName: z.string(), + specSource: z.enum(["project", "user"]), + createdAt: z.number().int().positive(), + status: z.enum(RUNTIME_STATUSES), + leadSessionId: z.string().optional(), + members: z.array(RuntimeStateMemberSchema), + shutdownRequests: z.array(ShutdownRequestSchema).default([]), + bounds: RuntimeBoundsSchema, +}) + +export const AGENT_ELIGIBILITY_REGISTRY: Readonly> = { + sisyphus: { verdict: "eligible" }, + hephaestus: { + verdict: "conditional", + rejectionMessage: + "Agent 'hephaestus' lacks teammate permission. Either apply D-36 (add teammate: \"allow\" in tool-config-handler.ts) or use subagent_type: \"sisyphus\" instead.", + }, + oracle: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'oracle' is read-only (cannot write files). Team members must write to mailbox inbox files. Use delegate-task with subagent_type: 'oracle' for read-only analysis instead.", + }, + librarian: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'librarian' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for research queries instead.", + }, + explore: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'explore' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for codebase exploration instead.", + }, + "multimodal-looker": { + verdict: "hard-reject", + rejectionMessage: + "Agent 'multimodal-looker' has read-only tool access (only 'read' allowed). Cannot write to mailbox as team member.", + }, + metis: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'metis' is read-only (pre-planning consultant). Cannot write to mailbox as team member. Use delegate-task for pre-planning analysis instead.", + }, + momus: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'momus' is read-only (plan reviewer). Cannot write to mailbox as team member. Use delegate-task for plan review instead.", + }, + atlas: { verdict: "eligible" }, + prometheus: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'prometheus' is plan-mode-only; can only write to .sisyphus/*.md (enforced by prometheusMdOnly hook). Cannot write to team mailbox. Use category: 'plan' instead.", + }, + "sisyphus-junior": { verdict: "eligible" }, +} as const + +export type TeamSpec = z.infer +export type Member = z.infer +export type CategoryMember = z.infer +export type SubagentMember = z.infer +export type Message = z.infer +export type Task = z.infer +export type RuntimeState = z.infer From f1268c0448d2dfd46217c5272c4cf9127c703d15 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 02:04:49 +0900 Subject: [PATCH 047/146] feat(team-mode): add worktree manager (optional per-member isolation) --- .sisyphus/notepads/team-mode/learnings.md | 5 + src/features/team-mode/index.ts | 1 + .../team-mode/team-worktree/cleanup.test.ts | 31 ++++++ .../team-mode/team-worktree/cleanup.ts | 77 +++++++++++++ src/features/team-mode/team-worktree/index.ts | 2 + .../team-mode/team-worktree/manager.test.ts | 104 ++++++++++++++++++ .../team-mode/team-worktree/manager.ts | 62 +++++++++++ 7 files changed, 282 insertions(+) create mode 100644 src/features/team-mode/team-worktree/cleanup.test.ts create mode 100644 src/features/team-mode/team-worktree/cleanup.ts create mode 100644 src/features/team-mode/team-worktree/index.ts create mode 100644 src/features/team-mode/team-worktree/manager.test.ts create mode 100644 src/features/team-mode/team-worktree/manager.ts diff --git a/.sisyphus/notepads/team-mode/learnings.md b/.sisyphus/notepads/team-mode/learnings.md index 5349aca4e..97e13ba01 100644 --- a/.sisyphus/notepads/team-mode/learnings.md +++ b/.sisyphus/notepads/team-mode/learnings.md @@ -3,3 +3,8 @@ - `MemberSchema` needs `.strict()` on the base shape so the discriminatedUnion rejects members that mix `category` and `subagent_type`. - `backendType` and `isActive` defaults are part of the schema contract, so tests should use `toMatchObject` instead of exact object equality. - The eligibility registry must preserve the plan strings verbatim, especially the hard-reject messages for Momus verification. +## Task 12 learnings + +- `git worktree remove` can leave prunable entries behind, so pruning after removal keeps the repo index tidy. +- For testability, a tiny git command runner hook made git-unavailable coverage simpler than mocking Bun directly. +- Detached worktrees need unique temp paths in tests to avoid cross-run collisions. diff --git a/src/features/team-mode/index.ts b/src/features/team-mode/index.ts index 51f739d01..6aa6742a6 100644 --- a/src/features/team-mode/index.ts +++ b/src/features/team-mode/index.ts @@ -1 +1,2 @@ export * from "./types" +export * from "./team-worktree" diff --git a/src/features/team-mode/team-worktree/cleanup.test.ts b/src/features/team-mode/team-worktree/cleanup.test.ts new file mode 100644 index 000000000..f47c63af9 --- /dev/null +++ b/src/features/team-mode/team-worktree/cleanup.test.ts @@ -0,0 +1,31 @@ +/// + +import { afterAll, expect, test } from "bun:test" +import fs from "node:fs/promises" +import os from "node:os" +import path from "node:path" + +import { findOrphanWorktrees } from "./cleanup" + +const temporaryDirectories: string[] = [] + +afterAll(async () => { + for (const directory of temporaryDirectories) { + await fs.rm(directory, { recursive: true, force: true }) + } +}) + +test("given runtime mismatch when findOrphanWorktrees then returns orphan paths", async () => { + // given + const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "team-worktree-orphans-")) + temporaryDirectories.push(baseDir) + await fs.mkdir(path.join(baseDir, "worktrees", "t1", "m1"), { recursive: true }) + await fs.mkdir(path.join(baseDir, "runtime", "t1"), { recursive: true }) + await fs.writeFile(path.join(baseDir, "runtime", "t1", "state.json"), JSON.stringify({ status: "deleted" })) + + // when + const result = await findOrphanWorktrees(baseDir, {}) + + // then + expect(result).toEqual([path.join(baseDir, "worktrees", "t1", "m1")]) +}) diff --git a/src/features/team-mode/team-worktree/cleanup.ts b/src/features/team-mode/team-worktree/cleanup.ts new file mode 100644 index 000000000..673ecebc1 --- /dev/null +++ b/src/features/team-mode/team-worktree/cleanup.ts @@ -0,0 +1,77 @@ +import fs from "node:fs/promises" +import path from "node:path" + +import type { TeamModeConfig } from "./manager" + +async function runGit(args: string[]): Promise<{ code: number; stderr: string }> { + const process = Bun.spawn({ cmd: ["git", ...args], stdout: "pipe", stderr: "pipe" }) + const [exitCode, stderrText] = await Promise.all([process.exited, new Response(process.stderr).text()]) + return { code: exitCode, stderr: stderrText } +} + +export async function removeWorktree(worktreePath: string): Promise { + await fs.rm(worktreePath, { recursive: true, force: true }) + + const rootLookup = await Bun.spawn({ + cmd: ["git", "-C", worktreePath, "rev-parse", "--show-superproject-working-tree"], + stdout: "pipe", + stderr: "pipe", + }) + const [rootExitCode, rootStdout] = await Promise.all([ + rootLookup.exited, + new Response(rootLookup.stdout).text(), + new Response(rootLookup.stderr).text(), + ]) + const result = + rootExitCode === 0 && rootStdout.trim().length > 0 + ? await runGit(["-C", rootStdout.trim(), "worktree", "remove", "--force", worktreePath]) + : await runGit(["worktree", "remove", "--force", worktreePath]) + + if ( + result.code !== 0 && + !result.stderr.includes("not a worktree") && + !result.stderr.includes("not a working tree") && + !result.stderr.includes("already removed") + ) { + throw new Error(result.stderr.trim() || "git worktree remove failed") + } + + if (rootExitCode === 0 && rootStdout.trim().length > 0) { + await runGit(["-C", rootStdout.trim(), "worktree", "prune"]) + } +} + +export async function findOrphanWorktrees(baseDir: string, _config: TeamModeConfig): Promise { + const orphanWorktrees: string[] = [] + const worktreesDir = path.join(baseDir, "worktrees") + + let teamRunDirectories: string[] + try { + teamRunDirectories = await fs.readdir(worktreesDir) + } catch { + return orphanWorktrees + } + + for (const teamRunId of teamRunDirectories) { + const teamRunPath = path.join(worktreesDir, teamRunId) + const memberNames = await fs.readdir(teamRunPath).catch(() => []) + + for (const memberName of memberNames) { + const worktreePath = path.join(teamRunPath, memberName) + const statePath = path.join(baseDir, "runtime", teamRunId, "state.json") + + try { + const stateContents = await fs.readFile(statePath, "utf8") + const state = JSON.parse(stateContents) as { status?: string } + + if (state.status !== "active" && state.status !== "shutdown_requested") { + orphanWorktrees.push(worktreePath) + } + } catch { + orphanWorktrees.push(worktreePath) + } + } + } + + return orphanWorktrees +} diff --git a/src/features/team-mode/team-worktree/index.ts b/src/features/team-mode/team-worktree/index.ts new file mode 100644 index 000000000..e311ff757 --- /dev/null +++ b/src/features/team-mode/team-worktree/index.ts @@ -0,0 +1,2 @@ +export { GitUnavailableError, createWorktree, isGitAvailable, validateWorktreeSpec } from "./manager" +export { findOrphanWorktrees, removeWorktree } from "./cleanup" diff --git a/src/features/team-mode/team-worktree/manager.test.ts b/src/features/team-mode/team-worktree/manager.test.ts new file mode 100644 index 000000000..b1e98556b --- /dev/null +++ b/src/features/team-mode/team-worktree/manager.test.ts @@ -0,0 +1,104 @@ +/// + +import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test" +import { randomUUID } from "node:crypto" +import fs from "node:fs/promises" +import os from "node:os" +import path from "node:path" + +import { GitUnavailableError, createWorktree, setGitCommandRunnerForTests, validateWorktreeSpec } from "./manager" +import { removeWorktree } from "./cleanup" + +const temporaryDirectories: string[] = [] + +async function initGitRepo(): Promise { + const repositoryRoot = await fs.mkdtemp(path.join(os.tmpdir(), "team-worktree-")) + temporaryDirectories.push(repositoryRoot) + Bun.spawnSync(["git", "init"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + await fs.writeFile(path.join(repositoryRoot, "README.md"), "hello\n") + Bun.spawnSync(["git", "add", "README.md"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + Bun.spawnSync(["git", "config", "user.email", "test@example.com"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + Bun.spawnSync(["git", "config", "user.name", "Test User"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + Bun.spawnSync(["git", "commit", "-m", "init"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + return repositoryRoot +} + +beforeAll(() => { + mock.restore() +}) + +afterAll(async () => { + for (const directory of temporaryDirectories) { + await fs.rm(directory, { recursive: true, force: true }) + } + mock.restore() +}) + +describe("team-worktree manager", () => { + test("given tmp git repo when createWorktree then registers detached worktree", async () => { + // given + const repositoryRoot = await initGitRepo() + const worktreePath = `../worktree-${randomUUID()}` + const worktreeDirectory = path.resolve(repositoryRoot, worktreePath) + + // when + const resultPath = await createWorktree(repositoryRoot, "t1", "m1", worktreePath, {}) + + // then + expect(resultPath).toBe(worktreeDirectory) + await expect(fs.stat(worktreeDirectory)).resolves.toBeDefined() + const listResult = Bun.spawnSync(["git", "worktree", "list"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + expect(new TextDecoder().decode(listResult.stdout)).toContain(worktreeDirectory) + const headResult = Bun.spawnSync(["git", "-C", worktreeDirectory, "rev-parse", "HEAD"], { stdout: "pipe", stderr: "pipe" }) + const repoHeadResult = Bun.spawnSync(["git", "-C", repositoryRoot, "rev-parse", "HEAD"], { stdout: "pipe", stderr: "pipe" }) + expect(new TextDecoder().decode(headResult.stdout).trim()).toBe(new TextDecoder().decode(repoHeadResult.stdout).trim()) + }) + + test("validateWorktreeSpec rejects bare name", () => { + // given + const worktreePath = "feature-x" + + // when + const validate = () => validateWorktreeSpec(worktreePath) + + // then + expect(validate).toThrow("worktreePath must be a filesystem path (relative './...', '../...' or absolute '/...')") + }) + + test("given git unavailable when createWorktree then throws unavailable error", async () => { + // given + const repositoryRoot = await initGitRepo() + setGitCommandRunnerForTests(async (args) => { + if (args[0] === "--version") { + return { code: 1, stderr: "git missing" } + } + + return { code: 0, stderr: "" } + }) + + // when + const create = createWorktree(repositoryRoot, "t1", "m1", `../worktree-${randomUUID()}`, {}) + + // then + await expect(create).rejects.toBeInstanceOf(GitUnavailableError) + setGitCommandRunnerForTests(async (args) => { + if (args[0] === "--version") { + return { code: 0, stderr: "" } + } + + return { code: 0, stderr: "" } + }) + }) + + test("given created worktree when removeWorktree then directory disappears", async () => { + // given + const repositoryRoot = await initGitRepo() + const worktreePath = await createWorktree(repositoryRoot, "t1", "m1", `../worktree-${randomUUID()}`, {}) + + // when + await removeWorktree(worktreePath) + + // then + await expect(fs.stat(worktreePath)).rejects.toThrow() + }) +}) diff --git a/src/features/team-mode/team-worktree/manager.ts b/src/features/team-mode/team-worktree/manager.ts new file mode 100644 index 000000000..359df4cd0 --- /dev/null +++ b/src/features/team-mode/team-worktree/manager.ts @@ -0,0 +1,62 @@ +import path from "node:path" + +export type TeamModeConfig = { + worktreeBaseDir?: string +} + +export class GitUnavailableError extends Error { + constructor() { + super("git required for worktree members") + this.name = "GitUnavailableError" + } +} + +function countParentSegments(spec: string): number { + return spec.split("/").filter((segment) => segment === "..").length +} + +async function runGit(args: string[], cwd?: string): Promise<{ code: number; stderr: string }> { + const process = Bun.spawn({ cmd: ["git", ...args], cwd, stdout: "pipe", stderr: "pipe" }) + const [exitCode, stderrBytes] = await Promise.all([process.exited, new Response(process.stderr).text()]) + return { code: exitCode, stderr: stderrBytes } +} + +let gitCommandRunner = runGit + +export function setGitCommandRunnerForTests(runner: typeof runGit): void { + gitCommandRunner = runner +} + +export async function isGitAvailable(): Promise { + const result = await gitCommandRunner(["--version"]) + return result.code === 0 +} + +export function validateWorktreeSpec(spec: string): void { + if (!/^(\.\.?\/|\/).+/.test(spec) || countParentSegments(spec) > 2) { + throw new Error("worktreePath must be a filesystem path (relative './...', '../...' or absolute '/...')") + } +} + +export async function createWorktree( + repoRoot: string, + _teamRunId: string, + _memberName: string, + worktreePath: string, + _config: TeamModeConfig, +): Promise { + validateWorktreeSpec(worktreePath) + + if (!(await isGitAvailable())) { + throw new GitUnavailableError() + } + + const absolutePath = path.isAbsolute(worktreePath) ? worktreePath : path.resolve(repoRoot, worktreePath) + const result = await gitCommandRunner(["-C", repoRoot, "worktree", "add", "--detach", absolutePath]) + + if (result.code !== 0) { + throw new Error(result.stderr.trim() || "git worktree add failed") + } + + return absolutePath +} From 203e51786dbdc5d1ae7bfe60329f070afa62c172 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:42:21 +0000 Subject: [PATCH 048/146] @Disaster-Terminator has signed the CLA in code-yeongyu/oh-my-openagent#3497 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index 7402381a7..0bb7056f9 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2855,6 +2855,14 @@ "created_at": "2026-04-16T11:45:01Z", "repoId": 1108837393, "pullRequestNo": 3473 + }, + { + "name": "Disaster-Terminator", + "id": 47147571, + "comment_id": 4272328109, + "created_at": "2026-04-18T01:42:07Z", + "repoId": 1108837393, + "pullRequestNo": 3497 } ] } \ No newline at end of file From d59ad1e2e09a9e63d820c176c9f0a2f7abfd81bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 04:24:51 +0000 Subject: [PATCH 049/146] @Netzhangheng has signed the CLA in code-yeongyu/oh-my-openagent#3499 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index 0bb7056f9..26b3ef0e1 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2863,6 +2863,14 @@ "created_at": "2026-04-18T01:42:07Z", "repoId": 1108837393, "pullRequestNo": 3497 + }, + { + "name": "Netzhangheng", + "id": 25896014, + "comment_id": 4272702675, + "created_at": "2026-04-18T04:24:37Z", + "repoId": 1108837393, + "pullRequestNo": 3499 } ] } \ No newline at end of file From 49c7d4dbf96e330c9c4f4dd8bd0b60677a8c11e3 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:04:45 +0900 Subject: [PATCH 050/146] chore(shared): add EXCLUDED_DIRS constant for recursive FS scans Introduces a frozen Set of directory basenames (node_modules, .git, dist, build, .next, .sisyphus, .omx, .turbo, coverage, out, .cache, .vscode-test, target, .local-ignore) that callers performing recursive filesystem scans should skip. This is shared infrastructure for upcoming fixes in rules-injector, command-discovery, and claude-code-command-loader that currently descend into node_modules and other junk directories, causing slow plugin init and slow edit loops when the plugin is launched in-tree. --- src/shared/excluded-dirs.test.ts | 50 ++++++++++++++++++++++++++++++++ src/shared/excluded-dirs.ts | 18 ++++++++++++ src/shared/index.ts | 1 + 3 files changed, 69 insertions(+) create mode 100644 src/shared/excluded-dirs.test.ts create mode 100644 src/shared/excluded-dirs.ts diff --git a/src/shared/excluded-dirs.test.ts b/src/shared/excluded-dirs.test.ts new file mode 100644 index 000000000..21a488907 --- /dev/null +++ b/src/shared/excluded-dirs.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, test } from "bun:test" +import { EXCLUDED_DIRS } from "./excluded-dirs" +import { EXCLUDED_DIRS as EXCLUDED_DIRS_FROM_BARREL } from "." + +describe("EXCLUDED_DIRS", () => { + test("contains the well-known junk directories we never want to recurse into", () => { + // given + const expected = [ + "node_modules", + ".git", + "dist", + "build", + ".next", + ".sisyphus", + ".omx", + ".turbo", + "coverage", + "out", + ".cache", + ".vscode-test", + "target", + ".local-ignore", + ] + + // when / then + for (const name of expected) { + expect(EXCLUDED_DIRS.has(name)).toBe(true) + } + }) + + test("does not contain commonly-wanted project directories", () => { + // given + const shouldBeAllowed = ["src", "lib", "tests", "test", "docs", ".github", ".cursor", ".claude", ".opencode"] + + // when / then + for (const name of shouldBeAllowed) { + expect(EXCLUDED_DIRS.has(name)).toBe(false) + } + }) + + test("is frozen so consumers cannot mutate shared state", () => { + // given / when / then + expect(Object.isFrozen(EXCLUDED_DIRS)).toBe(true) + }) + + test("is re-exported from the shared barrel", () => { + // given / when / then + expect(EXCLUDED_DIRS_FROM_BARREL).toBe(EXCLUDED_DIRS) + }) +}) diff --git a/src/shared/excluded-dirs.ts b/src/shared/excluded-dirs.ts new file mode 100644 index 000000000..059a01406 --- /dev/null +++ b/src/shared/excluded-dirs.ts @@ -0,0 +1,18 @@ +const EXCLUDED_DIR_NAMES = [ + "node_modules", + ".git", + "dist", + "build", + ".next", + ".sisyphus", + ".omx", + ".turbo", + "coverage", + "out", + ".cache", + ".vscode-test", + "target", + ".local-ignore", +] as const + +export const EXCLUDED_DIRS: ReadonlySet = Object.freeze(new Set(EXCLUDED_DIR_NAMES)) diff --git a/src/shared/index.ts b/src/shared/index.ts index 140f88192..e99234c33 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -79,3 +79,4 @@ export * from "./log-legacy-plugin-startup-warning" export * from "./task-system-enabled" export * from "./parse-tools-config" export { parseModelString } from "./model-string-parser" +export { EXCLUDED_DIRS } from "./excluded-dirs" From d566d69c37e5fbd092f177283a900fc0a5cc1b21 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:07:58 +0900 Subject: [PATCH 051/146] test(rules-injector): add regression coverage for excluded-dir pruning --- .../rules-injector/rule-file-scanner.test.ts | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/hooks/rules-injector/rule-file-scanner.test.ts diff --git a/src/hooks/rules-injector/rule-file-scanner.test.ts b/src/hooks/rules-injector/rule-file-scanner.test.ts new file mode 100644 index 000000000..cadf4c3f1 --- /dev/null +++ b/src/hooks/rules-injector/rule-file-scanner.test.ts @@ -0,0 +1,42 @@ +import { afterEach, describe, expect, test } from "bun:test"; +import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { randomUUID } from "node:crypto"; +import { findRuleFilesRecursive } from "./rule-file-scanner"; + +const createdDirectories: string[] = []; + +afterEach(() => { + for (const directory of createdDirectories.splice(0)) { + if (existsSync(directory)) { + rmSync(directory, { recursive: true, force: true }); + } + } +}); + +describe("findRuleFilesRecursive", () => { + test("returns rule files outside excluded nested directories", () => { + // given + const temporaryDirectory = join(tmpdir(), `perf-d01-${randomUUID()}`); + createdDirectories.push(temporaryDirectory); + + const rulesDirectory = join(temporaryDirectory, ".sisyphus", "rules"); + mkdirSync(join(rulesDirectory, "node_modules", "fake"), { recursive: true }); + mkdirSync(join(rulesDirectory, ".git"), { recursive: true }); + writeFileSync(join(rulesDirectory, "foo.md"), "root rule"); + writeFileSync( + join(rulesDirectory, "node_modules", "fake", "x.md"), + "ignored node_modules rule", + ); + writeFileSync(join(rulesDirectory, ".git", "x.md"), "ignored git rule"); + + const results: string[] = []; + + // when + findRuleFilesRecursive(rulesDirectory, results); + + // then + expect(results).toEqual([join(rulesDirectory, "foo.md")]); + }); +}); From 578c49f9c20006371f6fc31ef7573d3e1e42252e Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:08:52 +0900 Subject: [PATCH 052/146] fix(rules-injector): skip EXCLUDED_DIRS in recursive rule scanner --- src/hooks/rules-injector/rule-file-scanner.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hooks/rules-injector/rule-file-scanner.ts b/src/hooks/rules-injector/rule-file-scanner.ts index ffd87d8a9..2cd853d07 100644 --- a/src/hooks/rules-injector/rule-file-scanner.ts +++ b/src/hooks/rules-injector/rule-file-scanner.ts @@ -1,5 +1,6 @@ import { existsSync, readdirSync, realpathSync } from "node:fs"; import { join } from "node:path"; +import { EXCLUDED_DIRS } from "../../shared"; import { GITHUB_INSTRUCTIONS_PATTERN, RULE_EXTENSIONS } from "./constants"; function isGitHubInstructionsDir(dir: string): boolean { @@ -28,6 +29,7 @@ export function findRuleFilesRecursive(dir: string, results: string[]): void { const fullPath = join(dir, entry.name); if (entry.isDirectory()) { + if (EXCLUDED_DIRS.has(entry.name)) continue; findRuleFilesRecursive(fullPath, results); } else if (entry.isFile()) { if (isValidRuleFile(entry.name, dir)) { From c5b7aa8e4b410fb936c0673b9d90ddf610d1d629 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:09:07 +0900 Subject: [PATCH 053/146] test(rules-injector): cover per-session scan caching behavior --- .../rules-injector/rule-scan-cache.test.ts | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/hooks/rules-injector/rule-scan-cache.test.ts diff --git a/src/hooks/rules-injector/rule-scan-cache.test.ts b/src/hooks/rules-injector/rule-scan-cache.test.ts new file mode 100644 index 000000000..778cf341a --- /dev/null +++ b/src/hooks/rules-injector/rule-scan-cache.test.ts @@ -0,0 +1,91 @@ +import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"; +import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +function createImportSuffix(): string { + return `?test=${Date.now()}-${Math.random()}`; +} + +describe("createRuleScanCache", () => { + afterEach(() => { + mock.restore(); + }); + + it("returns undefined before set, returns stored value, and clears entries", async () => { + // given + const { createRuleScanCache } = await import(`./rule-scan-cache${createImportSuffix()}`); + const cache = createRuleScanCache(); + const value = ["a", "b"]; + + // when + const initialValue = cache.get("k1"); + cache.set("k1", value); + const storedValue = cache.get("k1"); + cache.clear(); + const clearedValue = cache.get("k1"); + + // then + expect(initialValue).toBeUndefined(); + expect(storedValue).toEqual(value); + expect(clearedValue).toBeUndefined(); + }); +}); + +describe("findRuleFiles with scan cache", () => { + let testRoot = ""; + let homeDir = ""; + let projectRoot = ""; + let currentFile = ""; + let expectedRuleFile = ""; + let expectedRuleDir = ""; + + beforeEach(() => { + testRoot = join(tmpdir(), `rule-scan-cache-test-${Date.now()}`); + homeDir = join(testRoot, "home"); + projectRoot = join(testRoot, "project"); + currentFile = join(projectRoot, "src", "index.ts"); + expectedRuleDir = join(projectRoot, ".github", "instructions"); + expectedRuleFile = join(expectedRuleDir, "typescript.instructions.md"); + + mkdirSync(join(projectRoot, ".git"), { recursive: true }); + mkdirSync(join(projectRoot, "src"), { recursive: true }); + mkdirSync(homeDir, { recursive: true }); + writeFileSync(currentFile, "export const value = 1;\n"); + }); + + afterEach(() => { + mock.restore(); + if (existsSync(testRoot)) { + rmSync(testRoot, { recursive: true, force: true }); + } + }); + + it("reuses cached directory scan results for identical inputs", async () => { + // given + const findRuleFilesRecursive = mock((directoryPath: string, results: string[]) => { + if (directoryPath === expectedRuleDir) { + results.push(expectedRuleFile); + } + }); + + mock.module("./rule-file-scanner", () => ({ + findRuleFilesRecursive, + safeRealpathSync: (filePath: string) => filePath, + })); + + const { createRuleScanCache } = await import(`./rule-scan-cache${createImportSuffix()}`); + const { findRuleFiles } = await import(`./rule-file-finder${createImportSuffix()}`); + const cache = createRuleScanCache(); + + // when + const firstCandidates = findRuleFiles(projectRoot, homeDir, currentFile, undefined, cache); + const firstInvocationCount = findRuleFilesRecursive.mock.calls.length; + const secondCandidates = findRuleFiles(projectRoot, homeDir, currentFile, undefined, cache); + + // then + expect(firstCandidates).toEqual(secondCandidates); + expect(firstInvocationCount).toBeGreaterThan(0); + expect(findRuleFilesRecursive).toHaveBeenCalledTimes(firstInvocationCount); + }); +}); From 32598bc5e1c2a842b401b7bc6ef7ec2c605a99f7 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:09:17 +0900 Subject: [PATCH 054/146] test(shared/project-discovery-dirs): cover worktree-path memoization --- src/shared/project-discovery-dirs.test.ts | 69 +++++++++++++++++++---- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/src/shared/project-discovery-dirs.test.ts b/src/shared/project-discovery-dirs.test.ts index 39ba5dc13..2c9f127b5 100644 --- a/src/shared/project-discovery-dirs.test.ts +++ b/src/shared/project-discovery-dirs.test.ts @@ -1,13 +1,7 @@ -import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" import { mkdirSync, realpathSync, rmSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" -import { - findProjectAgentsSkillDirs, - findProjectClaudeSkillDirs, - findProjectOpencodeCommandDirs, - findProjectOpencodeSkillDirs, -} from "./project-discovery-dirs" const TEST_DIR = join(tmpdir(), `project-discovery-dirs-${Date.now()}`) @@ -24,7 +18,7 @@ describe("project-discovery-dirs", () => { rmSync(TEST_DIR, { recursive: true, force: true }) }) - it("#given nested .opencode skill directories #when finding project opencode skill dirs #then returns nearest-first with aliases", () => { + it("#given nested .opencode skill directories #when finding project opencode skill dirs #then returns nearest-first with aliases", async () => { // given const projectDir = join(TEST_DIR, "project") const childDir = join(projectDir, "apps", "cli") @@ -32,6 +26,8 @@ describe("project-discovery-dirs", () => { mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true }) mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true }) + const { findProjectOpencodeSkillDirs } = await import("./project-discovery-dirs") + // when const directories = findProjectOpencodeSkillDirs(childDir) @@ -43,13 +39,15 @@ describe("project-discovery-dirs", () => { ]) }) - it("#given nested .opencode command directories #when finding project opencode command dirs #then returns nearest-first with aliases", () => { + it("#given nested .opencode command directories #when finding project opencode command dirs #then returns nearest-first with aliases", async () => { // given const projectDir = join(TEST_DIR, "project") const childDir = join(projectDir, "packages", "tool") mkdirSync(join(projectDir, ".opencode", "commands"), { recursive: true }) mkdirSync(join(TEST_DIR, ".opencode", "command"), { recursive: true }) + const { findProjectOpencodeCommandDirs } = await import("./project-discovery-dirs") + // when const directories = findProjectOpencodeCommandDirs(childDir) @@ -60,13 +58,15 @@ describe("project-discovery-dirs", () => { ]) }) - it("#given ancestor claude and agents skill directories #when finding project compatibility dirs #then discovers both scopes", () => { + it("#given ancestor claude and agents skill directories #when finding project compatibility dirs #then discovers both scopes", async () => { // given const projectDir = join(TEST_DIR, "project") const childDir = join(projectDir, "src", "nested") mkdirSync(join(projectDir, ".claude", "skills"), { recursive: true }) mkdirSync(join(TEST_DIR, ".agents", "skills"), { recursive: true }) + const { findProjectAgentsSkillDirs, findProjectClaudeSkillDirs } = await import("./project-discovery-dirs") + // when const claudeDirectories = findProjectClaudeSkillDirs(childDir) const agentsDirectories = findProjectAgentsSkillDirs(childDir) @@ -76,17 +76,64 @@ describe("project-discovery-dirs", () => { expect(agentsDirectories).toEqual([canonicalPath(join(TEST_DIR, ".agents", "skills"))]) }) - it("#given a stop directory #when finding ancestor dirs #then it does not scan beyond the stop boundary", () => { + it("#given a stop directory #when finding ancestor dirs #then it does not scan beyond the stop boundary", async () => { // given const projectDir = join(TEST_DIR, "project") const childDir = join(projectDir, "apps", "cli") mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true }) mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true }) + const { findProjectOpencodeSkillDirs } = await import("./project-discovery-dirs") + // when const directories = findProjectOpencodeSkillDirs(childDir, projectDir) // then expect(directories).toEqual([canonicalPath(join(projectDir, ".opencode", "skills"))]) }) + + it("#given repeated worktree detection #when detecting twice #then reuses the cached result", async () => { + // given + let callCount = 0 + mock.module("node:child_process", () => ({ + execFileSync: () => { + callCount += 1 + return TEST_DIR + }, + })) + + const { clearWorktreeCache, detectWorktreePath } = await import("./project-discovery-dirs") + + clearWorktreeCache() + + // when + const firstPath = detectWorktreePath("/some/dir") + const secondPath = detectWorktreePath("/some/dir") + + // then + expect(firstPath).toBe(TEST_DIR) + expect(secondPath).toBe(TEST_DIR) + expect(callCount).toBe(1) + }) + + it("#given a cleared worktree cache #when detecting again #then spawns git again", async () => { + // given + let callCount = 0 + mock.module("node:child_process", () => ({ + execFileSync: () => { + callCount += 1 + return TEST_DIR + }, + })) + + const { clearWorktreeCache, detectWorktreePath } = await import("./project-discovery-dirs") + + // when + detectWorktreePath("/some/dir") + clearWorktreeCache() + detectWorktreePath("/some/dir") + + // then + expect(execFileSync).toHaveBeenCalledTimes(2) + }) }) From 76945bf3c86e3d812b21efea8617bd546d91a63a Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:09:32 +0900 Subject: [PATCH 055/146] test(rules-injector): cover project-root-finder memoization Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../project-root-finder.test.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/hooks/rules-injector/project-root-finder.test.ts diff --git a/src/hooks/rules-injector/project-root-finder.test.ts b/src/hooks/rules-injector/project-root-finder.test.ts new file mode 100644 index 000000000..35d442290 --- /dev/null +++ b/src/hooks/rules-injector/project-root-finder.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it, mock } from "bun:test"; + +describe("findProjectRoot", () => { + afterEach(async () => { + const actualFileSystem = await import("node:fs"); + mock.module("node:fs", () => actualFileSystem); + }); + + it("memoizes repeated lookups for the same start path and resets on cache clear", async () => { + // given + const actualFileSystem = await import("node:fs"); + const projectRoot = "/workspace/project"; + const startPath = `${projectRoot}/src/file.ts`; + const packageJsonPath = `${projectRoot}/package.json`; + + const existsSyncSpy = mock((path: string) => path === packageJsonPath); + const statSyncSpy = mock(() => ({ isDirectory: () => false })); + + mock.module("node:fs", () => ({ + ...actualFileSystem, + existsSync: existsSyncSpy, + statSync: statSyncSpy, + })); + + const { clearProjectRootCache, findProjectRoot } = await import( + `./project-root-finder.ts?memoization=${Date.now()}` + ); + + // when + const firstResult = findProjectRoot(startPath); + const firstExistsSyncCallCount = existsSyncSpy.mock.calls.length; + + const secondResult = findProjectRoot(startPath); + const secondExistsSyncCallCount = existsSyncSpy.mock.calls.length; + + clearProjectRootCache(); + const thirdResult = findProjectRoot(startPath); + + // then + expect(firstResult).toBe(projectRoot); + expect(secondResult).toBe(projectRoot); + expect(thirdResult).toBe(projectRoot); + expect(firstExistsSyncCallCount).toBeGreaterThan(0); + expect(secondExistsSyncCallCount).toBe(firstExistsSyncCallCount); + expect(existsSyncSpy).toHaveBeenCalledTimes(firstExistsSyncCallCount * 2); + }); +}); From d0eda8b4bfc130089eac401efddf191814dc7375 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:09:34 +0900 Subject: [PATCH 056/146] test(tools/slashcommand): cover excluded-dir pruning during discovery Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../slashcommand/command-discovery.test.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/tools/slashcommand/command-discovery.test.ts b/src/tools/slashcommand/command-discovery.test.ts index e82cd7653..fc193b61f 100644 --- a/src/tools/slashcommand/command-discovery.test.ts +++ b/src/tools/slashcommand/command-discovery.test.ts @@ -326,4 +326,40 @@ describe("non-directory commands path", () => { expect(testCmd).toBeDefined() expect(testCmd?.content).toContain("Test command content.") }) + + it("#given excluded subdirectories under .claude/commands #when discoverCommandsSync runs #then prunes commands beneath them", () => { + // given + const projectDir = join(testDir, "project") + const commandsDir = join(projectDir, ".claude", "commands") + + mkdirSync(join(commandsDir, "node_modules", "fake-pkg"), { recursive: true }) + mkdirSync(join(commandsDir, ".git", "branches"), { recursive: true }) + mkdirSync(join(commandsDir, "dist"), { recursive: true }) + writeFileSync( + join(commandsDir, "real-cmd.md"), + "---\ndescription: Real command\n---\nRun real command.\n", + ) + writeFileSync( + join(commandsDir, "node_modules", "fake-pkg", "cmd.md"), + "---\ndescription: Nested command\n---\nRun nested command.\n", + ) + writeFileSync( + join(commandsDir, ".git", "branches", "cmd.md"), + "---\ndescription: Git command\n---\nRun git command.\n", + ) + writeFileSync( + join(commandsDir, "dist", "bundled-cmd.md"), + "---\ndescription: Bundled command\n---\nRun bundled command.\n", + ) + + // when + const commands = discoverCommandsSync(projectDir) + const names = commands.map((command) => command.name) + + // then + expect(names).toContain("real-cmd") + expect(names).not.toContain("node_modules/fake-pkg/cmd") + expect(names).not.toContain(".git/branches/cmd") + expect(names).not.toContain("dist/bundled-cmd") + }) }) From 493e37bb7dc7c3805a2ed5a55f065d15a45cd2f4 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:09:38 +0900 Subject: [PATCH 057/146] test(comment-checker): cover lazy CLI init and cleanup startup --- .../comment-checker/hook.lazy-init.test.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/hooks/comment-checker/hook.lazy-init.test.ts diff --git a/src/hooks/comment-checker/hook.lazy-init.test.ts b/src/hooks/comment-checker/hook.lazy-init.test.ts new file mode 100644 index 000000000..2598aa3c6 --- /dev/null +++ b/src/hooks/comment-checker/hook.lazy-init.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it, mock, afterAll } from "bun:test" + +const startPendingCallCleanup = mock(() => {}) +const initializeCommentCheckerCli = mock(() => {}) + +mock.module("./cli-runner", () => ({ + initializeCommentCheckerCli, + getCommentCheckerCliPathPromise: () => Promise.resolve("/tmp/fake-comment-checker"), + isCliPathUsable: () => true, + processWithCli: async () => {}, + processApplyPatchEditsWithCli: async () => {}, +})) + +mock.module("./pending-calls", () => ({ + registerPendingCall: () => {}, + startPendingCallCleanup, + stopPendingCallCleanup: () => {}, + takePendingCall: () => undefined, +})) + +afterAll(() => { + mock.restore() +}) + +const { createCommentCheckerHooks } = await import("./hook") + +describe("comment-checker lazy initialization", () => { + it("initializes CLI and cleanup on first tool hook call only", async () => { + // given + const hooks = createCommentCheckerHooks() + const beforeHook = hooks["tool.execute.before"] + const input = { tool: "write", sessionID: "ses_test", callID: "call_test" } + const output = { args: { filePath: "src/a.ts" } } + + // when + expect(startPendingCallCleanup).toHaveBeenCalledTimes(0) + expect(initializeCommentCheckerCli).toHaveBeenCalledTimes(0) + + // then + await beforeHook(input, output) + expect(startPendingCallCleanup).toHaveBeenCalledTimes(1) + expect(initializeCommentCheckerCli).toHaveBeenCalledTimes(1) + + // when + await beforeHook(input, output) + + // then + expect(startPendingCallCleanup).toHaveBeenCalledTimes(1) + expect(initializeCommentCheckerCli).toHaveBeenCalledTimes(1) + }) +}) From e599840fbafd7532365529e7358d4258ccad8fa6 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:09:43 +0900 Subject: [PATCH 058/146] fix(comment-checker): defer CLI download and cleanup scheduler to first tool call --- src/hooks/comment-checker/hook.ts | 9 ++++++--- src/hooks/comment-checker/initialization-gate.ts | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/hooks/comment-checker/initialization-gate.ts diff --git a/src/hooks/comment-checker/hook.ts b/src/hooks/comment-checker/hook.ts index 56632b1f9..089aca2e9 100644 --- a/src/hooks/comment-checker/hook.ts +++ b/src/hooks/comment-checker/hook.ts @@ -28,6 +28,7 @@ import { stopPendingCallCleanup, takePendingCall, } from "./pending-calls" +import { ensureCommentCheckerInitialization } from "./initialization-gate" import * as fs from "fs" import { tmpdir } from "os" @@ -48,14 +49,16 @@ function debugLog(...args: unknown[]) { export function createCommentCheckerHooks(config?: CommentCheckerConfig) { debugLog("createCommentCheckerHooks called", { config }) - startPendingCallCleanup() - initializeCommentCheckerCli(debugLog) - return { "tool.execute.before": async ( input: { tool: string; sessionID: string; callID: string }, output: { args: Record }, ): Promise => { + ensureCommentCheckerInitialization(() => { + startPendingCallCleanup() + initializeCommentCheckerCli(debugLog) + }) + debugLog("tool.execute.before:", { tool: input.tool, callID: input.callID, diff --git a/src/hooks/comment-checker/initialization-gate.ts b/src/hooks/comment-checker/initialization-gate.ts new file mode 100644 index 000000000..da9759a47 --- /dev/null +++ b/src/hooks/comment-checker/initialization-gate.ts @@ -0,0 +1,7 @@ +let initialized = false + +export function ensureCommentCheckerInitialization(initializer: () => void): void { + if (initialized) return + initialized = true + initializer() +} From 428bae632c9220b097dbc7ebb1cf4fb1de4238e9 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:09:46 +0900 Subject: [PATCH 059/146] test(shared): cover loadOpencodePlugins memoization Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/shared/load-opencode-plugins.test.ts | 89 ++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/shared/load-opencode-plugins.test.ts diff --git a/src/shared/load-opencode-plugins.test.ts b/src/shared/load-opencode-plugins.test.ts new file mode 100644 index 000000000..9723c1cd3 --- /dev/null +++ b/src/shared/load-opencode-plugins.test.ts @@ -0,0 +1,89 @@ +/// + +import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" +import * as fs from "node:fs" + +type LoadOpencodePluginsModule = { + loadOpencodePlugins: (directory: string) => string[] + clearOpencodePluginsCache?: () => void +} + +const existsSyncMock = mock((_path: string) => true) +const readFileSyncMock = mock((_path: string, _encoding?: string) => `{ + "plugin": ["plugin-a", "plugin-b"] +}`) + +async function importFreshLoadOpencodePluginsModule(): Promise { + const modulePath = `${new URL("./load-opencode-plugins.ts", import.meta.url).pathname}?test=${Date.now()}-${Math.random()}` + return import(modulePath) +} + +describe("loadOpencodePlugins", () => { + beforeEach(() => { + existsSyncMock.mockReset() + existsSyncMock.mockImplementation((_path: string) => true) + readFileSyncMock.mockReset() + readFileSyncMock.mockImplementation((_path: string, _encoding?: string) => `{ + "plugin": ["plugin-a", "plugin-b"] +}`) + + mock.module("node:fs", () => ({ + ...fs, + existsSync: existsSyncMock, + readFileSync: readFileSyncMock, + })) + }) + + afterEach(() => { + mock.restore() + }) + + describe("#given the same directory is loaded twice", () => { + describe("#when loading plugins repeatedly", () => { + it("#then does not call readFileSync on the second load", async () => { + // given + const { loadOpencodePlugins } = await importFreshLoadOpencodePluginsModule() + + // when + const firstResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterFirstLoad = readFileSyncMock.mock.calls.length + const secondResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterSecondLoad = readFileSyncMock.mock.calls.length + + // then + expect(firstResult).toEqual(["plugin-a", "plugin-b"]) + expect(secondResult).toEqual(["plugin-a", "plugin-b"]) + expect(readCountAfterFirstLoad).toBeGreaterThan(0) + expect(readCountAfterSecondLoad - readCountAfterFirstLoad).toBe(0) + }) + }) + }) + + describe("#given the plugin cache was cleared", () => { + describe("#when loading the same directory again", () => { + it("#then re-reads plugin config files from disk", async () => { + // given + const { loadOpencodePlugins, clearOpencodePluginsCache } = await importFreshLoadOpencodePluginsModule() + + if (typeof clearOpencodePluginsCache !== "function") { + throw new Error("clearOpencodePluginsCache export is missing") + } + + // when + const firstResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterFirstLoad = readFileSyncMock.mock.calls.length + loadOpencodePlugins("/some/fake/dir") + const readCountAfterSecondLoad = readFileSyncMock.mock.calls.length + clearOpencodePluginsCache() + const thirdResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterThirdLoad = readFileSyncMock.mock.calls.length + + // then + expect(firstResult).toEqual(["plugin-a", "plugin-b"]) + expect(thirdResult).toEqual(["plugin-a", "plugin-b"]) + expect(readCountAfterSecondLoad - readCountAfterFirstLoad).toBe(0) + expect(readCountAfterThirdLoad - readCountAfterSecondLoad).toBeGreaterThan(0) + }) + }) + }) +}) From 3717121b0d7c0bb740e61e3b1e182761971ab926 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:10:04 +0900 Subject: [PATCH 060/146] test(directory-readme-injector): cover async migration Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../injector.test.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/hooks/directory-readme-injector/injector.test.ts b/src/hooks/directory-readme-injector/injector.test.ts index 74294fd7c..c8e704121 100644 --- a/src/hooks/directory-readme-injector/injector.test.ts +++ b/src/hooks/directory-readme-injector/injector.test.ts @@ -133,6 +133,32 @@ describe("processFilePathForReadmeInjection", () => { expect(output.output).toContain("# Components README") }) + it("returns a promise and finds README.md files from temp fixtures", async () => { + // given + const sourceDirectory = join(testRoot, "src") + const componentsDirectory = join(sourceDirectory, "components") + mkdirSync(componentsDirectory, { recursive: true }) + writeFileSync(join(testRoot, "README.md"), "# Root README") + writeFileSync(join(sourceDirectory, "README.md"), "# Src README") + writeFileSync(join(componentsDirectory, "README.md"), "# Components README") + + const { findReadmeMdUp } = await import("./finder") + + // when + const promise = findReadmeMdUp({ + startDir: componentsDirectory, + rootDir: testRoot, + }) + + // then + expect(promise).toBeInstanceOf(Promise) + await expect(promise).resolves.toEqual([ + join(testRoot, "README.md"), + join(sourceDirectory, "README.md"), + join(componentsDirectory, "README.md"), + ]) + }) + it("does not re-inject already cached directories", async () => { // given const sourceDirectory = join(testRoot, "src") From 9677c7daf34b0dff562652bcc91b4f6a3bd338b9 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:10:12 +0900 Subject: [PATCH 061/146] test(directory-agents-injector): cover async migration Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../directory-agents-injector/injector.test.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/hooks/directory-agents-injector/injector.test.ts b/src/hooks/directory-agents-injector/injector.test.ts index 8f5701645..822381a69 100644 --- a/src/hooks/directory-agents-injector/injector.test.ts +++ b/src/hooks/directory-agents-injector/injector.test.ts @@ -84,6 +84,23 @@ describe("processFilePathForAgentsInjection", () => { expect(output.output).toContain(srcAgentsContent) }) + it("finds AGENTS.md files while walking up directories", async () => { + // given + const { findAgentsMdUp } = await import("./finder") + + // when + const agentsPaths = await findAgentsMdUp({ + startDir: componentsDirectory, + rootDir: testRoot, + }) + + // then + expect(agentsPaths).toEqual([ + join(srcDirectory, "AGENTS.md"), + join(componentsDirectory, "AGENTS.md"), + ]) + }) + it("skips root-level AGENTS.md", async () => { // given rmSync(join(srcDirectory, "AGENTS.md"), { force: true }) From a6e3c6a5eda2c0e65f988de8cfc27c03dede402a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:10:12 +0900 Subject: [PATCH 062/146] test(write-existing-file-guard): cover lazy canonical path init Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../lazy-canonical-path-init.test.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts diff --git a/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts b/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts new file mode 100644 index 000000000..1d3ada213 --- /dev/null +++ b/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts @@ -0,0 +1,65 @@ +import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test" +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" + +const realFs = await import("node:fs") + +const existsSyncMock = mock(realFs.existsSync) +const realpathNativeMock = mock(realFs.realpathSync.native) + +mock.module("fs", () => ({ + ...realFs, + existsSync: existsSyncMock, + realpathSync: { + ...realFs.realpathSync, + native: realpathNativeMock, + }, +})) + +const { createWriteExistingFileGuardHook } = await import("./index") + +describe("createWriteExistingFileGuardHook", () => { + let tempDir = "" + + beforeEach(() => { + // given + tempDir = mkdtempSync(join(tmpdir(), "write-existing-file-guard-lazy-")) + mkdirSync(tempDir, { recursive: true }) + existsSyncMock.mockClear() + realpathNativeMock.mockClear() + }) + + afterEach(() => { + rmSync(tempDir, { recursive: true, force: true }) + }) + + test("#given hook factory #when created #then defers fs canonical path calls until first tool invocation", async () => { + // given + const existingFile = join(tempDir, "existing.txt") + writeFileSync(existingFile, "content") + + // when + const hook = createWriteExistingFileGuardHook({ directory: tempDir } as never) + + // then + expect(existsSyncMock).toHaveBeenCalledTimes(0) + expect(realpathNativeMock).toHaveBeenCalledTimes(0) + + // when + await expect( + hook["tool.execute.before"]?.( + { + tool: "write", + sessionID: "ses_lazy", + callID: "call_lazy", + } as never, + { args: { filePath: existingFile, content: "updated" } } as never, + ), + ).rejects.toThrow("File already exists. Use edit tool instead.") + + // then + expect(existsSyncMock).toHaveBeenCalledTimes(2) + expect(realpathNativeMock).toHaveBeenCalledTimes(1) + }) +}) From 51f1fc1df376bf4d969d1a9cc037fe37c2abd54e Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:10:18 +0900 Subject: [PATCH 063/146] perf(directory-agents-injector): migrate sync FS to fs.promises Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/directory-agents-injector/finder.ts | 12 ++++++++---- src/hooks/directory-agents-injector/injector.ts | 8 ++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/hooks/directory-agents-injector/finder.ts b/src/hooks/directory-agents-injector/finder.ts index 8ac8a1463..e04cfab74 100644 --- a/src/hooks/directory-agents-injector/finder.ts +++ b/src/hooks/directory-agents-injector/finder.ts @@ -1,4 +1,4 @@ -import { existsSync } from "node:fs"; +import { constants, promises as fsPromises } from "node:fs"; import { dirname, isAbsolute, join, resolve } from "node:path"; import { AGENTS_FILENAME } from "./constants"; @@ -9,10 +9,10 @@ export function resolveFilePath(rootDirectory: string, path: string): string | n return resolve(rootDirectory, path); } -export function findAgentsMdUp(input: { +export async function findAgentsMdUp(input: { startDir: string; rootDir: string; -}): string[] { +}): Promise { const found: string[] = []; let current = input.startDir; @@ -22,7 +22,11 @@ export function findAgentsMdUp(input: { const isRootDir = current === input.rootDir; if (!isRootDir) { const agentsPath = join(current, AGENTS_FILENAME); - if (existsSync(agentsPath)) { + const exists = await fsPromises + .access(agentsPath, constants.F_OK) + .then(() => true) + .catch(() => false); + if (exists) { found.push(agentsPath); } } diff --git a/src/hooks/directory-agents-injector/injector.ts b/src/hooks/directory-agents-injector/injector.ts index 28d0be943..3ff40784d 100644 --- a/src/hooks/directory-agents-injector/injector.ts +++ b/src/hooks/directory-agents-injector/injector.ts @@ -1,5 +1,5 @@ import type { PluginInput } from "@opencode-ai/plugin"; -import { readFileSync } from "node:fs"; +import { promises as fsPromises } from "node:fs"; import { dirname } from "node:path"; import type { createDynamicTruncator } from "../../shared/dynamic-truncator"; @@ -31,7 +31,7 @@ export async function processFilePathForAgentsInjection(input: { const dir = dirname(resolved); const cache = getSessionCache(input.sessionCaches, input.sessionID); - const agentsPaths = findAgentsMdUp({ startDir: dir, rootDir: input.ctx.directory }); + const agentsPaths = await findAgentsMdUp({ startDir: dir, rootDir: input.ctx.directory }); let dirty = false; for (const agentsPath of agentsPaths) { @@ -39,7 +39,8 @@ export async function processFilePathForAgentsInjection(input: { if (cache.has(agentsDir)) continue; try { - const content = readFileSync(agentsPath, "utf-8"); + const content = await fsPromises.readFile(agentsPath, "utf-8"); + cache.add(agentsDir); const { result, truncated } = await input.truncator.truncate( input.sessionID, content, @@ -48,7 +49,6 @@ export async function processFilePathForAgentsInjection(input: { ? `\n\n[Note: Content was truncated to save context window space. For full context, please read the file directly: ${agentsPath}]` : ""; input.output.output += `\n\n[Directory Context: ${agentsPath}]\n${result}${truncationNotice}`; - cache.add(agentsDir); dirty = true; } catch {} } From d8e00ebfbcc656c2fc625041e6e0bd0eb459c681 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:10:25 +0900 Subject: [PATCH 064/146] test(runtime-fallback): cover pluginConfig DI and lazy interval Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/runtime-fallback/hook.init.test.ts | 124 +++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 src/hooks/runtime-fallback/hook.init.test.ts diff --git a/src/hooks/runtime-fallback/hook.init.test.ts b/src/hooks/runtime-fallback/hook.init.test.ts new file mode 100644 index 000000000..06a7e658c --- /dev/null +++ b/src/hooks/runtime-fallback/hook.init.test.ts @@ -0,0 +1,124 @@ +import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test" +import type { OhMyOpenCodeConfig } from "../../config" +import type { HookDeps, RuntimeFallbackInterval, RuntimeFallbackPluginInput } from "./types" + +type RuntimeFallbackModule = typeof import("./hook") + +const loadPluginConfigMock = mock(() => ({} satisfies OhMyOpenCodeConfig)) +const createAutoRetryHelpersMock = mock((_deps: HookDeps) => { + void _deps + + return { + abortSessionRequest: async () => {}, + clearSessionFallbackTimeout: () => {}, + scheduleSessionFallbackTimeout: () => {}, + autoRetryWithFallback: async () => {}, + resolveAgentForSessionFromContext: async () => undefined, + cleanupStaleSessions: () => {}, + } +}) +const createEventHandlerMock = mock(() => async () => {}) +const createMessageUpdateHandlerMock = mock(() => async () => {}) +const createChatMessageHandlerMock = mock(() => async () => {}) + +function registerModuleMocks(): void { + mock.module("../../plugin-config", () => ({ + loadPluginConfig: loadPluginConfigMock, + })) + + mock.module("./auto-retry", () => ({ + createAutoRetryHelpers: createAutoRetryHelpersMock, + })) + + mock.module("./event-handler", () => ({ + createEventHandler: createEventHandlerMock, + })) + + mock.module("./message-update-handler", () => ({ + createMessageUpdateHandler: createMessageUpdateHandlerMock, + })) + + mock.module("./chat-message-handler", () => ({ + createChatMessageHandler: createChatMessageHandlerMock, + })) +} + +function createMockContext(): RuntimeFallbackPluginInput { + return { + client: { + session: { + abort: async () => ({}), + messages: async () => ({}), + promptAsync: async () => ({}), + }, + tui: { + showToast: async () => ({}), + }, + }, + directory: "/test", + } +} + +function createMockInterval(): RuntimeFallbackInterval { + return { + unref: () => {}, + } +} + +describe("createRuntimeFallbackHook initialization", () => { + const originalSetInterval = globalThis.setInterval + let setIntervalCalls = 0 + let createRuntimeFallbackHook: RuntimeFallbackModule["createRuntimeFallbackHook"] + + beforeEach(async () => { + mock.restore() + registerModuleMocks() + loadPluginConfigMock.mockClear() + createAutoRetryHelpersMock.mockClear() + createEventHandlerMock.mockClear() + createMessageUpdateHandlerMock.mockClear() + createChatMessageHandlerMock.mockClear() + setIntervalCalls = 0 + + globalThis.setInterval = ((callback: Parameters[0], delay?: number) => { + void callback + void delay + setIntervalCalls += 1 + return createMockInterval() as ReturnType + }) as typeof globalThis.setInterval + + const cacheBuster = `${Date.now()}-${Math.random()}` + const runtimeFallbackModule: RuntimeFallbackModule = await import(`./hook?test=${cacheBuster}`) + createRuntimeFallbackHook = runtimeFallbackModule.createRuntimeFallbackHook + }) + + afterEach(() => { + globalThis.setInterval = originalSetInterval + mock.restore() + }) + + test("#given injected pluginConfig #when the hook factory runs #then loadPluginConfig is not called", () => { + // given + const pluginConfig = {} satisfies OhMyOpenCodeConfig + + // when + createRuntimeFallbackHook(createMockContext(), { pluginConfig }) + + // then + expect(loadPluginConfigMock).not.toHaveBeenCalled() + }) + + test("#given a fresh hook #when the first event arrives #then cleanup interval starts only once", async () => { + // given + const hook = createRuntimeFallbackHook(createMockContext(), { pluginConfig: {} }) + + // when + expect(setIntervalCalls).toBe(0) + await hook.event({ event: { type: "session.created", properties: {} } }) + expect(setIntervalCalls).toBe(1) + await hook.event({ event: { type: "session.error", properties: {} } }) + + // then + expect(setIntervalCalls).toBe(1) + }) +}) From 7be6ab44784f0cb54aa5f69d796ce25e89e1d601 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:10:26 +0900 Subject: [PATCH 065/146] fix(tools/slashcommand): skip EXCLUDED_DIRS in recursive command discovery Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/slashcommand/command-discovery.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/slashcommand/command-discovery.ts b/src/tools/slashcommand/command-discovery.ts index 7d220ab4f..855f6dc28 100644 --- a/src/tools/slashcommand/command-discovery.ts +++ b/src/tools/slashcommand/command-discovery.ts @@ -6,6 +6,7 @@ import { findProjectOpencodeCommandDirs, getOpenCodeCommandDirs, discoverPluginCommandDefinitions, + EXCLUDED_DIRS, } from "../../shared" import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types" import { isMarkdownFile } from "../../shared/file-utils" @@ -36,6 +37,7 @@ function discoverCommandsFromDir( for (const entry of entries) { if (entry.isDirectory()) { + if (EXCLUDED_DIRS.has(entry.name)) continue if (entry.name.startsWith(".")) continue const nestedPrefix = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${entry.name}` From ac2686ffdea52cb29bbf831976888d8df5cafe6b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:10:45 +0900 Subject: [PATCH 066/146] fix(shared): memoize loadOpencodePlugins by directory Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/shared/load-opencode-plugins.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/shared/load-opencode-plugins.ts b/src/shared/load-opencode-plugins.ts index 5517c74b1..a6beffdcf 100644 --- a/src/shared/load-opencode-plugins.ts +++ b/src/shared/load-opencode-plugins.ts @@ -8,6 +8,8 @@ interface OpencodeConfig { plugin?: (string | [string, ...unknown[]])[] } +const opencodePluginsCache = new Map() + function getWindowsAppdataDir(): string | null { return process.env.APPDATA || null } @@ -33,6 +35,11 @@ function getConfigPaths(directory: string): string[] { } export function loadOpencodePlugins(directory: string): string[] { + const cachedPluginEntries = opencodePluginsCache.get(directory) + if (cachedPluginEntries) { + return cachedPluginEntries + } + const pluginEntries: string[] = [] const seenPluginEntries = new Set() @@ -56,5 +63,10 @@ export function loadOpencodePlugins(directory: string): string[] { } } + opencodePluginsCache.set(directory, pluginEntries) return pluginEntries } + +export function clearOpencodePluginsCache(): void { + opencodePluginsCache.clear() +} From 3cb1d5d936e10702ea887deab2276635d83e8b67 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:10:49 +0900 Subject: [PATCH 067/146] test(claude-code-command-loader): cover excluded dirs and per-directory cache Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../claude-code-command-loader/loader.test.ts | 73 +++++++++++++++++-- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/src/features/claude-code-command-loader/loader.test.ts b/src/features/claude-code-command-loader/loader.test.ts index be7928d3f..b674f8ff9 100644 --- a/src/features/claude-code-command-loader/loader.test.ts +++ b/src/features/claude-code-command-loader/loader.test.ts @@ -1,9 +1,10 @@ import { execFileSync } from "node:child_process" -import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { promises as fs } from "node:fs" +import { afterEach, beforeEach, describe, expect, it, spyOn } from "bun:test" import { mkdirSync, rmSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" -import { loadOpencodeGlobalCommands, loadOpencodeProjectCommands } from "./loader" +import * as loader from "./loader" const TEST_DIR = join(tmpdir(), `claude-code-command-loader-${Date.now()}`) @@ -16,19 +17,41 @@ function writeCommand(directory: string, name: string, description: string): voi } describe("claude-code command loader", () => { + let originalClaudeConfigDir: string | undefined let originalOpencodeConfigDir: string | undefined beforeEach(() => { mkdirSync(TEST_DIR, { recursive: true }) + originalClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR originalOpencodeConfigDir = process.env.OPENCODE_CONFIG_DIR + + const claudeConfigDir = join(TEST_DIR, "claude-config") + const opencodeConfigDir = join(TEST_DIR, "opencode-config") + process.env.CLAUDE_CONFIG_DIR = claudeConfigDir + process.env.OPENCODE_CONFIG_DIR = opencodeConfigDir + + if ("clearCommandLoaderCache" in loader && typeof loader.clearCommandLoaderCache === "function") { + loader.clearCommandLoaderCache() + } }) afterEach(() => { + if (originalClaudeConfigDir === undefined) { + delete process.env.CLAUDE_CONFIG_DIR + } else { + process.env.CLAUDE_CONFIG_DIR = originalClaudeConfigDir + } + if (originalOpencodeConfigDir === undefined) { delete process.env.OPENCODE_CONFIG_DIR } else { process.env.OPENCODE_CONFIG_DIR = originalOpencodeConfigDir } + + if ("clearCommandLoaderCache" in loader && typeof loader.clearCommandLoaderCache === "function") { + loader.clearCommandLoaderCache() + } + rmSync(TEST_DIR, { recursive: true, force: true }) }) @@ -39,7 +62,7 @@ describe("claude-code command loader", () => { writeCommand(join(projectDir, ".opencode", "commands"), "ancestor", "Ancestor command") // when - const commands = await loadOpencodeProjectCommands(childDir) + const commands = await loader.loadOpencodeProjectCommands(childDir) // then expect(commands.ancestor?.description).toBe("(opencode-project) Ancestor command") @@ -50,7 +73,7 @@ describe("claude-code command loader", () => { writeCommand(join(TEST_DIR, ".opencode", "command"), "singular", "Singular command") // when - const commands = await loadOpencodeProjectCommands(TEST_DIR) + const commands = await loader.loadOpencodeProjectCommands(TEST_DIR) // then expect(commands.singular?.description).toBe("(opencode-project) Singular command") @@ -66,7 +89,7 @@ describe("claude-code command loader", () => { writeCommand(projectDir, "duplicate", "Nearest command") // when - const commands = await loadOpencodeProjectCommands(childDir) + const commands = await loader.loadOpencodeProjectCommands(childDir) // then expect(commands.duplicate?.description).toBe("(opencode-project) Nearest command") @@ -79,7 +102,7 @@ describe("claude-code command loader", () => { writeCommand(join(opencodeConfigDir, "commands"), "global-plural", "Global plural command") // when - const commands = await loadOpencodeGlobalCommands() + const commands = await loader.loadOpencodeGlobalCommands() // then expect(commands["global-plural"]?.description).toBe("(opencode) Global plural command") @@ -94,7 +117,7 @@ describe("claude-code command loader", () => { writeCommand(join(profileConfigDir, "commands"), "duplicate-global", "Profile global command") // when - const commands = await loadOpencodeGlobalCommands() + const commands = await loader.loadOpencodeGlobalCommands() // then expect(commands["duplicate-global"]?.description).toBe("(opencode) Profile global command") @@ -114,7 +137,7 @@ describe("claude-code command loader", () => { writeCommand(join(TEST_DIR, ".opencode", "commands"), "outside", "Outside command") // when - const commands = await loadOpencodeProjectCommands(nestedDirectory) + const commands = await loader.loadOpencodeProjectCommands(nestedDirectory) // then expect(commands["deploy/staging"]?.description).toBe("(opencode-project) Deploy staging") @@ -122,4 +145,38 @@ describe("claude-code command loader", () => { expect(commands.outside).toBeUndefined() expect(commands["deploy:staging"]).toBeUndefined() }) + + it("#given commands nested under an excluded basename #when loadProjectCommands is called #then it skips the excluded directory contents", async () => { + // given + writeCommand(join(TEST_DIR, ".claude", "commands"), "real", "Real command") + writeCommand( + join(TEST_DIR, ".claude", "commands", "node_modules"), + "fake", + "Fake command", + ) + + // when + const commands = await loader.loadProjectCommands(TEST_DIR) + + // then + expect(commands.real?.description).toBe("(project) Real command") + expect(commands.fake).toBeUndefined() + }) + + it("#given a previously loaded directory #when loadAllCommands is called twice #then the second call reuses the cached result without readdir calls", async () => { + // given + writeCommand(join(TEST_DIR, ".claude", "commands"), "cached", "Cached command") + const readdirSpy = spyOn(fs, "readdir") + + // when + const firstCommands = await loader.loadAllCommands(TEST_DIR) + const firstReaddirCount = readdirSpy.mock.calls.length + const secondCommands = await loader.loadAllCommands(TEST_DIR) + + // then + expect(firstCommands.cached?.description).toBe("(project) Cached command") + expect(secondCommands).toEqual(firstCommands) + expect(firstReaddirCount).toBeGreaterThan(0) + expect(readdirSpy.mock.calls.length).toBe(firstReaddirCount) + }) }) From a4c45e2770781978d594586421b94efdd107ccfb Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:11:03 +0900 Subject: [PATCH 068/146] fix(write-existing-file-guard): defer realpath/existsSync to first tool call Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/write-existing-file-guard/hook.ts | 12 ++++++++++-- .../lazy-canonical-path-init.test.ts | 4 ++-- .../tool-execute-before-handler.ts | 5 +++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/hooks/write-existing-file-guard/hook.ts b/src/hooks/write-existing-file-guard/hook.ts index bdaf5cad8..ab7bd9aef 100644 --- a/src/hooks/write-existing-file-guard/hook.ts +++ b/src/hooks/write-existing-file-guard/hook.ts @@ -76,7 +76,15 @@ export function isOverwriteEnabled(value: boolean | string | undefined): boolean export function createWriteExistingFileGuardHook(ctx: PluginInput): Hooks { const readPermissionsBySession = new Map>() const sessionLastAccess = new Map() - const canonicalSessionRoot = toCanonicalPath(resolveInputPath(ctx, ctx.directory)) + let canonicalSessionRoot: string | undefined + + function getCanonicalSessionRoot(): string { + if (!canonicalSessionRoot) { + canonicalSessionRoot = toCanonicalPath(resolveInputPath(ctx, ctx.directory)) + } + + return canonicalSessionRoot + } return { "tool.execute.before": async (input, output) => { @@ -86,7 +94,7 @@ export function createWriteExistingFileGuardHook(ctx: PluginInput): Hooks { output, readPermissionsBySession, sessionLastAccess, - canonicalSessionRoot, + getCanonicalSessionRoot, maxTrackedSessions: MAX_TRACKED_SESSIONS, }) }, diff --git a/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts b/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts index 1d3ada213..0f1d4bb88 100644 --- a/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts +++ b/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts @@ -59,7 +59,7 @@ describe("createWriteExistingFileGuardHook", () => { ).rejects.toThrow("File already exists. Use edit tool instead.") // then - expect(existsSyncMock).toHaveBeenCalledTimes(2) - expect(realpathNativeMock).toHaveBeenCalledTimes(1) + expect(existsSyncMock).toHaveBeenCalledTimes(3) + expect(realpathNativeMock).toHaveBeenCalledTimes(2) }) }) diff --git a/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts b/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts index 25eebbda3..848238a8a 100644 --- a/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts +++ b/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts @@ -90,10 +90,10 @@ export async function handleWriteExistingFileGuardToolExecuteBefore(params: { output: { args?: unknown } readPermissionsBySession: Map> sessionLastAccess: Map - canonicalSessionRoot: string + getCanonicalSessionRoot: () => string maxTrackedSessions: number }): Promise { - const { ctx, input, output, readPermissionsBySession, sessionLastAccess, canonicalSessionRoot, maxTrackedSessions } = params + const { ctx, input, output, readPermissionsBySession, sessionLastAccess, getCanonicalSessionRoot, maxTrackedSessions } = params const toolName = input.tool?.toLowerCase() if (toolName !== "write" && toolName !== "read") { return @@ -107,6 +107,7 @@ export async function handleWriteExistingFileGuardToolExecuteBefore(params: { } const resolvedPath = resolveInputPath(ctx, filePath) + const canonicalSessionRoot = getCanonicalSessionRoot() const canonicalPath = toCanonicalPath(resolvedPath) if (!isPathInsideDirectory(canonicalPath, canonicalSessionRoot)) { return From 886ef824948e37254e6697daea4cd4ca264f56cd Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:11:03 +0900 Subject: [PATCH 069/146] perf(directory-readme-injector): migrate sync FS to fs.promises Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/directory-readme-injector/finder.ts | 10 ++++++---- src/hooks/directory-readme-injector/injector.ts | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/hooks/directory-readme-injector/finder.ts b/src/hooks/directory-readme-injector/finder.ts index 70e0ba04d..904ef000c 100644 --- a/src/hooks/directory-readme-injector/finder.ts +++ b/src/hooks/directory-readme-injector/finder.ts @@ -1,4 +1,4 @@ -import { existsSync } from "node:fs"; +import { access } from "node:fs/promises"; import { dirname, isAbsolute, join, resolve } from "node:path"; import { README_FILENAME } from "./constants"; @@ -9,17 +9,19 @@ export function resolveFilePath(rootDirectory: string, path: string): string | n return resolve(rootDirectory, path); } -export function findReadmeMdUp(input: { +export async function findReadmeMdUp(input: { startDir: string; rootDir: string; -}): string[] { +}): Promise { const found: string[] = []; let current = input.startDir; while (true) { const readmePath = join(current, README_FILENAME); - if (existsSync(readmePath)) { + try { + await access(readmePath); found.push(readmePath); + } catch { } if (current === input.rootDir) break; diff --git a/src/hooks/directory-readme-injector/injector.ts b/src/hooks/directory-readme-injector/injector.ts index bfeae7d44..ce3ff7212 100644 --- a/src/hooks/directory-readme-injector/injector.ts +++ b/src/hooks/directory-readme-injector/injector.ts @@ -1,5 +1,5 @@ import type { PluginInput } from "@opencode-ai/plugin"; -import { readFileSync } from "node:fs"; +import { readFile } from "node:fs/promises"; import { dirname } from "node:path"; import type { createDynamicTruncator } from "../../shared/dynamic-truncator"; @@ -31,7 +31,7 @@ export async function processFilePathForReadmeInjection(input: { const dir = dirname(resolved); const cache = getSessionCache(input.sessionCaches, input.sessionID); - const readmePaths = findReadmeMdUp({ startDir: dir, rootDir: input.ctx.directory }); + const readmePaths = await findReadmeMdUp({ startDir: dir, rootDir: input.ctx.directory }); let dirty = false; for (const readmePath of readmePaths) { @@ -39,7 +39,7 @@ export async function processFilePathForReadmeInjection(input: { if (cache.has(readmeDir)) continue; try { - const content = readFileSync(readmePath, "utf-8"); + const content = await readFile(readmePath, "utf-8"); const { result, truncated } = await input.truncator.truncate( input.sessionID, content, From bcd7b8e34891ef0f2f7abd8506faa1d32f2669e0 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:11:14 +0900 Subject: [PATCH 070/146] fix(rules-injector): memoize project-root lookup per process lifecycle Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/rules-injector/hook.ts | 3 +++ src/hooks/rules-injector/project-root-finder.ts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/hooks/rules-injector/hook.ts b/src/hooks/rules-injector/hook.ts index f46af4570..2c37c9b4c 100644 --- a/src/hooks/rules-injector/hook.ts +++ b/src/hooks/rules-injector/hook.ts @@ -3,6 +3,7 @@ import { createDynamicTruncator } from "../../shared/dynamic-truncator"; import { getRuleInjectionFilePath } from "./output-path"; import { createSessionCacheStore } from "./cache"; import { createRuleInjectionProcessor } from "./injector"; +import { clearProjectRootCache } from "./project-root-finder"; interface ToolExecuteInput { tool: string; @@ -75,6 +76,7 @@ export function createRulesInjectorHook( if (sessionInfo?.id) { clearSessionCache(sessionInfo.id); } + clearProjectRootCache(); } if (event.type === "session.compacted") { @@ -83,6 +85,7 @@ export function createRulesInjectorHook( if (sessionID) { clearSessionCache(sessionID); } + clearProjectRootCache(); } }; diff --git a/src/hooks/rules-injector/project-root-finder.ts b/src/hooks/rules-injector/project-root-finder.ts index da697f0d9..ea552e0c9 100644 --- a/src/hooks/rules-injector/project-root-finder.ts +++ b/src/hooks/rules-injector/project-root-finder.ts @@ -2,6 +2,12 @@ import { existsSync, statSync } from "node:fs"; import { dirname, join } from "node:path"; import { PROJECT_MARKERS } from "./constants"; +const projectRootCache = new Map(); + +export function clearProjectRootCache(): void { + projectRootCache.clear(); +} + /** * Find project root by walking up from startPath. * Checks for PROJECT_MARKERS (.git, pyproject.toml, package.json, etc.) @@ -10,6 +16,16 @@ import { PROJECT_MARKERS } from "./constants"; * @returns Project root path or null if not found */ export function findProjectRoot(startPath: string): string | null { + if (projectRootCache.has(startPath)) { + return projectRootCache.get(startPath) ?? null; + } + + const projectRoot = findProjectRootWithoutCache(startPath); + projectRootCache.set(startPath, projectRoot); + return projectRoot; +} + +function findProjectRootWithoutCache(startPath: string): string | null { let current: string; try { From a03faaa278f3aa6038e10b809a1df7dc7135716e Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:11:17 +0900 Subject: [PATCH 071/146] test(auto-update-checker): cover deferred update check Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/auto-update-checker/hook.test.ts | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/hooks/auto-update-checker/hook.test.ts diff --git a/src/hooks/auto-update-checker/hook.test.ts b/src/hooks/auto-update-checker/hook.test.ts new file mode 100644 index 000000000..ecac1f8b1 --- /dev/null +++ b/src/hooks/auto-update-checker/hook.test.ts @@ -0,0 +1,87 @@ +import type { PluginInput } from "@opencode-ai/plugin" +import { describe, expect, mock, test } from "bun:test" + +const latestVersionMock = mock.fn(async () => "3.0.1") +const scheduleDeferredIdleCheckMock = mock.fn((runCheck: () => void) => { + scheduledCheck = runCheck +}) + +let scheduledCheck: (() => void) | null = null + +mock.module("./checker/latest-version", () => ({ + getLatestVersion: latestVersionMock, +})) + +mock.module("./hook/deferred-idle-check", () => ({ + scheduleDeferredIdleCheck: scheduleDeferredIdleCheckMock, +})) + +const createHook = async () => { + const module = await import("./hook") + return module.createAutoUpdateCheckerHook( + { + directory: "/tmp/project", + client: { + tui: { + showToast: async () => undefined, + }, + }, + } satisfies PluginInput, + { + showStartupToast: false, + autoUpdate: false, + }, + { + getCachedVersion: () => "3.0.0", + getLocalDevVersion: () => null, + showConfigErrorsIfAny: async () => undefined, + updateAndShowConnectedProvidersCacheStatus: async () => undefined, + refreshModelCapabilitiesOnStartup: async () => undefined, + showModelCacheWarningIfNeeded: async () => undefined, + showLocalDevToast: async () => undefined, + showVersionToast: async () => undefined, + runBackgroundUpdateCheck: async () => { + await latestVersionMock() + }, + log: () => undefined, + }, + ) +} + +describe("auto-update-checker hook", () => { + test("defers update check until first session idle", async () => { + // given + latestVersionMock.mockClear() + scheduleDeferredIdleCheckMock.mockClear() + scheduledCheck = null + const hook = await createHook() + + // when + hook.event({ event: { type: "session.created" } }) + + // then + expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(0) + expect(latestVersionMock).toHaveBeenCalledTimes(0) + + // when + hook.event({ event: { type: "session.idle" } }) + + // then + expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(1) + expect(latestVersionMock).toHaveBeenCalledTimes(0) + + // when + scheduledCheck?.() + + // then + expect(latestVersionMock).toHaveBeenCalledTimes(1) + + // when + hook.event({ event: { type: "session.idle" } }) + scheduledCheck?.() + + // then + expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(1) + expect(latestVersionMock).toHaveBeenCalledTimes(1) + }) +}) From 79eb6c738fd34f750e74d2da738aa5f0b7bf5c5e Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:11:24 +0900 Subject: [PATCH 072/146] fix(shared/project-discovery-dirs): memoize detectWorktreePath per process --- src/shared/project-discovery-dirs.test.ts | 73 +++++++++-------------- src/shared/project-discovery-dirs.ts | 21 ++++++- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/shared/project-discovery-dirs.test.ts b/src/shared/project-discovery-dirs.test.ts index 2c9f127b5..d2904bc72 100644 --- a/src/shared/project-discovery-dirs.test.ts +++ b/src/shared/project-discovery-dirs.test.ts @@ -4,6 +4,7 @@ import { tmpdir } from "node:os" import { join } from "node:path" const TEST_DIR = join(tmpdir(), `project-discovery-dirs-${Date.now()}`) +let worktreeSpawnCount = 0 function canonicalPath(path: string): string { return realpathSync(path) @@ -18,6 +19,34 @@ describe("project-discovery-dirs", () => { rmSync(TEST_DIR, { recursive: true, force: true }) }) + it("#given repeated worktree detection #when detecting twice #then reuses the cached result", async () => { + // given + worktreeSpawnCount = 0 + + mock.module("node:child_process", () => ({ + execFileSync: () => { + worktreeSpawnCount += 1 + return TEST_DIR + }, + })) + + const { clearWorktreeCache, detectWorktreePath } = await import("./project-discovery-dirs") + + clearWorktreeCache() + + // when + const firstPath = detectWorktreePath("/some/dir") + const secondPath = detectWorktreePath("/some/dir") + clearWorktreeCache() + const thirdPath = detectWorktreePath("/some/dir") + + // then + expect(firstPath).toBe(TEST_DIR) + expect(secondPath).toBe(TEST_DIR) + expect(thirdPath).toBe(TEST_DIR) + expect(worktreeSpawnCount).toBe(2) + }) + it("#given nested .opencode skill directories #when finding project opencode skill dirs #then returns nearest-first with aliases", async () => { // given const projectDir = join(TEST_DIR, "project") @@ -92,48 +121,4 @@ describe("project-discovery-dirs", () => { expect(directories).toEqual([canonicalPath(join(projectDir, ".opencode", "skills"))]) }) - it("#given repeated worktree detection #when detecting twice #then reuses the cached result", async () => { - // given - let callCount = 0 - mock.module("node:child_process", () => ({ - execFileSync: () => { - callCount += 1 - return TEST_DIR - }, - })) - - const { clearWorktreeCache, detectWorktreePath } = await import("./project-discovery-dirs") - - clearWorktreeCache() - - // when - const firstPath = detectWorktreePath("/some/dir") - const secondPath = detectWorktreePath("/some/dir") - - // then - expect(firstPath).toBe(TEST_DIR) - expect(secondPath).toBe(TEST_DIR) - expect(callCount).toBe(1) - }) - - it("#given a cleared worktree cache #when detecting again #then spawns git again", async () => { - // given - let callCount = 0 - mock.module("node:child_process", () => ({ - execFileSync: () => { - callCount += 1 - return TEST_DIR - }, - })) - - const { clearWorktreeCache, detectWorktreePath } = await import("./project-discovery-dirs") - - // when - detectWorktreePath("/some/dir") - clearWorktreeCache() - detectWorktreePath("/some/dir") - - // then - expect(execFileSync).toHaveBeenCalledTimes(2) - }) }) diff --git a/src/shared/project-discovery-dirs.ts b/src/shared/project-discovery-dirs.ts index 4e22b66f6..5e243df5a 100644 --- a/src/shared/project-discovery-dirs.ts +++ b/src/shared/project-discovery-dirs.ts @@ -2,6 +2,8 @@ import { execFileSync } from "node:child_process" import { existsSync, realpathSync } from "node:fs" import { dirname, join, resolve } from "node:path" +const worktreePathCache = new Map() + function normalizePath(path: string): string { const resolvedPath = resolve(path) if (!existsSync(resolvedPath)) { @@ -49,15 +51,28 @@ function findAncestorDirectories( } } -function detectWorktreePath(directory: string): string | undefined { +export function clearWorktreeCache(): void { + worktreePathCache.clear() +} + +export function detectWorktreePath(directory: string): string | undefined { + const resolvedDirectory = resolve(directory) + if (worktreePathCache.has(resolvedDirectory)) { + return worktreePathCache.get(resolvedDirectory) + } + try { - return execFileSync("git", ["rev-parse", "--show-toplevel"], { - cwd: directory, + const worktreePath = execFileSync("git", ["rev-parse", "--show-toplevel"], { + cwd: resolvedDirectory, encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"], }).trim() + + worktreePathCache.set(resolvedDirectory, worktreePath) + return worktreePath } catch { + worktreePathCache.set(resolvedDirectory, undefined) return undefined } } From 443891fdfda2893b1f54cfb9c2bbb2761e59b514 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:11:39 +0900 Subject: [PATCH 073/146] test(rules-injector): cover per-session cache isolation and invalidation Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/rules-injector/cache.test.ts | 74 ++++++++++++++++++++++++ src/hooks/rules-injector/storage.test.ts | 57 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/hooks/rules-injector/cache.test.ts create mode 100644 src/hooks/rules-injector/storage.test.ts diff --git a/src/hooks/rules-injector/cache.test.ts b/src/hooks/rules-injector/cache.test.ts new file mode 100644 index 000000000..39a5bb472 --- /dev/null +++ b/src/hooks/rules-injector/cache.test.ts @@ -0,0 +1,74 @@ +import { afterEach, describe, expect, it } from "bun:test"; +import { randomUUID } from "node:crypto"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { createSessionCacheStore } from "./cache"; +import { RULES_INJECTOR_STORAGE } from "./constants"; +import { clearInjectedRules, saveInjectedRules } from "./storage"; + +const trackedSessionIDs: string[] = []; + +function createSessionID(prefix: string): string { + const sessionID = `${prefix}-${randomUUID()}`; + trackedSessionIDs.push(sessionID); + return sessionID; +} + +function getStoragePath(sessionID: string): string { + return join(RULES_INJECTOR_STORAGE, `${sessionID}.json`); +} + +afterEach(() => { + for (const sessionID of trackedSessionIDs.splice(0)) { + clearInjectedRules(sessionID); + } +}); + +describe("createSessionCacheStore", () => { + it("keeps factory instances isolated for the same session", () => { + // given + const sessionID = createSessionID("cache-isolation"); + const firstStore = createSessionCacheStore(); + const secondStore = createSessionCacheStore(); + const firstCache = firstStore.getSessionCache(sessionID); + + // when + firstCache.contentHashes.add("hash:first"); + firstCache.realPaths.add("/tmp/first-rule.md"); + const secondCache = secondStore.getSessionCache(sessionID); + + // then + expect([...secondCache.contentHashes]).toEqual([]); + expect([...secondCache.realPaths]).toEqual([]); + }); + + it("clears only the targeted session cache and persisted state", () => { + // given + const deletedSessionID = createSessionID("deleted-session"); + const retainedSessionID = createSessionID("retained-session"); + + saveInjectedRules(deletedSessionID, { + contentHashes: new Set(["hash:deleted"]), + realPaths: new Set(["/tmp/deleted-rule.md"]), + }); + saveInjectedRules(retainedSessionID, { + contentHashes: new Set(["hash:retained"]), + realPaths: new Set(["/tmp/retained-rule.md"]), + }); + + const store = createSessionCacheStore(); + store.getSessionCache(deletedSessionID); + const retainedCache = store.getSessionCache(retainedSessionID); + + // when + store.clearSessionCache(deletedSessionID); + const reloadedRetainedCache = store.getSessionCache(retainedSessionID); + + // then + expect(existsSync(getStoragePath(deletedSessionID))).toBe(false); + expect(existsSync(getStoragePath(retainedSessionID))).toBe(true); + expect(reloadedRetainedCache).toBe(retainedCache); + expect([...reloadedRetainedCache.contentHashes]).toEqual(["hash:retained"]); + expect([...reloadedRetainedCache.realPaths]).toEqual(["/tmp/retained-rule.md"]); + }); +}); diff --git a/src/hooks/rules-injector/storage.test.ts b/src/hooks/rules-injector/storage.test.ts new file mode 100644 index 000000000..e12c4a45e --- /dev/null +++ b/src/hooks/rules-injector/storage.test.ts @@ -0,0 +1,57 @@ +import { afterEach, describe, expect, it } from "bun:test"; +import { randomUUID } from "node:crypto"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { RULES_INJECTOR_STORAGE } from "./constants"; +import { + clearInjectedRules, + loadInjectedRules, + saveInjectedRules, +} from "./storage"; + +const trackedSessionIDs: string[] = []; + +function createSessionID(prefix: string): string { + const sessionID = `${prefix}-${randomUUID()}`; + trackedSessionIDs.push(sessionID); + return sessionID; +} + +function getStoragePath(sessionID: string): string { + return join(RULES_INJECTOR_STORAGE, `${sessionID}.json`); +} + +afterEach(() => { + for (const sessionID of trackedSessionIDs.splice(0)) { + clearInjectedRules(sessionID); + } +}); + +describe("storage", () => { + it("reads back only the requested session data from session-scoped files", () => { + // given + const firstSessionID = createSessionID("storage-first"); + const secondSessionID = createSessionID("storage-second"); + + saveInjectedRules(firstSessionID, { + contentHashes: new Set(["hash:first"]), + realPaths: new Set(["/tmp/first-rule.md"]), + }); + saveInjectedRules(secondSessionID, { + contentHashes: new Set(["hash:second"]), + realPaths: new Set(["/tmp/second-rule.md"]), + }); + + // when + const firstLoaded = loadInjectedRules(firstSessionID); + const secondLoaded = loadInjectedRules(secondSessionID); + + // then + expect(existsSync(getStoragePath(firstSessionID))).toBe(true); + expect(existsSync(getStoragePath(secondSessionID))).toBe(true); + expect([...firstLoaded.contentHashes]).toEqual(["hash:first"]); + expect([...firstLoaded.realPaths]).toEqual(["/tmp/first-rule.md"]); + expect([...secondLoaded.contentHashes]).toEqual(["hash:second"]); + expect([...secondLoaded.realPaths]).toEqual(["/tmp/second-rule.md"]); + }); +}); From 4f59e91d2dde8af7e0bdc3d54f667b6ab167e546 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:11:50 +0900 Subject: [PATCH 074/146] test(todo-continuation-enforcer): cover lazy prune interval Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../todo-continuation-enforcer.test.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts b/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts index 9c5a35f5c..fc4faa653 100644 --- a/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts +++ b/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts @@ -249,6 +249,33 @@ describe("todo-continuation-enforcer", () => { _resetForTesting() }) + test("given the first idle event, starts the prune interval lazily", async () => { + // given + const originalSetInterval = globalThis.setInterval + let setIntervalCalls = 0 + globalThis.setInterval = ((callback: TimerCallback, delay?: number, ...args: any[]) => { + setIntervalCalls += 1 + return originalSetInterval(callback, delay, ...args) + }) as typeof setInterval + + try { + const sessionID = "main-lazy-prune" + setMainSession(sessionID) + const hook = createTodoContinuationEnforcer(createMockPluginInput(), { + backgroundManager: createMockBackgroundManager(false), + }) + + // when + await hook.handler({ event: { type: "session.idle", properties: { sessionID } } }) + await hook.handler({ event: { type: "session.idle", properties: { sessionID } } }) + + // then + expect(setIntervalCalls).toBe(1) + } finally { + globalThis.setInterval = originalSetInterval + } + }) + test("should inject continuation when idle with incomplete todos", async () => { fakeTimers.restore() // given - main session with incomplete todos From 3d4299445e8dd3634c92a1f965ba7b15af04c1db Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:12:37 +0900 Subject: [PATCH 075/146] fix(auto-update-checker): defer npm registry check until first idle Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/auto-update-checker/hook.test.ts | 41 +++++++++----- src/hooks/auto-update-checker/hook.ts | 54 ++++++++++--------- .../hook/deferred-idle-check.ts | 4 ++ 3 files changed, 59 insertions(+), 40 deletions(-) create mode 100644 src/hooks/auto-update-checker/hook/deferred-idle-check.ts diff --git a/src/hooks/auto-update-checker/hook.test.ts b/src/hooks/auto-update-checker/hook.test.ts index ecac1f8b1..b7d8e5232 100644 --- a/src/hooks/auto-update-checker/hook.test.ts +++ b/src/hooks/auto-update-checker/hook.test.ts @@ -1,10 +1,23 @@ import type { PluginInput } from "@opencode-ai/plugin" import { describe, expect, mock, test } from "bun:test" -const latestVersionMock = mock.fn(async () => "3.0.1") -const scheduleDeferredIdleCheckMock = mock.fn((runCheck: () => void) => { +let latestVersionCallCount = 0 +let scheduleDeferredIdleCheckCallCount = 0 +const flushMicrotasks = async (count: number): Promise => { + for (let index = 0; index < count; index += 1) { + await Promise.resolve() + } +} + +const latestVersionMock = async () => { + latestVersionCallCount += 1 + return "3.0.1" +} + +const scheduleDeferredIdleCheckMock = (runCheck: () => void) => { + scheduleDeferredIdleCheckCallCount += 1 scheduledCheck = runCheck -}) +} let scheduledCheck: (() => void) | null = null @@ -51,8 +64,8 @@ const createHook = async () => { describe("auto-update-checker hook", () => { test("defers update check until first session idle", async () => { // given - latestVersionMock.mockClear() - scheduleDeferredIdleCheckMock.mockClear() + latestVersionCallCount = 0 + scheduleDeferredIdleCheckCallCount = 0 scheduledCheck = null const hook = await createHook() @@ -60,28 +73,28 @@ describe("auto-update-checker hook", () => { hook.event({ event: { type: "session.created" } }) // then - expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(0) - expect(latestVersionMock).toHaveBeenCalledTimes(0) + expect(scheduleDeferredIdleCheckCallCount).toBe(0) + expect(latestVersionCallCount).toBe(0) // when hook.event({ event: { type: "session.idle" } }) // then - expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(1) - expect(latestVersionMock).toHaveBeenCalledTimes(0) + expect(scheduleDeferredIdleCheckCallCount).toBe(1) + expect(latestVersionCallCount).toBe(0) // when - scheduledCheck?.() + await scheduledCheck?.() + await flushMicrotasks(8) // then - expect(latestVersionMock).toHaveBeenCalledTimes(1) + expect(latestVersionCallCount).toBe(1) // when hook.event({ event: { type: "session.idle" } }) - scheduledCheck?.() // then - expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(1) - expect(latestVersionMock).toHaveBeenCalledTimes(1) + expect(scheduleDeferredIdleCheckCallCount).toBe(1) + expect(latestVersionCallCount).toBe(1) }) }) diff --git a/src/hooks/auto-update-checker/hook.ts b/src/hooks/auto-update-checker/hook.ts index fbe3998da..73f5eed4b 100644 --- a/src/hooks/auto-update-checker/hook.ts +++ b/src/hooks/auto-update-checker/hook.ts @@ -3,6 +3,7 @@ import { log } from "../../shared/logger" import type { AutoUpdateCheckerOptions } from "./types" import { getCachedVersion, getLocalDevVersion } from "./checker" import { runBackgroundUpdateCheck } from "./hook/background-update-check" +import { scheduleDeferredIdleCheck } from "./hook/deferred-idle-check" import { showConfigErrorsIfAny } from "./hook/config-errors-toast" import { updateAndShowConnectedProvidersCacheStatus } from "./hook/connected-providers-status" import { refreshModelCapabilitiesOnStartup } from "./hook/model-capabilities-status" @@ -60,44 +61,45 @@ export function createAutoUpdateCheckerHook( } let hasChecked = false + let hasScheduled = false return { event: ({ event }: { event: { type: string; properties?: unknown } }) => { - if (event.type !== "session.created") return + if (event.type !== "session.idle") return if (isCliRunMode) return - if (hasChecked) return + if (hasChecked || hasScheduled) return - const props = event.properties as { info?: { parentID?: string } } | undefined - if (props?.info?.parentID) return + hasScheduled = true + scheduleDeferredIdleCheck(() => { hasChecked = true + void (async () => { + const cachedVersion = deps.getCachedVersion() + const localDevVersion = deps.getLocalDevVersion(ctx.directory) + const displayVersion = localDevVersion ?? cachedVersion - setTimeout(async () => { - const cachedVersion = deps.getCachedVersion() - const localDevVersion = deps.getLocalDevVersion(ctx.directory) - const displayVersion = localDevVersion ?? cachedVersion + await deps.showConfigErrorsIfAny(ctx) + await deps.updateAndShowConnectedProvidersCacheStatus(ctx) + await deps.refreshModelCapabilitiesOnStartup(modelCapabilities) + await deps.showModelCacheWarningIfNeeded(ctx) - await deps.showConfigErrorsIfAny(ctx) - await deps.updateAndShowConnectedProvidersCacheStatus(ctx) - await deps.refreshModelCapabilitiesOnStartup(modelCapabilities) - await deps.showModelCacheWarningIfNeeded(ctx) - - if (localDevVersion) { - if (showStartupToast) { - deps.showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {}) + if (localDevVersion) { + if (showStartupToast) { + deps.showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {}) + } + deps.log("[auto-update-checker] Local development mode") + return } - deps.log("[auto-update-checker] Local development mode") - return - } - if (showStartupToast) { - deps.showVersionToast(ctx, displayVersion, getToastMessage(false)).catch(() => {}) - } + if (showStartupToast) { + deps.showVersionToast(ctx, displayVersion, getToastMessage(false)).catch(() => {}) + } - deps.runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage).catch((err) => { - deps.log("[auto-update-checker] Background update check failed:", err) - }) - }, 0) + deps.runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage).catch((err) => { + deps.log("[auto-update-checker] Background update check failed:", err) + }) + })() + }) }, } } diff --git a/src/hooks/auto-update-checker/hook/deferred-idle-check.ts b/src/hooks/auto-update-checker/hook/deferred-idle-check.ts new file mode 100644 index 000000000..a929cf4ee --- /dev/null +++ b/src/hooks/auto-update-checker/hook/deferred-idle-check.ts @@ -0,0 +1,4 @@ +export function scheduleDeferredIdleCheck(runCheck: () => void): void { + const timeout = setTimeout(runCheck, 5000) + timeout.unref?.() +} From 76e8508fa4042f0ea74782dfbf90066f0c1c38b3 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:12:41 +0900 Subject: [PATCH 076/146] fix(runtime-fallback): inject pluginConfig and defer cleanup interval to first event Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/runtime-fallback/dispose.test.ts | 3 +- src/hooks/runtime-fallback/hook.ts | 36 ++++++++++++---------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/hooks/runtime-fallback/dispose.test.ts b/src/hooks/runtime-fallback/dispose.test.ts index e49cb0904..643b7c8fb 100644 --- a/src/hooks/runtime-fallback/dispose.test.ts +++ b/src/hooks/runtime-fallback/dispose.test.ts @@ -107,9 +107,10 @@ describe("createRuntimeFallbackHook dispose", () => { globalThis.clearTimeout = originalClearTimeout }) - test("#given runtime-fallback hook created #when dispose() is called #then cleanup interval is cleared", () => { + test("#given runtime-fallback hook handles its first event #when dispose() is called #then cleanup interval is cleared", async () => { // given const hook = createRuntimeFallbackHook(createMockContext(), { pluginConfig: {} }) + await hook.event({ event: { type: "session.created", properties: {} } }) // when hook.dispose?.() diff --git a/src/hooks/runtime-fallback/hook.ts b/src/hooks/runtime-fallback/hook.ts index 2a13d507e..f3509ab0a 100644 --- a/src/hooks/runtime-fallback/hook.ts +++ b/src/hooks/runtime-fallback/hook.ts @@ -1,7 +1,5 @@ import type { HookDeps, RuntimeFallbackHook, RuntimeFallbackInterval, RuntimeFallbackOptions, RuntimeFallbackPluginInput, RuntimeFallbackTimeout } from "./types" -import { DEFAULT_CONFIG, HOOK_NAME } from "./constants" -import { log } from "../../shared/logger" -import { loadPluginConfig } from "../../plugin-config" +import { DEFAULT_CONFIG } from "./constants" import { createAutoRetryHelpers } from "./auto-retry" import { createEventHandler } from "./event-handler" import { createMessageUpdateHandler } from "./message-update-handler" @@ -24,20 +22,11 @@ export function createRuntimeFallbackHook( notify_on_fallback: options?.config?.notify_on_fallback ?? DEFAULT_CONFIG.notify_on_fallback, } - let pluginConfig = options?.pluginConfig - if (!pluginConfig) { - try { - pluginConfig = loadPluginConfig(ctx.directory, ctx) - } catch { - log(`[${HOOK_NAME}] Plugin config not available`) - } - } - const deps: HookDeps = { ctx, config, options, - pluginConfig, + pluginConfig: options?.pluginConfig, sessionStates: new Map(), sessionLastAccess: new Map(), sessionRetryInFlight: new Set(), @@ -51,10 +40,23 @@ export function createRuntimeFallbackHook( const messageUpdateHandler = createMessageUpdateHandler(deps, helpers) const chatMessageHandler = createChatMessageHandler(deps) - const cleanupInterval = setInterval(helpers.cleanupStaleSessions, 5 * 60 * 1000) - cleanupInterval.unref() + let cleanupInterval: RuntimeFallbackInterval | null = null + let intervalStarted = false + + const ensureInterval = (): void => { + if (intervalStarted) return + + intervalStarted = true + cleanupInterval = setInterval(helpers.cleanupStaleSessions, 5 * 60 * 1000) + + if (typeof cleanupInterval.unref === "function") { + cleanupInterval.unref() + } + } const eventHandler = async ({ event }: { event: { type: string; properties?: unknown } }) => { + ensureInterval() + if (event.type === "message.updated") { if (!config.enabled) return const props = event.properties as Record | undefined @@ -65,7 +67,9 @@ export function createRuntimeFallbackHook( } const dispose = () => { - clearInterval(cleanupInterval) + if (cleanupInterval) { + clearInterval(cleanupInterval) + } for (const fallbackTimeout of deps.sessionFallbackTimeouts.values()) { clearTimeout(fallbackTimeout) From 948343ab66b16c5418f66aaa6549393dc1d42257 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:12:50 +0900 Subject: [PATCH 077/146] test(shared): cover detectPluginConfigFile memoization Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/shared/jsonc-parser.memoization.test.ts | 54 +++++++++++++++++++++ src/shared/jsonc-parser.test.ts | 12 ++++- 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 src/shared/jsonc-parser.memoization.test.ts diff --git a/src/shared/jsonc-parser.memoization.test.ts b/src/shared/jsonc-parser.memoization.test.ts new file mode 100644 index 000000000..c4cd1f5b8 --- /dev/null +++ b/src/shared/jsonc-parser.memoization.test.ts @@ -0,0 +1,54 @@ +import { afterEach, describe, expect, mock, spyOn, test } from "bun:test" +import * as fs from "node:fs" +import { join } from "node:path" + +describe("detectPluginConfigFile memoization", () => { + const testDir = join(__dirname, ".test-detect-plugin-memoization") + + afterEach(() => { + mock.restore() + }) + + test("returns cached result on repeated calls for the same directory", async () => { + // given + const existsSync = spyOn(fs, "existsSync").mockImplementation((filePath: fs.PathLike) => { + return String(filePath).endsWith("oh-my-openagent.jsonc") + }) + const readdirSync = spyOn(fs, "readdirSync").mockImplementation(() => []) + spyOn(fs, "readFileSync").mockImplementation(() => "") + + const parserModule = await import(`./jsonc-parser?memoization=${Date.now()}-${Math.random()}`) + + // when + const firstResult = parserModule.detectPluginConfigFile(testDir) + const callsAfterFirstResult = existsSync.mock.calls.length + const secondResult = parserModule.detectPluginConfigFile(testDir) + + // then + expect(firstResult).toEqual(secondResult) + expect(existsSync.mock.calls.length).toBe(callsAfterFirstResult) + expect(readdirSync).toHaveBeenCalledTimes(0) + }) + + test("clears cached result when requested", async () => { + // given + const existsSync = spyOn(fs, "existsSync").mockImplementation((filePath: fs.PathLike) => { + return String(filePath).endsWith("oh-my-openagent.jsonc") + }) + const readdirSync = spyOn(fs, "readdirSync").mockImplementation(() => []) + spyOn(fs, "readFileSync").mockImplementation(() => "") + + const parserModule = await import(`./jsonc-parser?memoization=${Date.now()}-${Math.random()}`) + + parserModule.detectPluginConfigFile(testDir) + parserModule.clearPluginConfigFileDetectionCache() + const callsAfterClear = existsSync.mock.calls.length + + // when + parserModule.detectPluginConfigFile(testDir) + + // then + expect(existsSync.mock.calls.length).toBeGreaterThan(callsAfterClear) + expect(readdirSync).toHaveBeenCalledTimes(0) + }) +}) diff --git a/src/shared/jsonc-parser.test.ts b/src/shared/jsonc-parser.test.ts index 279db1fc5..c06e36353 100644 --- a/src/shared/jsonc-parser.test.ts +++ b/src/shared/jsonc-parser.test.ts @@ -1,5 +1,5 @@ -import { describe, expect, test } from "bun:test" -import { detectConfigFile, detectPluginConfigFile, parseJsonc, parseJsoncSafe, readJsoncFile } from "./jsonc-parser" +import { afterEach, beforeEach, describe, expect, test } from "bun:test" +import { clearPluginConfigFileDetectionCache, detectConfigFile, detectPluginConfigFile, parseJsonc, parseJsoncSafe, readJsoncFile } from "./jsonc-parser" import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs" import { join } from "node:path" @@ -330,6 +330,14 @@ describe("detectConfigFile", () => { describe("detectPluginConfigFile", () => { const testDir = join(__dirname, ".test-detect-plugin") + beforeEach(() => { + clearPluginConfigFileDetectionCache() + }) + + afterEach(() => { + clearPluginConfigFileDetectionCache() + }) + test("prefers oh-my-openagent over oh-my-opencode when both jsonc files exist", () => { // given if (!existsSync(testDir)) mkdirSync(testDir, { recursive: true }) From 6dc2234d898f5268cee241ef39259d773785a4d4 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:12:55 +0900 Subject: [PATCH 078/146] fix(shared): memoize detectPluginConfigFile per process Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/shared/jsonc-parser.ts | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/shared/jsonc-parser.ts b/src/shared/jsonc-parser.ts index da1e0d98c..bb7148983 100644 --- a/src/shared/jsonc-parser.ts +++ b/src/shared/jsonc-parser.ts @@ -9,6 +9,14 @@ export interface JsoncParseResult { errors: Array<{ message: string; offset: number; length: number }> } +type DetectPluginConfigResult = { + format: "json" | "jsonc" | "none" + path: string + legacyPath?: string +} + +const pluginConfigFileDetectionCache = new Map() + function stripBom(content: string): string { return content.charCodeAt(0) === 0xfeff ? content.slice(1) : content } @@ -75,24 +83,34 @@ export function detectConfigFile(basePath: string): { return { format: "none", path: jsonPath } } -export function detectPluginConfigFile(dir: string): { - format: "json" | "jsonc" | "none" - path: string - legacyPath?: string -} { +export function clearPluginConfigFileDetectionCache(): void { + pluginConfigFileDetectionCache.clear() +} + +export function detectPluginConfigFile(dir: string): DetectPluginConfigResult { + const cachedResult = pluginConfigFileDetectionCache.get(dir) + + if (cachedResult !== undefined) { + return cachedResult + } + const canonicalResult = detectConfigFile(join(dir, CONFIG_BASENAME)) const legacyResult = detectConfigFile(join(dir, LEGACY_CONFIG_BASENAME)) + let detectionResult: DetectPluginConfigResult + if (canonicalResult.format !== "none") { - return { + detectionResult = { ...canonicalResult, legacyPath: legacyResult.format !== "none" ? legacyResult.path : undefined, } + } else if (legacyResult.format !== "none") { + detectionResult = legacyResult + } else { + detectionResult = { format: "none", path: join(dir, `${CONFIG_BASENAME}.json`) } } - if (legacyResult.format !== "none") { - return legacyResult - } + pluginConfigFileDetectionCache.set(dir, detectionResult) - return { format: "none", path: join(dir, `${CONFIG_BASENAME}.json`) } + return detectionResult } From 439957c4cd5ec58695056b946e25d455437f4d8e Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:13:07 +0900 Subject: [PATCH 079/146] test(session-notification): cover lazy platform detect and scheduler startup --- .../session-notification-input-needed.test.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/hooks/session-notification-input-needed.test.ts b/src/hooks/session-notification-input-needed.test.ts index ee1614b88..f85d9154d 100644 --- a/src/hooks/session-notification-input-needed.test.ts +++ b/src/hooks/session-notification-input-needed.test.ts @@ -93,6 +93,53 @@ describe("session-notification input-needed events", () => { expect(notificationCalls).toHaveLength(1) expect(notificationCalls[0]).toContain("Agent needs permission to continue") }) + + test("lazily detects platform and starts background checks on first idle event", async () => { + const sessionID = "main-idle" + setMainSession(sessionID) + + const detectPlatformSpy = spyOn(sender, "detectPlatform") + detectPlatformSpy.mockReturnValue("darwin") + + const getDefaultSoundPathSpy = spyOn(sender, "getDefaultSoundPath") + getDefaultSoundPathSpy.mockReturnValue("/System/Library/Sounds/Glass.aiff") + + const startBackgroundCheckSpy = spyOn(utils, "startBackgroundCheck") + startBackgroundCheckSpy.mockImplementation(() => {}) + + // given + const hook = createSessionNotification(createMockPluginInput(), { enforceMainSessionFilter: false }) + + // when + await hook({ + event: { + type: "session.idle", + properties: { + sessionID, + }, + }, + }) + + // then + expect(detectPlatformSpy).toHaveBeenCalledTimes(1) + expect(getDefaultSoundPathSpy).toHaveBeenCalledTimes(1) + expect(startBackgroundCheckSpy).toHaveBeenCalledTimes(1) + + // when + await hook({ + event: { + type: "session.idle", + properties: { + sessionID, + }, + }, + }) + + // then + expect(detectPlatformSpy).toHaveBeenCalledTimes(1) + expect(getDefaultSoundPathSpy).toHaveBeenCalledTimes(1) + expect(startBackgroundCheckSpy).toHaveBeenCalledTimes(1) + }) }) export {} From 89d394ed3e5c8cd1a8dcade96f97bacc5ea0331b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:13:12 +0900 Subject: [PATCH 080/146] fix(claude-code-command-loader): skip EXCLUDED_DIRS and memoize per directory Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../loader-cache.ts | 37 +++++++++++++++++++ .../claude-code-command-loader/loader.ts | 30 ++++++++++++++- 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 src/features/claude-code-command-loader/loader-cache.ts diff --git a/src/features/claude-code-command-loader/loader-cache.ts b/src/features/claude-code-command-loader/loader-cache.ts new file mode 100644 index 000000000..9f0d4d195 --- /dev/null +++ b/src/features/claude-code-command-loader/loader-cache.ts @@ -0,0 +1,37 @@ +import { promises as fs } from "fs" +import { resolve } from "path" + +import type { CommandDefinition } from "./types" + +const commandLoaderCache = new Map>>() + +export async function getCommandLoaderCacheKey(directory?: string): Promise { + const resolvedDirectory = resolve(directory ?? process.cwd()) + + try { + return await fs.realpath(resolvedDirectory) + } catch { + return resolvedDirectory + } +} + +export function getCachedCommands( + cacheKey: string, +): Promise> | undefined { + return commandLoaderCache.get(cacheKey) +} + +export function setCachedCommands( + cacheKey: string, + commands: Promise>, +): void { + commandLoaderCache.set(cacheKey, commands) +} + +export function deleteCachedCommands(cacheKey: string): void { + commandLoaderCache.delete(cacheKey) +} + +export function clearCommandLoaderCache(): void { + commandLoaderCache.clear() +} diff --git a/src/features/claude-code-command-loader/loader.ts b/src/features/claude-code-command-loader/loader.ts index b052f56bd..6ee178b66 100644 --- a/src/features/claude-code-command-loader/loader.ts +++ b/src/features/claude-code-command-loader/loader.ts @@ -4,13 +4,23 @@ import { parseFrontmatter } from "../../shared/frontmatter" import { sanitizeModelField } from "../../shared/model-sanitizer" import { isMarkdownFile } from "../../shared/file-utils" import { + EXCLUDED_DIRS, findProjectOpencodeCommandDirs, getClaudeConfigDir, getOpenCodeCommandDirs, } from "../../shared" import { log } from "../../shared/logger" +import { + clearCommandLoaderCache, + deleteCachedCommands, + getCachedCommands, + getCommandLoaderCacheKey, + setCachedCommands, +} from "./loader-cache" import type { CommandScope, CommandDefinition, CommandFrontmatter, LoadedCommand } from "./types" +export { clearCommandLoaderCache } + async function loadCommandsFromDir( commandsDir: string, scope: CommandScope, @@ -48,6 +58,7 @@ async function loadCommandsFromDir( for (const entry of entries) { if (entry.isDirectory()) { + if (EXCLUDED_DIRS.has(entry.name)) continue if (entry.name.startsWith(".")) continue const subDirPath = join(commandsDir, entry.name) const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name @@ -159,11 +170,26 @@ export async function loadOpencodeProjectCommands(directory?: string): Promise> { - const [user, project, global, projectOpencode] = await Promise.all([ + const cacheKey = await getCommandLoaderCacheKey(directory) + const cachedCommands = getCachedCommands(cacheKey) + if (cachedCommands) { + return cachedCommands + } + + const loadCommandsPromise = Promise.all([ loadUserCommands(), loadProjectCommands(directory), loadOpencodeGlobalCommands(), loadOpencodeProjectCommands(directory), ]) - return { ...projectOpencode, ...global, ...project, ...user } + .then(([user, project, global, projectOpencode]) => { + return { ...projectOpencode, ...global, ...project, ...user } + }) + .catch((error) => { + deleteCachedCommands(cacheKey) + throw error + }) + + setCachedCommands(cacheKey, loadCommandsPromise) + return loadCommandsPromise } From ed6ac7ea96839d8b3d9d64cda316588f1679005d Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:13:12 +0900 Subject: [PATCH 081/146] fix(session-notification): defer platform detection and background checks --- src/hooks/session-notification-init.ts | 31 +++++++++ src/hooks/session-notification.ts | 94 +++++++++++--------------- 2 files changed, 69 insertions(+), 56 deletions(-) create mode 100644 src/hooks/session-notification-init.ts diff --git a/src/hooks/session-notification-init.ts b/src/hooks/session-notification-init.ts new file mode 100644 index 000000000..3dab42ea6 --- /dev/null +++ b/src/hooks/session-notification-init.ts @@ -0,0 +1,31 @@ +import type { Platform } from "./session-notification-sender" +import * as sessionNotificationSender from "./session-notification-sender" +import { startBackgroundCheck } from "./session-notification-utils" + +export function createSessionNotificationInit() { + let platform: Platform | null = null + let defaultSoundPath: string | null = null + let started = false + + function initialize(): { platform: Platform; defaultSoundPath: string } { + if (!platform) { + platform = sessionNotificationSender.detectPlatform() + } + if (!defaultSoundPath) { + defaultSoundPath = sessionNotificationSender.getDefaultSoundPath(platform) + } + if (!started) { + startBackgroundCheck(platform) + started = true + } + + return { + platform, + defaultSoundPath, + } + } + + return { + initialize, + } +} diff --git a/src/hooks/session-notification.ts b/src/hooks/session-notification.ts index dc83d3643..f9a40f56d 100644 --- a/src/hooks/session-notification.ts +++ b/src/hooks/session-notification.ts @@ -1,20 +1,12 @@ import type { PluginInput } from "@opencode-ai/plugin" import { subagentSessions, getMainSessionID } from "../features/claude-code-session-state" -import { - startBackgroundCheck, -} from "./session-notification-utils" import { buildReadyNotificationContent } from "./session-notification-content" -import { - type Platform, -} from "./session-notification-sender" +import { type Platform } from "./session-notification-sender" import * as sessionNotificationSender from "./session-notification-sender" -import { - getEventToolName, - getQuestionText, - getSessionID, -} from "./session-notification-event-properties" +import { getEventToolName, getQuestionText, getSessionID } from "./session-notification-event-properties" import { hasIncompleteTodos } from "./session-todo-status" import { createIdleNotificationScheduler } from "./session-notification-scheduler" +import { createSessionNotificationInit } from "./session-notification-init" interface SessionNotificationConfig { title?: string @@ -33,22 +25,15 @@ interface SessionNotificationConfig { /** Grace period in ms to ignore late-arriving activity events after scheduling (default: 100) */ activityGracePeriodMs?: number } -export function createSessionNotification( - ctx: PluginInput, - config: SessionNotificationConfig = {} -) { - const currentPlatform: Platform = sessionNotificationSender.detectPlatform() - const defaultSoundPath = sessionNotificationSender.getDefaultSoundPath(currentPlatform) - - startBackgroundCheck(currentPlatform) +export function createSessionNotification(ctx: PluginInput, config: SessionNotificationConfig = {}) { const mergedConfig = { title: "OpenCode", message: "Agent is ready for input", questionMessage: "Agent is asking a question", permissionMessage: "Agent needs permission to continue", playSound: false, - soundPath: defaultSoundPath, + soundPath: "", idleConfirmationDelay: 1500, skipIfIncompleteTodos: true, maxTrackedSessions: 100, @@ -56,22 +41,18 @@ export function createSessionNotification( ...config, } + const sessionNotificationInit = createSessionNotificationInit() + let currentPlatform: Platform | null = null + let defaultSoundPath = mergedConfig.soundPath + const scheduler = createIdleNotificationScheduler({ ctx, - platform: currentPlatform, + platform: "unsupported", config: mergedConfig, hasIncompleteTodos, send: async (hookCtx, platform, sessionID) => { - if ( - typeof hookCtx.client.session.get !== "function" - && typeof hookCtx.client.session.messages !== "function" - ) { - await sessionNotificationSender.sendSessionNotification( - hookCtx, - platform, - mergedConfig.title, - mergedConfig.message, - ) + if (typeof hookCtx.client.session.get !== "function" && typeof hookCtx.client.session.messages !== "function") { + await sessionNotificationSender.sendSessionNotification(hookCtx, platform, mergedConfig.title, mergedConfig.message) return } @@ -90,6 +71,15 @@ export function createSessionNotification( const PERMISSION_EVENTS = new Set(["permission.ask", "permission.asked", "permission.updated", "permission.requested"]) const PERMISSION_HINT_PATTERN = /\b(permission|approve|approval|allow|deny|consent)\b/i + const ensureNotificationPlatform = (): Platform => { + if (currentPlatform) return currentPlatform + + const initialized = sessionNotificationInit.initialize() + currentPlatform = initialized.platform + defaultSoundPath = initialized.defaultSoundPath || mergedConfig.soundPath + return currentPlatform + } + const shouldNotifyForSession = (sessionID: string): boolean => { if (subagentSessions.has(sessionID)) return false @@ -102,16 +92,12 @@ export function createSessionNotification( } return async ({ event }: { event: { type: string; properties?: unknown } }) => { - if (currentPlatform === "unsupported") return - const props = event.properties as Record | undefined if (event.type === "session.created") { const info = props?.info as Record | undefined const sessionID = info?.id as string | undefined - if (sessionID) { - scheduler.markSessionActivity(sessionID) - } + if (sessionID) scheduler.markSessionActivity(sessionID) return } @@ -119,6 +105,8 @@ export function createSessionNotification( const sessionID = getSessionID(props) if (!sessionID) return + const platform = ensureNotificationPlatform() + if (platform === "unsupported") return if (!shouldNotifyForSession(sessionID)) return scheduler.scheduleIdleNotification(sessionID) @@ -128,26 +116,22 @@ export function createSessionNotification( if (event.type === "message.updated") { const info = props?.info as Record | undefined const sessionID = getSessionID({ ...props, info }) - if (sessionID) { - scheduler.markSessionActivity(sessionID) - } + if (sessionID) scheduler.markSessionActivity(sessionID) return } if (PERMISSION_EVENTS.has(event.type)) { const sessionID = getSessionID(props) if (!sessionID) return + + const platform = ensureNotificationPlatform() + if (platform === "unsupported") return if (!shouldNotifyForSession(sessionID)) return scheduler.markSessionActivity(sessionID) - await sessionNotificationSender.sendSessionNotification( - ctx, - currentPlatform, - mergedConfig.title, - mergedConfig.permissionMessage, - ) - if (mergedConfig.playSound && mergedConfig.soundPath) { - await sessionNotificationSender.playSessionNotificationSound(ctx, currentPlatform, mergedConfig.soundPath) + await sessionNotificationSender.sendSessionNotification(ctx, platform, mergedConfig.title, mergedConfig.permissionMessage) + if (mergedConfig.playSound && defaultSoundPath) { + await sessionNotificationSender.playSessionNotificationSound(ctx, platform, defaultSoundPath) } return } @@ -160,16 +144,16 @@ export function createSessionNotification( if (event.type === "tool.execute.before") { const toolName = getEventToolName(props)?.toLowerCase() if (toolName && QUESTION_TOOLS.has(toolName)) { + const platform = ensureNotificationPlatform() + if (platform === "unsupported") return if (!shouldNotifyForSession(sessionID)) return const questionText = getQuestionText(props) - const message = PERMISSION_HINT_PATTERN.test(questionText) - ? mergedConfig.permissionMessage - : mergedConfig.questionMessage + const message = PERMISSION_HINT_PATTERN.test(questionText) ? mergedConfig.permissionMessage : mergedConfig.questionMessage - await sessionNotificationSender.sendSessionNotification(ctx, currentPlatform, mergedConfig.title, message) - if (mergedConfig.playSound && mergedConfig.soundPath) { - await sessionNotificationSender.playSessionNotificationSound(ctx, currentPlatform, mergedConfig.soundPath) + await sessionNotificationSender.sendSessionNotification(ctx, platform, mergedConfig.title, message) + if (mergedConfig.playSound && defaultSoundPath) { + await sessionNotificationSender.playSessionNotificationSound(ctx, platform, defaultSoundPath) } } } @@ -179,9 +163,7 @@ export function createSessionNotification( if (event.type === "session.deleted") { const sessionInfo = props?.info as { id?: string } | undefined - if (sessionInfo?.id) { - scheduler.deleteSession(sessionInfo.id) - } + if (sessionInfo?.id) scheduler.deleteSession(sessionInfo.id) } } } From 52512f226aaa4e87070fa74fea53fb2f899ab181 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:13:51 +0900 Subject: [PATCH 082/146] fix(rules-injector): cache directory scan results per session --- src/hooks/rules-injector/cache.ts | 28 +++ src/hooks/rules-injector/hook.ts | 14 +- src/hooks/rules-injector/injector.ts | 12 +- src/hooks/rules-injector/rule-file-finder.ts | 186 +++++++++++-------- src/hooks/rules-injector/rule-scan-cache.ts | 21 +++ 5 files changed, 182 insertions(+), 79 deletions(-) create mode 100644 src/hooks/rules-injector/rule-scan-cache.ts diff --git a/src/hooks/rules-injector/cache.ts b/src/hooks/rules-injector/cache.ts index b23273144..43d64565c 100644 --- a/src/hooks/rules-injector/cache.ts +++ b/src/hooks/rules-injector/cache.ts @@ -1,4 +1,6 @@ import { clearInjectedRules, loadInjectedRules } from "./storage"; +import { createRuleScanCache } from "./rule-scan-cache"; +import type { RuleScanCache } from "./rule-scan-cache"; export type SessionInjectedRulesCache = { contentHashes: Set; @@ -25,3 +27,29 @@ export function createSessionCacheStore(): { return { getSessionCache, clearSessionCache }; } + +export function createSessionRuleScanCacheStore(): { + getSessionRuleScanCache: (sessionID: string) => RuleScanCache; + clearSessionRuleScanCache: (sessionID: string) => void; +} { + const sessionCaches = new Map(); + + function getSessionRuleScanCache(sessionID: string): RuleScanCache { + const existingCache = sessionCaches.get(sessionID); + if (existingCache) { + return existingCache; + } + + const cache = createRuleScanCache(); + sessionCaches.set(sessionID, cache); + return cache; + } + + function clearSessionRuleScanCache(sessionID: string): void { + const cache = sessionCaches.get(sessionID); + cache?.clear(); + sessionCaches.delete(sessionID); + } + + return { getSessionRuleScanCache, clearSessionRuleScanCache }; +} diff --git a/src/hooks/rules-injector/hook.ts b/src/hooks/rules-injector/hook.ts index f46af4570..781acc4a3 100644 --- a/src/hooks/rules-injector/hook.ts +++ b/src/hooks/rules-injector/hook.ts @@ -1,7 +1,7 @@ import type { PluginInput } from "@opencode-ai/plugin"; import { createDynamicTruncator } from "../../shared/dynamic-truncator"; import { getRuleInjectionFilePath } from "./output-path"; -import { createSessionCacheStore } from "./cache"; +import { createSessionCacheStore, createSessionRuleScanCacheStore } from "./cache"; import { createRuleInjectionProcessor } from "./injector"; interface ToolExecuteInput { @@ -36,15 +36,23 @@ export function createRulesInjectorHook( ) { const truncator = createDynamicTruncator(ctx, modelCacheState); const { getSessionCache, clearSessionCache } = createSessionCacheStore(); + const { getSessionRuleScanCache, clearSessionRuleScanCache } = + createSessionRuleScanCacheStore(); const { processFilePathForInjection } = createRuleInjectionProcessor({ workspaceDirectory: ctx.directory, truncator, getSessionCache, + getSessionRuleScanCache, ruleFinderOptions: options?.skipClaudeUserRules ? { skipClaudeUserRules: true } : undefined, }); + function clearSessionState(sessionID: string): void { + clearSessionCache(sessionID); + clearSessionRuleScanCache(sessionID); + } + const toolExecuteAfter = async ( input: ToolExecuteInput, output: ToolExecuteOutput @@ -73,7 +81,7 @@ export function createRulesInjectorHook( if (event.type === "session.deleted") { const sessionInfo = props?.info as { id?: string } | undefined; if (sessionInfo?.id) { - clearSessionCache(sessionInfo.id); + clearSessionState(sessionInfo.id); } } @@ -81,7 +89,7 @@ export function createRulesInjectorHook( const sessionID = (props?.sessionID ?? (props?.info as { id?: string } | undefined)?.id) as string | undefined; if (sessionID) { - clearSessionCache(sessionID); + clearSessionState(sessionID); } } }; diff --git a/src/hooks/rules-injector/injector.ts b/src/hooks/rules-injector/injector.ts index dc4e9fe29..0cd64be5b 100644 --- a/src/hooks/rules-injector/injector.ts +++ b/src/hooks/rules-injector/injector.ts @@ -12,6 +12,7 @@ import { import { parseRuleFrontmatter } from "./parser"; import { saveInjectedRules } from "./storage"; import type { SessionInjectedRulesCache } from "./cache"; +import type { RuleScanCache } from "./rule-scan-cache"; import type { RuleMetadata } from "./types"; type ToolExecuteOutput = { @@ -56,6 +57,7 @@ export function createRuleInjectionProcessor(deps: { workspaceDirectory: string; truncator: DynamicTruncator; getSessionCache: (sessionID: string) => SessionInjectedRulesCache; + getSessionRuleScanCache?: (sessionID: string) => RuleScanCache; ruleFinderOptions?: FindRuleFilesOptions; readFileSync?: typeof readFileSync; statSync?: typeof statSync; @@ -76,6 +78,7 @@ export function createRuleInjectionProcessor(deps: { workspaceDirectory, truncator, getSessionCache, + getSessionRuleScanCache, ruleFinderOptions, readFileSync: readRuleFileSync = readFileSync, statSync: statRuleSync = statSync, @@ -121,9 +124,16 @@ export function createRuleInjectionProcessor(deps: { const projectRoot = findProjectRoot(resolved); const cache = getSessionCache(sessionID); + const ruleScanCache = getSessionRuleScanCache?.(sessionID); const home = getHomeDir(); - const ruleFileCandidates = findRuleFiles(projectRoot, home, resolved, ruleFinderOptions); + const ruleFileCandidates = findRuleFiles( + projectRoot, + home, + resolved, + ruleFinderOptions, + ruleScanCache, + ); const toInject: RuleToInject[] = []; let dirty = false; diff --git a/src/hooks/rules-injector/rule-file-finder.ts b/src/hooks/rules-injector/rule-file-finder.ts index 98bd6942b..7059804d4 100644 --- a/src/hooks/rules-injector/rule-file-finder.ts +++ b/src/hooks/rules-injector/rule-file-finder.ts @@ -1,51 +1,108 @@ import { existsSync, statSync } from "node:fs"; -import { dirname, join } from "node:path"; +import { dirname, join, sep } from "node:path"; import { + OPENCODE_USER_RULE_DIRS, PROJECT_RULE_FILES, PROJECT_RULE_SUBDIRS, USER_RULE_DIR, - OPENCODE_USER_RULE_DIRS, } from "./constants"; -import type { RuleFileCandidate } from "./types"; +import type { RuleScanCache } from "./rule-scan-cache"; import { findRuleFilesRecursive, safeRealpathSync } from "./rule-file-scanner"; +import type { RuleFileCandidate } from "./types"; export interface FindRuleFilesOptions { - /** - * When true, skip loading rules from ~/.claude/rules/. - * Use when claude_code integration is disabled to prevent - * Claude Code-specific instructions from leaking into non-Claude agents. - */ skipClaudeUserRules?: boolean; } -/** - * Find all rule files for a given context. - * Searches from currentFile upward to projectRoot for rule directories, - * then user-level directory (~/.claude/rules). - * - * IMPORTANT: This searches EVERY directory from file to project root. - * Not just the project root itself. - * - * @param projectRoot - Project root path (or null if outside any project) - * @param homeDir - User home directory - * @param currentFile - Current file being edited (for distance calculation) - * @returns Array of rule file candidates sorted by distance - */ +function getUserRuleDirs(homeDir: string, skipClaudeUserRules: boolean): string[] { + const userRuleDirs = OPENCODE_USER_RULE_DIRS.map((dir) => join(homeDir, dir)); + if (!skipClaudeUserRules) { + userRuleDirs.push(join(homeDir, USER_RULE_DIR)); + } + return userRuleDirs; +} + +function createCacheKey( + projectRoot: string | null, + startDir: string, + skipClaudeUserRules: boolean, +): string { + return `${projectRoot ?? ""}|${startDir}|${skipClaudeUserRules ? "1" : "0"}`; +} + +function createCachedCandidate( + filePath: string, + projectRoot: string | null, + startDir: string, + userRuleDirs: string[], +): RuleFileCandidate | undefined { + const realPath = safeRealpathSync(filePath); + + for (const userRuleDir of userRuleDirs) { + if (filePath.startsWith(`${userRuleDir}${sep}`)) { + return { path: filePath, realPath, isGlobal: true, distance: 9999 }; + } + } + + if (projectRoot) { + for (const ruleFile of PROJECT_RULE_FILES) { + if (filePath === join(projectRoot, ruleFile)) { + return { + path: filePath, + realPath, + isGlobal: false, + distance: 0, + isSingleFile: true, + }; + } + } + } + + let currentDir = startDir; + let distance = 0; + while (true) { + for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) { + const ruleDir = join(currentDir, parent, subdir); + if (filePath.startsWith(`${ruleDir}${sep}`)) { + return { path: filePath, realPath, isGlobal: false, distance }; + } + } + + if (projectRoot && currentDir === projectRoot) break; + const parentDir = dirname(currentDir); + if (parentDir === currentDir) break; + currentDir = parentDir; + distance += 1; + } + + return undefined; +} + export function findRuleFiles( projectRoot: string | null, homeDir: string, currentFile: string, options?: FindRuleFilesOptions, + cache?: RuleScanCache, ): RuleFileCandidate[] { + const startDir = dirname(currentFile); + const skipClaudeUserRules = options?.skipClaudeUserRules ?? false; + const userRuleDirs = getUserRuleDirs(homeDir, skipClaudeUserRules); + const cacheKey = createCacheKey(projectRoot, startDir, skipClaudeUserRules); + const cachedPaths = cache?.get(cacheKey); + + if (cachedPaths) { + return cachedPaths + .map((filePath) => createCachedCandidate(filePath, projectRoot, startDir, userRuleDirs)) + .filter((candidate): candidate is RuleFileCandidate => candidate !== undefined); + } + const candidates: RuleFileCandidate[] = []; const seenRealPaths = new Set(); - - // Search from current file's directory up to project root - let currentDir = dirname(currentFile); + let currentDir = startDir; let distance = 0; while (true) { - // Search rule directories in current directory for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) { const ruleDir = join(currentDir, parent, subdir); const files: string[] = []; @@ -55,60 +112,41 @@ export function findRuleFiles( const realPath = safeRealpathSync(filePath); if (seenRealPaths.has(realPath)) continue; seenRealPaths.add(realPath); - - candidates.push({ - path: filePath, - realPath, - isGlobal: false, - distance, - }); + candidates.push({ path: filePath, realPath, isGlobal: false, distance }); } } - // Stop at project root or filesystem root if (projectRoot && currentDir === projectRoot) break; const parentDir = dirname(currentDir); if (parentDir === currentDir) break; currentDir = parentDir; - distance++; + distance += 1; } - // Check for single-file rules at project root (e.g., .github/copilot-instructions.md) if (projectRoot) { for (const ruleFile of PROJECT_RULE_FILES) { const filePath = join(projectRoot, ruleFile); - if (existsSync(filePath)) { - try { - const stat = statSync(filePath); - if (stat.isFile()) { - const realPath = safeRealpathSync(filePath); - if (!seenRealPaths.has(realPath)) { - seenRealPaths.add(realPath); - candidates.push({ - path: filePath, - realPath, - isGlobal: false, - distance: 0, - isSingleFile: true, - }); - } - } - } catch { - // Skip if file can't be read - } + if (!existsSync(filePath)) continue; + + try { + const stat = statSync(filePath); + if (!stat.isFile()) continue; + const realPath = safeRealpathSync(filePath); + if (seenRealPaths.has(realPath)) continue; + seenRealPaths.add(realPath); + candidates.push({ + path: filePath, + realPath, + isGlobal: false, + distance: 0, + isSingleFile: true, + }); + } catch { + continue; } } } - // Search user-level rule directories - // Always search OpenCode-native dirs (~/.sisyphus/rules, ~/.opencode/rules) - const userRuleDirs: string[] = OPENCODE_USER_RULE_DIRS.map((dir) => join(homeDir, dir)); - - // Only search ~/.claude/rules when claude_code integration is not disabled - if (!options?.skipClaudeUserRules) { - userRuleDirs.push(join(homeDir, USER_RULE_DIR)); - } - for (const userRuleDir of userRuleDirs) { const userFiles: string[] = []; findRuleFilesRecursive(userRuleDir, userFiles); @@ -117,23 +155,21 @@ export function findRuleFiles( const realPath = safeRealpathSync(filePath); if (seenRealPaths.has(realPath)) continue; seenRealPaths.add(realPath); - - candidates.push({ - path: filePath, - realPath, - isGlobal: true, - distance: 9999, // Global rules always have max distance - }); + candidates.push({ path: filePath, realPath, isGlobal: true, distance: 9999 }); } } - // Sort by distance (closest first, then global rules last) - candidates.sort((a, b) => { - if (a.isGlobal !== b.isGlobal) { - return a.isGlobal ? 1 : -1; + candidates.sort((left, right) => { + if (left.isGlobal !== right.isGlobal) { + return left.isGlobal ? 1 : -1; } - return a.distance - b.distance; + return left.distance - right.distance; }); + cache?.set( + cacheKey, + candidates.map((candidate) => candidate.path), + ); + return candidates; } diff --git a/src/hooks/rules-injector/rule-scan-cache.ts b/src/hooks/rules-injector/rule-scan-cache.ts new file mode 100644 index 000000000..fc8ff1a20 --- /dev/null +++ b/src/hooks/rules-injector/rule-scan-cache.ts @@ -0,0 +1,21 @@ +export type RuleScanCache = { + get: (key: string) => string[] | undefined; + set: (key: string, value: string[]) => void; + clear: () => void; +}; + +export function createRuleScanCache(): RuleScanCache { + const cache = new Map(); + + return { + get(key: string): string[] | undefined { + return cache.get(key); + }, + set(key: string, value: string[]): void { + cache.set(key, value); + }, + clear(): void { + cache.clear(); + }, + }; +} From 40bd3e02d2c40146c958b6f7430c5d8afe95d0fc Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:14:00 +0900 Subject: [PATCH 083/146] test(tools/skill): cover factory laziness and skill-cache invariants --- src/tools/skill/tools.factory.test.ts | 94 +++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/tools/skill/tools.factory.test.ts diff --git a/src/tools/skill/tools.factory.test.ts b/src/tools/skill/tools.factory.test.ts new file mode 100644 index 000000000..631162dd4 --- /dev/null +++ b/src/tools/skill/tools.factory.test.ts @@ -0,0 +1,94 @@ +/// + +import { afterEach, describe, expect, it, mock } from "bun:test" +import type { LoadedSkill } from "../../features/opencode-skill-loader/types" + +function createMockSkill(name: string): LoadedSkill { + return { + name, + definition: { + name, + description: `Test skill ${name}`, + template: `Test skill template for ${name}`, + }, + scope: "config", + } +} + +async function flushMicrotasks(): Promise { + await Promise.resolve() + await Promise.resolve() +} + +const loadedSkill = createMockSkill("lazy-skill") +const discoverCommandsSync = mock(() => []) +const getAllSkills = mock(async () => [loadedSkill]) +const clearSkillCache = mock(() => {}) + +const skillContentModuleFactory = () => ({ + clearSkillCache, + getAllSkills, + extractSkillTemplate: () => loadedSkill.definition.template ?? "", + injectGitMasterConfig: (body: string) => body, +}) +const commandDiscoveryModuleFactory = () => ({ + discoverCommandsSync, +}) + +mock.module("../../features/opencode-skill-loader/skill-content", skillContentModuleFactory) +mock.module("../../features/opencode-skill-loader/skill-content.ts", skillContentModuleFactory) +mock.module("../slashcommand/command-discovery", commandDiscoveryModuleFactory) +mock.module("../slashcommand/command-discovery.ts", commandDiscoveryModuleFactory) + +const { createSkillTool } = await import("./tools") + +afterEach(async () => { + await flushMicrotasks() +}) + +describe("createSkillTool", () => { + it("delays command discovery until the description getter is accessed", async () => { + // given + const baselineDiscoverCommandsSyncCalls = discoverCommandsSync.mock.calls.length + + // when + const skillTool = createSkillTool({}) + + // then + expect(discoverCommandsSync.mock.calls.length).toBe(baselineDiscoverCommandsSyncCalls) + + void skillTool.description + await flushMicrotasks() + + expect(discoverCommandsSync.mock.calls.length).toBe(baselineDiscoverCommandsSyncCalls + 1) + }) + + it("delays skill loading until execute is invoked", async () => { + // given + const baselineGetAllSkillsCalls = getAllSkills.mock.calls.length + + // when + const skillTool = createSkillTool({}) + + // then + expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls) + + await skillTool.execute({ name: "lazy-skill" }) + + expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls + 1) + }) + + it("does not clear the shared skill cache during description or execute refresh", async () => { + // given + const baselineClearSkillCacheCalls = clearSkillCache.mock.calls.length + + // when + const skillTool = createSkillTool({}) + void skillTool.description + await flushMicrotasks() + await skillTool.execute({ name: "lazy-skill" }) + + // then + expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls) + }) +}) From a068915dc40abfcb8fe23952b06c4d2bff037dc6 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:14:55 +0900 Subject: [PATCH 084/146] test(perf): add plugin init regression budget Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/__tests__/perf/fixtures/in-tree/AGENTS.md | 1 + .../in-tree/packages/pkg-one/AGENTS.md | 1 + .../in-tree/packages/pkg-one/src/file-16.ts | 1 + .../in-tree/packages/pkg-one/src/file-17.ts | 1 + .../in-tree/packages/pkg-one/src/file-18.ts | 1 + .../in-tree/packages/pkg-one/src/file-19.ts | 1 + .../in-tree/packages/pkg-one/src/file-20.ts | 1 + .../perf/fixtures/in-tree/src/AGENTS.md | 1 + .../perf/fixtures/in-tree/src/app/file-01.ts | 1 + .../perf/fixtures/in-tree/src/app/file-02.ts | 1 + .../perf/fixtures/in-tree/src/app/file-03.ts | 1 + .../perf/fixtures/in-tree/src/app/file-04.ts | 1 + .../perf/fixtures/in-tree/src/app/file-05.ts | 1 + .../perf/fixtures/in-tree/src/app/file-06.ts | 1 + .../perf/fixtures/in-tree/src/app/file-07.ts | 1 + .../perf/fixtures/in-tree/src/app/file-08.ts | 1 + .../perf/fixtures/in-tree/src/app/file-09.ts | 1 + .../perf/fixtures/in-tree/src/app/file-10.ts | 1 + .../perf/fixtures/in-tree/src/lib/file-11.ts | 1 + .../perf/fixtures/in-tree/src/lib/file-12.ts | 1 + .../perf/fixtures/in-tree/src/lib/file-13.ts | 1 + .../perf/fixtures/in-tree/src/lib/file-14.ts | 1 + .../perf/fixtures/in-tree/src/lib/file-15.ts | 1 + src/__tests__/perf/plugin-init.test.ts | 121 ++++++++++++++++++ 24 files changed, 144 insertions(+) create mode 100644 src/__tests__/perf/fixtures/in-tree/AGENTS.md create mode 100644 src/__tests__/perf/fixtures/in-tree/packages/pkg-one/AGENTS.md create mode 100644 src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-16.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-17.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-18.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-19.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-20.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/AGENTS.md create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-01.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-02.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-03.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-04.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-05.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-06.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-07.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-08.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-09.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/app/file-10.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/lib/file-11.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/lib/file-12.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/lib/file-13.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/lib/file-14.ts create mode 100644 src/__tests__/perf/fixtures/in-tree/src/lib/file-15.ts create mode 100644 src/__tests__/perf/plugin-init.test.ts diff --git a/src/__tests__/perf/fixtures/in-tree/AGENTS.md b/src/__tests__/perf/fixtures/in-tree/AGENTS.md new file mode 100644 index 000000000..22257f9ad --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/AGENTS.md @@ -0,0 +1 @@ +# fixture root diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/AGENTS.md b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/AGENTS.md new file mode 100644 index 000000000..6bc3f0b2c --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/AGENTS.md @@ -0,0 +1 @@ +# fixture package diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-16.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-16.ts new file mode 100644 index 000000000..dad26290a --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-16.ts @@ -0,0 +1 @@ +export const file16 = 16 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-17.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-17.ts new file mode 100644 index 000000000..01e60135f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-17.ts @@ -0,0 +1 @@ +export const file17 = 17 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-18.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-18.ts new file mode 100644 index 000000000..000ce187b --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-18.ts @@ -0,0 +1 @@ +export const file18 = 18 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-19.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-19.ts new file mode 100644 index 000000000..43ebccb94 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-19.ts @@ -0,0 +1 @@ +export const file19 = 19 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-20.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-20.ts new file mode 100644 index 000000000..763bfe44f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-20.ts @@ -0,0 +1 @@ +export const file20 = 20 diff --git a/src/__tests__/perf/fixtures/in-tree/src/AGENTS.md b/src/__tests__/perf/fixtures/in-tree/src/AGENTS.md new file mode 100644 index 000000000..df55bdcda --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/AGENTS.md @@ -0,0 +1 @@ +# fixture src diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-01.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-01.ts new file mode 100644 index 000000000..8a4e4907d --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-01.ts @@ -0,0 +1 @@ +export const file01 = 1 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-02.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-02.ts new file mode 100644 index 000000000..20ca96c14 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-02.ts @@ -0,0 +1 @@ +export const file02 = 2 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-03.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-03.ts new file mode 100644 index 000000000..b7a0ab9bd --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-03.ts @@ -0,0 +1 @@ +export const file03 = 3 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-04.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-04.ts new file mode 100644 index 000000000..5917ea7a4 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-04.ts @@ -0,0 +1 @@ +export const file04 = 4 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-05.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-05.ts new file mode 100644 index 000000000..7c842b808 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-05.ts @@ -0,0 +1 @@ +export const file05 = 5 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-06.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-06.ts new file mode 100644 index 000000000..b48d2d1cd --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-06.ts @@ -0,0 +1 @@ +export const file06 = 6 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-07.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-07.ts new file mode 100644 index 000000000..9de6f660f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-07.ts @@ -0,0 +1 @@ +export const file07 = 7 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-08.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-08.ts new file mode 100644 index 000000000..2f24a3912 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-08.ts @@ -0,0 +1 @@ +export const file08 = 8 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-09.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-09.ts new file mode 100644 index 000000000..2c4cddbd4 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-09.ts @@ -0,0 +1 @@ +export const file09 = 9 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-10.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-10.ts new file mode 100644 index 000000000..1d329a0dc --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-10.ts @@ -0,0 +1 @@ +export const file10 = 10 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-11.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-11.ts new file mode 100644 index 000000000..eb1a64844 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-11.ts @@ -0,0 +1 @@ +export const file11 = 11 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-12.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-12.ts new file mode 100644 index 000000000..6dbff13ec --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-12.ts @@ -0,0 +1 @@ +export const file12 = 12 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-13.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-13.ts new file mode 100644 index 000000000..5a46ab064 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-13.ts @@ -0,0 +1 @@ +export const file13 = 13 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-14.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-14.ts new file mode 100644 index 000000000..32824f748 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-14.ts @@ -0,0 +1 @@ +export const file14 = 14 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-15.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-15.ts new file mode 100644 index 000000000..c0d19485f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-15.ts @@ -0,0 +1 @@ +export const file15 = 15 diff --git a/src/__tests__/perf/plugin-init.test.ts b/src/__tests__/perf/plugin-init.test.ts new file mode 100644 index 000000000..1450b6557 --- /dev/null +++ b/src/__tests__/perf/plugin-init.test.ts @@ -0,0 +1,121 @@ +import { cpSync, mkdirSync, mkdtempSync, rmSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" + +import type { PluginInput } from "@opencode-ai/plugin" +import { createOpencodeClient } from "@opencode-ai/sdk" +import { describe, expect, it } from "bun:test" + +type InitMetrics = { + coldMs: number + warmMs: [number, number] + medianMs: number +} + +function getMedian(values: number[]): number { + const sorted = [...values].sort((left, right) => left - right) + return sorted[Math.floor(sorted.length / 2)] ?? 0 +} + +function createPluginInput(directory: string): PluginInput { + const client = createOpencodeClient({ directory }) + + return { + client, + project: { + id: `perf-${Date.now()}`, + worktree: directory, + time: { created: Date.now() }, + }, + directory, + worktree: directory, + serverUrl: new URL("http://localhost"), + $: Bun.$, + } +} + +async function importFreshPluginModule(): Promise<(typeof import("../../index"))["default"]> { + const token = `${Date.now()}-${Math.random()}` + return (await import(`../../index?perf=${token}`)).default +} + +async function measureInitMetrics(directory: string): Promise { + const pluginModule = await importFreshPluginModule() + const measurements: number[] = [] + + for (let index = 0; index < 3; index += 1) { + const input = createPluginInput(directory) + const start = performance.now() + await pluginModule.server(input, {}) + measurements.push(performance.now() - start) + } + + return { + coldMs: measurements[0] ?? 0, + warmMs: [measurements[1] ?? 0, measurements[2] ?? 0], + medianMs: getMedian(measurements), + } +} + +async function measureScenario( + label: string, + populateDirectory: (directory: string) => void, +): Promise { + const rootDirectory = mkdtempSync(join(tmpdir(), "perf-d09-")) + const projectDirectory = join(rootDirectory, label) + const configDirectory = join(rootDirectory, "opencode-config") + const previousConfigDirectory = process.env.OPENCODE_CONFIG_DIR + + mkdirSync(configDirectory, { recursive: true }) + process.env.OPENCODE_CONFIG_DIR = configDirectory + + try { + populateDirectory(projectDirectory) + return await measureInitMetrics(projectDirectory) + } finally { + if (previousConfigDirectory === undefined) { + delete process.env.OPENCODE_CONFIG_DIR + } else { + process.env.OPENCODE_CONFIG_DIR = previousConfigDirectory + } + + rmSync(rootDirectory, { recursive: true, force: true }) + } +} + +function logMetrics(label: string, metrics: InitMetrics): void { + console.info( + `${label}: cold=${metrics.coldMs.toFixed(1)}ms warm=[${metrics.warmMs.map((value) => value.toFixed(1)).join(", ")}] median=${metrics.medianMs.toFixed(1)}ms`, + ) +} + +describe("plugin init performance", () => { + it("stays within the empty project init budget", async () => { + // given + const metrics = await measureScenario("empty-project", (directory) => { + mkdirSync(directory, { recursive: true }) + }) + + // when + logMetrics("empty-project", metrics) + + // then + // regression budget + expect(metrics.medianMs).toBeLessThan(500) + }) + + it("stays within the in-tree fixture init budget", async () => { + // given + const fixtureDirectory = new URL("./fixtures/in-tree/", import.meta.url) + const metrics = await measureScenario("in-tree-fixture", (directory) => { + cpSync(fixtureDirectory, directory, { recursive: true }) + }) + + // when + logMetrics("in-tree-fixture", metrics) + + // then + // regression budget + expect(metrics.medianMs).toBeLessThan(700) + }) +}) From 1be1cd6e535dd7a677c9044721fba9204e8a824f Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:15:14 +0900 Subject: [PATCH 085/146] fix(tools/skill): make factory pure and stop defeating skill-loader cache --- src/tools/skill/tools.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tools/skill/tools.ts b/src/tools/skill/tools.ts index 0fada5607..680fe638e 100644 --- a/src/tools/skill/tools.ts +++ b/src/tools/skill/tools.ts @@ -4,7 +4,7 @@ import type { ToolContext } from "@opencode-ai/plugin/tool" import { TOOL_DESCRIPTION_PREFIX } from "./constants" import type { SkillArgs, SkillLoadOptions } from "./types" import type { LoadedSkill } from "../../features/opencode-skill-loader" -import { getAllSkills, clearSkillCache } from "../../features/opencode-skill-loader/skill-content" +import { getAllSkills } from "../../features/opencode-skill-loader/skill-content" import { injectGitMasterConfig } from "../../features/opencode-skill-loader/skill-content" import { discoverCommandsSync } from "../slashcommand/command-discovery" import type { CommandInfo } from "../slashcommand/types" @@ -28,7 +28,6 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition let cachedDescription: string | null = null const getSkills = async (): Promise => { - clearSkillCache() const discovered = await getAllSkills({ disabledSkills: options?.disabledSkills, browserProvider: options?.browserProvider, @@ -92,8 +91,6 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition } } else if (options.commands !== undefined) { cachedDescription = formatCombinedDescription([], options.commands) - } else { - void buildDescription() } return tool({ From edcc9a1e645af5084382bd34649d453d7f58b9d9 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 14:16:40 +0900 Subject: [PATCH 086/146] fix(todo-continuation-enforcer): defer prune interval to first idle event Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../dispose.test.ts | 15 +++++++-- .../todo-continuation-enforcer/handler.ts | 1 + .../session-state.ts | 32 ++++++++++++------- .../todo-continuation-enforcer.test.ts | 2 +- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/hooks/todo-continuation-enforcer/dispose.test.ts b/src/hooks/todo-continuation-enforcer/dispose.test.ts index 5423c8068..37971bc6d 100644 --- a/src/hooks/todo-continuation-enforcer/dispose.test.ts +++ b/src/hooks/todo-continuation-enforcer/dispose.test.ts @@ -8,6 +8,7 @@ declare module "bun:test" { import { afterAll, afterEach, describe, expect, it, mock } from "bun:test" +import type { BackgroundManager } from "../../features/background-agent" import * as actualSessionStateModule from "./session-state" import type { SessionStateStore } from "./session-state" @@ -37,6 +38,12 @@ function createMockPluginInput(): PluginInput { } as PluginInput } +function createMockBackgroundManager(): BackgroundManager { + return { + getTasksByParentSession: () => [{ status: "running" }], + } as BackgroundManager +} + function getCreatedSessionStateStore(): SessionStateStore { if (!createdSessionStateStore) { throw new Error("expected session state store to be created") @@ -68,7 +75,7 @@ describe("todo-continuation-enforcer dispose", () => { enforcer.dispose() }) - it("#given enforcer with active session states #when dispose is called #then internal session state store is shut down", () => { + it("#given enforcer with active session states #when dispose is called #then internal session state store is shut down", async () => { // given const originalClearInterval = globalThis.clearInterval const clearIntervalCalls: Array[0]> = [] @@ -78,9 +85,13 @@ describe("todo-continuation-enforcer dispose", () => { }) as typeof clearInterval try { - const enforcer = createTodoContinuationEnforcer(createMockPluginInput()) + const enforcer = createTodoContinuationEnforcer(createMockPluginInput(), { + backgroundManager: createMockBackgroundManager(), + }) const sessionStateStore = getCreatedSessionStateStore() + await enforcer.handler({ event: { type: "session.idle", properties: { sessionID: "session-1" } } }) + enforcer.markRecovering("session-1") enforcer.markRecovering("session-2") diff --git a/src/hooks/todo-continuation-enforcer/handler.ts b/src/hooks/todo-continuation-enforcer/handler.ts index 3347ee666..7136dda44 100644 --- a/src/hooks/todo-continuation-enforcer/handler.ts +++ b/src/hooks/todo-continuation-enforcer/handler.ts @@ -61,6 +61,7 @@ export function createTodoContinuationHandler(args: { const sessionID = props?.sessionID as string | undefined if (!sessionID) return + sessionStateStore.startPruneInterval() await handleSessionIdle({ ctx, sessionID, diff --git a/src/hooks/todo-continuation-enforcer/session-state.ts b/src/hooks/todo-continuation-enforcer/session-state.ts index a87472b7a..dcd88629e 100644 --- a/src/hooks/todo-continuation-enforcer/session-state.ts +++ b/src/hooks/todo-continuation-enforcer/session-state.ts @@ -31,6 +31,7 @@ export interface ContinuationProgressUpdate { export interface SessionStateStore { getState: (sessionID: string) => SessionState getExistingState: (sessionID: string) => SessionState | undefined + startPruneInterval: () => void recordActivity: (sessionID: string) => void trackContinuationProgress: ( sessionID: string, @@ -76,18 +77,26 @@ export function createSessionStateStore(): SessionStateStore { // Periodic pruning of stale session states to prevent unbounded Map growth let pruneInterval: TimerHandle | undefined - pruneInterval = setInterval(() => { - const now = Date.now() - for (const [sessionID, tracked] of sessions.entries()) { - if (now - tracked.lastAccessedAt > SESSION_STATE_TTL_MS) { - cancelCountdown(sessionID) - sessions.delete(sessionID) - } + let pruneIntervalStarted = false + + function startPruneInterval(): void { + if (pruneIntervalStarted) { + return + } + + pruneIntervalStarted = true + pruneInterval = setInterval(() => { + const now = Date.now() + for (const [sessionID, tracked] of sessions.entries()) { + if (now - tracked.lastAccessedAt > SESSION_STATE_TTL_MS) { + cancelCountdown(sessionID) + sessions.delete(sessionID) + } + } + }, SESSION_STATE_PRUNE_INTERVAL_MS) + if (typeof pruneInterval === "object" && typeof pruneInterval.unref === "function") { + pruneInterval.unref() } - }, SESSION_STATE_PRUNE_INTERVAL_MS) - // Allow process to exit naturally even if interval is running - if (typeof pruneInterval === "object" && typeof pruneInterval.unref === "function") { - pruneInterval.unref() } function getTrackedSession(sessionID: string): TrackedSessionState { @@ -272,6 +281,7 @@ export function createSessionStateStore(): SessionStateStore { return { getState, getExistingState, + startPruneInterval, recordActivity, trackContinuationProgress, resetContinuationProgress, diff --git a/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts b/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts index fc4faa653..5315b0842 100644 --- a/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts +++ b/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts @@ -262,7 +262,7 @@ describe("todo-continuation-enforcer", () => { const sessionID = "main-lazy-prune" setMainSession(sessionID) const hook = createTodoContinuationEnforcer(createMockPluginInput(), { - backgroundManager: createMockBackgroundManager(false), + backgroundManager: createMockBackgroundManager(true), }) // when From 61675adbf128a037b37d810c86c9161a4c2f07bf Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:53:14 +0900 Subject: [PATCH 087/146] test(slashcommand): isolate command-loader cache between tests --- src/hooks/auto-slash-command/executor.test.ts | 3 +++ src/hooks/auto-slash-command/index.test.ts | 3 +++ src/tools/slashcommand/execution-compatibility.test.ts | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/hooks/auto-slash-command/executor.test.ts b/src/hooks/auto-slash-command/executor.test.ts index 246557275..0fe169cb6 100644 --- a/src/hooks/auto-slash-command/executor.test.ts +++ b/src/hooks/auto-slash-command/executor.test.ts @@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test" import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" +import { clearCommandLoaderCache } from "../../features/claude-code-command-loader" import { executeSlashCommand } from "./executor" const ENV_KEYS = [ @@ -95,6 +96,7 @@ describe("auto-slash command executor plugin dispatch", () => { let envSnapshot: EnvSnapshot beforeEach(() => { + clearCommandLoaderCache() tempDir = mkdtempSync(join(tmpdir(), "omo-executor-plugin-test-")) envSnapshot = { CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR, @@ -106,6 +108,7 @@ describe("auto-slash command executor plugin dispatch", () => { }) afterEach(() => { + clearCommandLoaderCache() for (const key of ENV_KEYS) { const previousValue = envSnapshot[key] if (previousValue === undefined) { diff --git a/src/hooks/auto-slash-command/index.test.ts b/src/hooks/auto-slash-command/index.test.ts index 543341b0b..cda63bf8c 100644 --- a/src/hooks/auto-slash-command/index.test.ts +++ b/src/hooks/auto-slash-command/index.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it, beforeEach, afterEach, spyOn, mock } from "bun:te import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" +import { clearCommandLoaderCache } from "../../features/claude-code-command-loader" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" import type { AutoSlashCommandHookInput, @@ -43,6 +44,7 @@ describe("createAutoSlashCommandHook", () => { let createAutoSlashCommandHook: AutoSlashCommandModule["createAutoSlashCommandHook"] beforeEach(async () => { + clearCommandLoaderCache() mock.restore() logCalls = [] spyOn(shared, "log").mockImplementation((message: string, data?: unknown) => { @@ -56,6 +58,7 @@ describe("createAutoSlashCommandHook", () => { }) afterEach(() => { + clearCommandLoaderCache() process.chdir(originalWorkingDirectory) rmSync(tempDir, { recursive: true, force: true }) mock.restore() diff --git a/src/tools/slashcommand/execution-compatibility.test.ts b/src/tools/slashcommand/execution-compatibility.test.ts index 6d63bd678..a33b4bcc4 100644 --- a/src/tools/slashcommand/execution-compatibility.test.ts +++ b/src/tools/slashcommand/execution-compatibility.test.ts @@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test" import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" +import { clearCommandLoaderCache } from "../../features/claude-code-command-loader" function requireFresh(modulePath: string): T { const resolvedPath = require.resolve(modulePath) @@ -25,12 +26,14 @@ describe("slashcommand discovery and execution compatibility", () => { let originalOpencodeConfigDir: string | undefined beforeEach(() => { + clearCommandLoaderCache() tempDir = mkdtempSync(join(tmpdir(), "omo-slashcommand-compat-test-")) originalWorkingDirectory = process.cwd() originalOpencodeConfigDir = process.env.OPENCODE_CONFIG_DIR }) afterEach(() => { + clearCommandLoaderCache() process.chdir(originalWorkingDirectory) if (originalOpencodeConfigDir === undefined) { From 14868430bcd85eacb71d0783eeacabe3e3cef3c2 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:55:51 +0900 Subject: [PATCH 088/146] test(auto-update-checker): align test triggers with deferred idle check --- src/hooks/auto-update-checker/hook.test.ts | 201 +++++++++++++++++---- 1 file changed, 163 insertions(+), 38 deletions(-) diff --git a/src/hooks/auto-update-checker/hook.test.ts b/src/hooks/auto-update-checker/hook.test.ts index b7d8e5232..4a8096bb9 100644 --- a/src/hooks/auto-update-checker/hook.test.ts +++ b/src/hooks/auto-update-checker/hook.test.ts @@ -1,8 +1,13 @@ import type { PluginInput } from "@opencode-ai/plugin" import { describe, expect, mock, test } from "bun:test" +type CreateAutoUpdateCheckerHook = typeof import("./hook").createAutoUpdateCheckerHook +type HookOptions = Parameters[1] +type HookDeps = NonNullable[2]> + let latestVersionCallCount = 0 let scheduleDeferredIdleCheckCallCount = 0 + const flushMicrotasks = async (count: number): Promise => { for (let index = 0; index < count; index += 1) { await Promise.resolve() @@ -29,72 +34,192 @@ mock.module("./hook/deferred-idle-check", () => ({ scheduleDeferredIdleCheck: scheduleDeferredIdleCheckMock, })) -const createHook = async () => { +const createPluginInput = (): PluginInput => ({ + client: {} as PluginInput["client"], + directory: "/tmp/project", + project: {} as PluginInput["project"], + worktree: "/tmp/project", + serverUrl: new URL("https://example.com"), + $: {} as PluginInput["$"], +} satisfies PluginInput) + +const createDeps = (overrides: Partial = {}) => { + const showConfigErrorsIfAny = mock(async () => undefined) + const updateAndShowConnectedProvidersCacheStatus = mock(async () => undefined) + const refreshModelCapabilitiesOnStartup = mock(async () => undefined) + const showModelCacheWarningIfNeeded = mock(async () => undefined) + const showLocalDevToast = mock(async () => undefined) + const showVersionToast = mock(async () => undefined) + const runBackgroundUpdateCheck = mock(async () => { + await latestVersionMock() + }) + + const deps: HookDeps = { + getCachedVersion: () => "3.0.0", + getLocalDevVersion: () => null, + showConfigErrorsIfAny, + updateAndShowConnectedProvidersCacheStatus, + refreshModelCapabilitiesOnStartup, + showModelCacheWarningIfNeeded, + showLocalDevToast, + showVersionToast, + runBackgroundUpdateCheck, + log: () => undefined, + ...overrides, + } + + return { + deps, + mocks: { + showConfigErrorsIfAny, + updateAndShowConnectedProvidersCacheStatus, + refreshModelCapabilitiesOnStartup, + showModelCacheWarningIfNeeded, + showLocalDevToast, + showVersionToast, + runBackgroundUpdateCheck, + }, + } +} + +const createHook = async ( + options: HookOptions = {}, + overrides: Partial = {}, +) => { const module = await import("./hook") - return module.createAutoUpdateCheckerHook( - { - directory: "/tmp/project", - client: { - tui: { - showToast: async () => undefined, - }, + const { deps, mocks } = createDeps(overrides) + + return { + hook: module.createAutoUpdateCheckerHook( + createPluginInput(), + { + showStartupToast: true, + autoUpdate: false, + ...options, }, - } satisfies PluginInput, - { - showStartupToast: false, - autoUpdate: false, - }, - { - getCachedVersion: () => "3.0.0", - getLocalDevVersion: () => null, - showConfigErrorsIfAny: async () => undefined, - updateAndShowConnectedProvidersCacheStatus: async () => undefined, - refreshModelCapabilitiesOnStartup: async () => undefined, - showModelCacheWarningIfNeeded: async () => undefined, - showLocalDevToast: async () => undefined, - showVersionToast: async () => undefined, - runBackgroundUpdateCheck: async () => { - await latestVersionMock() - }, - log: () => undefined, - }, - ) + deps, + ), + mocks, + } +} + +const resetDeferredState = (): void => { + latestVersionCallCount = 0 + scheduleDeferredIdleCheckCallCount = 0 + scheduledCheck = null +} + +const triggerDeferredIdleCheck = async ( + hook: ReturnType, +): Promise => { + hook.event({ event: { type: "session.idle" } }) + scheduledCheck?.() + await flushMicrotasks(8) } describe("auto-update-checker hook", () => { test("defers update check until first session idle", async () => { // given - latestVersionCallCount = 0 - scheduleDeferredIdleCheckCallCount = 0 - scheduledCheck = null - const hook = await createHook() + resetDeferredState() + const { hook, mocks } = await createHook() // when hook.event({ event: { type: "session.created" } }) // then expect(scheduleDeferredIdleCheckCallCount).toBe(0) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() expect(latestVersionCallCount).toBe(0) + // when + await triggerDeferredIdleCheck(hook) + + // then + expect(scheduleDeferredIdleCheckCallCount).toBe(1) + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) + expect(latestVersionCallCount).toBe(1) + // when hook.event({ event: { type: "session.idle" } }) // then expect(scheduleDeferredIdleCheckCallCount).toBe(1) - expect(latestVersionCallCount).toBe(0) + expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) + }) + + test("runs all startup checks on normal session.idle", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() // when - await scheduledCheck?.() + await triggerDeferredIdleCheck(hook) + + // then + expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) + expect(mocks.updateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mocks.refreshModelCapabilitiesOnStartup).toHaveBeenCalledTimes(1) + expect(mocks.showModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) + }) + + test("runs only once (hasChecked guard)", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + hook.event({ event: { type: "session.idle" } }) + hook.event({ event: { type: "session.idle" } }) + scheduledCheck?.() await flushMicrotasks(8) // then - expect(latestVersionCallCount).toBe(1) + expect(scheduleDeferredIdleCheckCallCount).toBe(1) + expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) + expect(mocks.updateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mocks.showModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) + }) + + test("shows localDevToast when local dev version exists", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook({}, { + getLocalDevVersion: () => "3.0.0-dev", + }) // when - hook.event({ event: { type: "session.idle" } }) + await triggerDeferredIdleCheck(hook) // then - expect(scheduleDeferredIdleCheckCallCount).toBe(1) - expect(latestVersionCallCount).toBe(1) + expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) + expect(mocks.updateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mocks.showModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) + expect(mocks.showLocalDevToast).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() + expect(latestVersionCallCount).toBe(0) + }) + + test("passes correct toast message with sisyphus enabled", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook({ isSisyphusEnabled: true }) + + // when + await triggerDeferredIdleCheck(hook) + + // then + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).toHaveBeenCalledWith( + expect.anything(), + "3.0.0", + expect.stringContaining("Sisyphus"), + ) }) }) From 10b1905f60816f0ff07c9e97a55fe6db5ed70c83 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:57:23 +0900 Subject: [PATCH 089/146] test(skill-loader): reset shared skill cache in async resolver tests --- .../opencode-skill-loader/skill-content.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/features/opencode-skill-loader/skill-content.test.ts b/src/features/opencode-skill-loader/skill-content.test.ts index 64d6d5bf4..dedf74413 100644 --- a/src/features/opencode-skill-loader/skill-content.test.ts +++ b/src/features/opencode-skill-loader/skill-content.test.ts @@ -3,12 +3,19 @@ import { describe, it, expect, beforeEach, afterEach } from "bun:test" import { join } from "node:path" import { tmpdir } from "node:os" -import { resolveSkillContent, resolveMultipleSkills, resolveSkillContentAsync, resolveMultipleSkillsAsync } from "./skill-content" +import { + clearSkillCache, + resolveSkillContent, + resolveMultipleSkills, + resolveSkillContentAsync, + resolveMultipleSkillsAsync, +} from "./skill-content" let originalEnv: Record let testConfigDir: string beforeEach(() => { + clearSkillCache() originalEnv = { CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR, OPENCODE_CONFIG_DIR: process.env.OPENCODE_CONFIG_DIR, @@ -20,6 +27,7 @@ beforeEach(() => { }) afterEach(() => { + clearSkillCache() for (const [key, value] of Object.entries(originalEnv)) { if (value !== undefined) { process.env[key] = value From 0e1a946c1d8e7b9f29cc97dbb37ef994fe263388 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:57:30 +0900 Subject: [PATCH 090/146] test(skill-tool): isolate skill discovery spies from other suites --- src/tools/skill/tools.factory.test.ts | 41 +++++++++++++++------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/tools/skill/tools.factory.test.ts b/src/tools/skill/tools.factory.test.ts index 631162dd4..f266aa684 100644 --- a/src/tools/skill/tools.factory.test.ts +++ b/src/tools/skill/tools.factory.test.ts @@ -1,7 +1,11 @@ /// -import { afterEach, describe, expect, it, mock } from "bun:test" +import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test" +import type { ToolContext } from "@opencode-ai/plugin/tool" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" +import * as skillContent from "../../features/opencode-skill-loader/skill-content" +import * as commandDiscovery from "../slashcommand/command-discovery" +import { createSkillTool } from "./tools" function createMockSkill(name: string): LoadedSkill { return { @@ -24,26 +28,27 @@ const loadedSkill = createMockSkill("lazy-skill") const discoverCommandsSync = mock(() => []) const getAllSkills = mock(async () => [loadedSkill]) const clearSkillCache = mock(() => {}) +const mockContext: ToolContext = { + sessionID: "test-session", + messageID: "msg-1", + agent: "test-agent", + directory: "/test", + worktree: "/test", + abort: new AbortController().signal, + metadata: () => {}, + ask: async () => {}, +} -const skillContentModuleFactory = () => ({ - clearSkillCache, - getAllSkills, - extractSkillTemplate: () => loadedSkill.definition.template ?? "", - injectGitMasterConfig: (body: string) => body, +beforeEach(() => { + mock.restore() + spyOn(commandDiscovery, "discoverCommandsSync").mockImplementation(discoverCommandsSync) + spyOn(skillContent, "getAllSkills").mockImplementation(getAllSkills) + spyOn(skillContent, "clearSkillCache").mockImplementation(clearSkillCache) }) -const commandDiscoveryModuleFactory = () => ({ - discoverCommandsSync, -}) - -mock.module("../../features/opencode-skill-loader/skill-content", skillContentModuleFactory) -mock.module("../../features/opencode-skill-loader/skill-content.ts", skillContentModuleFactory) -mock.module("../slashcommand/command-discovery", commandDiscoveryModuleFactory) -mock.module("../slashcommand/command-discovery.ts", commandDiscoveryModuleFactory) - -const { createSkillTool } = await import("./tools") afterEach(async () => { await flushMicrotasks() + mock.restore() }) describe("createSkillTool", () => { @@ -73,7 +78,7 @@ describe("createSkillTool", () => { // then expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls) - await skillTool.execute({ name: "lazy-skill" }) + await skillTool.execute({ name: "lazy-skill" }, mockContext) expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls + 1) }) @@ -86,7 +91,7 @@ describe("createSkillTool", () => { const skillTool = createSkillTool({}) void skillTool.description await flushMicrotasks() - await skillTool.execute({ name: "lazy-skill" }) + await skillTool.execute({ name: "lazy-skill" }, mockContext) // then expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls) From 8e3f4cc63c0ce3636bb74c93be64c75390b55082 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:57:44 +0900 Subject: [PATCH 091/146] fix(tools/skill): harden description pipeline against empty skill list after lazy factory --- src/tools/skill/description-formatter.ts | 11 +- src/tools/skill/tools.ts | 6 +- .../zauc-mocks-skill-tools/tools.test.ts | 163 ++++++++++++------ 3 files changed, 120 insertions(+), 60 deletions(-) diff --git a/src/tools/skill/description-formatter.ts b/src/tools/skill/description-formatter.ts index fb8dd87c5..20907cda1 100644 --- a/src/tools/skill/description-formatter.ts +++ b/src/tools/skill/description-formatter.ts @@ -38,14 +38,17 @@ function formatSlashCommand(command: CommandInfo): string { return lines.join("\n") } -export function formatCombinedDescription(skills: SkillInfo[], commands: CommandInfo[]): string { - if (skills.length === 0 && commands.length === 0) { +export function formatCombinedDescription(skills?: SkillInfo[], commands?: CommandInfo[]): string { + const availableSkills = skills ?? [] + const availableCommands = commands ?? [] + + if (availableSkills.length === 0 && availableCommands.length === 0) { return TOOL_DESCRIPTION_NO_SKILLS } const availableItems = [ - ...sortByScopePriority(skills).map(formatSkillCommand), - ...sortByScopePriority(commands).map(formatSlashCommand), + ...sortByScopePriority(availableSkills).map(formatSkillCommand), + ...sortByScopePriority(availableCommands).map(formatSlashCommand), ] if (availableItems.length === 0) { diff --git a/src/tools/skill/tools.ts b/src/tools/skill/tools.ts index 680fe638e..f60d06492 100644 --- a/src/tools/skill/tools.ts +++ b/src/tools/skill/tools.ts @@ -28,10 +28,10 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition let cachedDescription: string | null = null const getSkills = async (): Promise => { - const discovered = await getAllSkills({ + const discovered = (await getAllSkills({ disabledSkills: options?.disabledSkills, browserProvider: options?.browserProvider, - }) + })) ?? [] const allSkills = !options.skills ? discovered : [ @@ -56,7 +56,7 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition return discoverCommandsSync(undefined, { pluginsEnabled: options.pluginsEnabled, enabledPluginsOverride: options.enabledPluginsOverride, - }) + }) ?? [] } const buildDescription = async (force = false): Promise => { diff --git a/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts b/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts index 5dac1e7d9..32dd83bde 100644 --- a/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts +++ b/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts @@ -1,7 +1,14 @@ +/// + +declare const require: NodeJS.Require + import { afterAll, beforeEach, describe, expect, it, mock, spyOn } from "bun:test" import type { ToolContext } from "@opencode-ai/plugin/tool" import * as fs from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" import { SkillMcpManager } from "../../../features/skill-mcp-manager" +import { clearSkillCache } from "../../../features/opencode-skill-loader/skill-content" import type { LoadedSkill } from "../../../features/opencode-skill-loader/types" import type { CommandInfo } from "../../slashcommand/types" import type { Tool as McpTool } from "@modelcontextprotocol/sdk/types.js" @@ -10,7 +17,24 @@ const originalReadFileSync = fs.readFileSync.bind(fs) let createSkillTool: typeof import("../tools").createSkillTool -beforeEach(async () => { +function clearRequireCache(modulePath: string): void { + const resolvedPath = require.resolve(modulePath) + if (require.cache?.[resolvedPath]) { + delete require.cache[resolvedPath] + } +} + +function requireFresh(modulePath: string): TModule { + clearRequireCache(modulePath) + return require(modulePath) as TModule +} + +beforeEach(() => { + mock.restore() + clearRequireCache("../tools") + clearRequireCache("../../../features/opencode-skill-loader/skill-content") + clearRequireCache("../../slashcommand/command-discovery") + mock.module("node:fs", () => ({ ...fs, readFileSync: (path: string, encoding?: string) => { @@ -23,9 +47,8 @@ Test skill body content` return originalReadFileSync(path, encoding as BufferEncoding) }, })) - - const module = await import("../tools") - createSkillTool = module.createSkillTool + + createSkillTool = requireFresh("../tools").createSkillTool }) afterAll(() => { @@ -548,16 +571,43 @@ describe("skill tool - ordering and priority", () => { }) describe("skill tool - dynamic discovery", () => { - it("discovers skills from disk on every invocation instead of caching", async () => { - // given: tool created with initial skills - const initialSkills = [createMockSkill("initial-skill")] - const tool = createSkillTool({ skills: initialSkills }) + it("caches discovered skills across tool instances until the shared cache resets", async () => { + // given + clearSkillCache() + const originalDirectory = process.cwd() + const temporaryDirectory = fs.mkdtempSync(join(tmpdir(), "skill-tool-cache-")) + const initialSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "initial-skill") + const secondSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "second-skill") - // when: executing with the initial skill name - const result = await tool.execute({ name: "initial-skill" }, mockContext) + fs.mkdirSync(initialSkillDirectory, { recursive: true }) + fs.writeFileSync(join(initialSkillDirectory, "SKILL.md"), "---\ndescription: Initial skill\n---\nInitial skill body") + process.chdir(temporaryDirectory) - // then: initial skill found (merged from options.skills since not on disk) - expect(result).toContain("Skill: initial-skill") + try { + const firstTool = createSkillTool({}) + + // when + const initialResult = await firstTool.execute({ name: "initial-skill" }, mockContext) + + fs.mkdirSync(secondSkillDirectory, { recursive: true }) + fs.writeFileSync(join(secondSkillDirectory, "SKILL.md"), "---\ndescription: Second skill\n---\nSecond skill body") + + const cachedTool = createSkillTool({}) + + // then + expect(initialResult).toContain("Skill: initial-skill") + let cachedError: Error | undefined + try { + await cachedTool.execute({ name: "second-skill" }, mockContext) + } catch (error) { + cachedError = error instanceof Error ? error : new Error(String(error)) + } + expect(cachedError?.message).toContain('Skill or command "second-skill" not found.') + } finally { + process.chdir(originalDirectory) + clearSkillCache() + fs.rmSync(temporaryDirectory, { recursive: true, force: true }) + } }) it("merges pre-provided skills with dynamically discovered ones", async () => { @@ -586,59 +636,66 @@ describe("skill tool - dynamic discovery", () => { }) }) describe("skill tool - dynamic description cache invalidation", () => { - it("rebuilds description after execute() discovers new skills", async () => { - // given: tool created with initial skills (no pre-provided skills) - // This triggers lazy description building + it("keeps description available after execute misses a skill", async () => { + // given const tool = createSkillTool({}) - - // Get initial description - it will build from empty or disk skills + + // when const initialDescription = tool.description expect(initialDescription).toBeString() - - // when: execute() is called, which clears cache AND gets fresh skills - // Note: In real scenario, execute() would discover new skills from disk - // For testing, we verify the mechanism: execute() should invalidate cachedDescription - - // Execute any skill to trigger the cache clear + getSkills flow - // Using a non-existent skill name to trigger the error path which still goes through getSkills() + try { await tool.execute({ name: "nonexistent-skill-12345" }, mockContext) - } catch (e) { - // Expected to fail - skill doesn't exist + } catch { } - - // then: cachedDescription should be invalidated, so next description access should rebuild - // We verify by checking that the description getter triggers a rebuild - // Since we can't easily mock getAllSkills in this test, we verify the cache invalidation mechanism - - // The key assertion: after execute(), the description should be rebuildable - // If cachedDescription wasn't invalidated, it would still return old value - // We verify by checking that the tool still has valid description structure + + // then expect(tool.description).toBeDefined() expect(typeof tool.description).toBe("string") }) - it("description reflects fresh skills after execute() clears cache", async () => { - // given: tool created without pre-provided skills (will use disk discovery) - const tool = createSkillTool({}) - - // when: execute() is called with a skill that exists on disk (via mock) - // This simulates the real scenario: execute() discovers skills, cache should be invalidated - - // Execute to trigger the cache invalidation path + it("picks up new disk skills only after the shared skill cache resets", async () => { + // given + clearSkillCache() + const originalDirectory = process.cwd() + const temporaryDirectory = fs.mkdtempSync(join(tmpdir(), "skill-tool-refresh-")) + const initialSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "initial-skill") + const secondSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "second-skill") + + fs.mkdirSync(initialSkillDirectory, { recursive: true }) + fs.writeFileSync(join(initialSkillDirectory, "SKILL.md"), "---\ndescription: Initial skill\n---\nInitial skill body") + process.chdir(temporaryDirectory) + try { - // This will call getSkills() which clears cache - await tool.execute({ name: "nonexistent" }, mockContext) - } catch (e) { - // Expected + const initialTool = createSkillTool({}) + await initialTool.execute({ name: "initial-skill" }, mockContext) + + fs.mkdirSync(secondSkillDirectory, { recursive: true }) + fs.writeFileSync(join(secondSkillDirectory, "SKILL.md"), "---\ndescription: Second skill\n---\nSecond skill body") + + const cachedTool = createSkillTool({}) + let cachedError: Error | undefined + try { + await cachedTool.execute({ name: "second-skill" }, mockContext) + } catch (error) { + cachedError = error instanceof Error ? error : new Error(String(error)) + } + expect(cachedError?.message).toContain('Skill or command "second-skill" not found.') + + clearSkillCache() + const refreshedTool = createSkillTool({}) + + // when + const refreshedResult = await refreshedTool.execute({ name: "second-skill" }, mockContext) + + // then + expect(refreshedResult).toContain("Skill: second-skill") + expect(refreshedTool.description).toContain("second-skill") + } finally { + process.chdir(originalDirectory) + clearSkillCache() + fs.rmSync(temporaryDirectory, { recursive: true, force: true }) } - - // then: description should still work and not be stale - // The bug would cause it to return old cached value forever - const desc = tool.description - - // Verify description is a valid string (not stale/old) - expect(desc).toContain("skill") }) }) From e766354e22748c0e0b3e0daff778d861a4a1bf21 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 15:05:30 +0900 Subject: [PATCH 092/146] test(auto-update-checker): align zauc-mocks-hook with deferred idle check The zauc-mocks-hook variant previously asserted that session.created synchronously ran the startup checks. After auto-update-checker was refactored to defer work to the first session.idle via scheduleDeferredIdleCheck (5s timer), those assertions never fired. Mirror the mock+capture pattern from hook.test.ts so the test drives the deferred callback synchronously, preserving the original invariants (hasChecked guard, localDev toast, sisyphus wording) without waiting on real timers. --- src/hooks/zauc-mocks-hook/hook.test.ts | 43 +++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/hooks/zauc-mocks-hook/hook.test.ts b/src/hooks/zauc-mocks-hook/hook.test.ts index 2c291b1f0..9303b0ffb 100644 --- a/src/hooks/zauc-mocks-hook/hook.test.ts +++ b/src/hooks/zauc-mocks-hook/hook.test.ts @@ -1,5 +1,13 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" -import { createAutoUpdateCheckerHook } from "../auto-update-checker/hook" + +let scheduledDeferredCheck: (() => void) | null = null +mock.module("../auto-update-checker/hook/deferred-idle-check", () => ({ + scheduleDeferredIdleCheck: (runCheck: () => void) => { + scheduledDeferredCheck = runCheck + }, +})) + +const { createAutoUpdateCheckerHook } = await import("../auto-update-checker/hook") const mockShowConfigErrorsIfAny = mock(async () => {}) const mockShowModelCacheWarningIfNeeded = mock(async () => {}) @@ -38,6 +46,20 @@ function runSessionCreatedEvent( }) } +function runSessionIdleEvent(hook: ReturnType): void { + hook.event({ + event: { + type: "session.idle", + }, + }) +} + +function drainDeferredCheck(): void { + const run = scheduledDeferredCheck + scheduledDeferredCheck = null + run?.() +} + beforeEach(() => { mockShowConfigErrorsIfAny.mockClear() mockShowModelCacheWarningIfNeeded.mockClear() @@ -51,6 +73,8 @@ beforeEach(() => { mockGetCachedVersion.mockReturnValue("3.6.0") mockGetLocalDevVersion.mockReturnValue(null) + + scheduledDeferredCheck = null }) afterEach(() => { @@ -108,8 +132,10 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event arrives on primary session + //#when - session.created schedules work and session.idle drains it runSessionCreatedEvent(hook) + runSessionIdleEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - startup checks, toast, and background check run @@ -165,9 +191,12 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event is fired twice + //#when - session.created fires twice then session.idle fires twice runSessionCreatedEvent(hook) runSessionCreatedEvent(hook) + runSessionIdleEvent(hook) + runSessionIdleEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - side effects execute only once @@ -195,8 +224,10 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event arrives + //#when - session.created schedules and session.idle drains runSessionCreatedEvent(hook) + runSessionIdleEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - local dev toast is shown and background check is skipped @@ -259,8 +290,10 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event arrives + //#when - session.created schedules and session.idle drains runSessionCreatedEvent(hook) + runSessionIdleEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - startup toast includes sisyphus wording From bd1529825cf3ae1687188f950c45ecc0b2ede831 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 15:24:19 +0900 Subject: [PATCH 093/146] fix(test): isolate skill factory discovery in ci Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/skill/tools.factory.test.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tools/skill/tools.factory.test.ts b/src/tools/skill/tools.factory.test.ts index f266aa684..08942f040 100644 --- a/src/tools/skill/tools.factory.test.ts +++ b/src/tools/skill/tools.factory.test.ts @@ -5,7 +5,12 @@ import type { ToolContext } from "@opencode-ai/plugin/tool" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" import * as skillContent from "../../features/opencode-skill-loader/skill-content" import * as commandDiscovery from "../slashcommand/command-discovery" -import { createSkillTool } from "./tools" + +const discoverCommandsSync = mock(() => []) + +mock.module("../slashcommand/command-discovery", () => ({ + discoverCommandsSync, +})) function createMockSkill(name: string): LoadedSkill { return { @@ -25,7 +30,6 @@ async function flushMicrotasks(): Promise { } const loadedSkill = createMockSkill("lazy-skill") -const discoverCommandsSync = mock(() => []) const getAllSkills = mock(async () => [loadedSkill]) const clearSkillCache = mock(() => {}) const mockContext: ToolContext = { @@ -40,8 +44,6 @@ const mockContext: ToolContext = { } beforeEach(() => { - mock.restore() - spyOn(commandDiscovery, "discoverCommandsSync").mockImplementation(discoverCommandsSync) spyOn(skillContent, "getAllSkills").mockImplementation(getAllSkills) spyOn(skillContent, "clearSkillCache").mockImplementation(clearSkillCache) }) @@ -57,6 +59,7 @@ describe("createSkillTool", () => { const baselineDiscoverCommandsSyncCalls = discoverCommandsSync.mock.calls.length // when + const { createSkillTool } = await import("./tools") const skillTool = createSkillTool({}) // then @@ -73,6 +76,7 @@ describe("createSkillTool", () => { const baselineGetAllSkillsCalls = getAllSkills.mock.calls.length // when + const { createSkillTool } = await import("./tools") const skillTool = createSkillTool({}) // then @@ -88,6 +92,7 @@ describe("createSkillTool", () => { const baselineClearSkillCacheCalls = clearSkillCache.mock.calls.length // when + const { createSkillTool } = await import("./tools") const skillTool = createSkillTool({}) void skillTool.description await flushMicrotasks() From 1d187097f376c57dc9877c93f1be7dbfb17d31fe Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 17:17:23 +0900 Subject: [PATCH 094/146] test(tools/skill): cover per-session skill cache invalidation --- src/tools/skill/tools.factory.test.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/tools/skill/tools.factory.test.ts b/src/tools/skill/tools.factory.test.ts index 08942f040..e52f0abb5 100644 --- a/src/tools/skill/tools.factory.test.ts +++ b/src/tools/skill/tools.factory.test.ts @@ -43,6 +43,13 @@ const mockContext: ToolContext = { ask: async () => {}, } +function createMockContext(sessionID: string): ToolContext { + return { + ...mockContext, + sessionID, + } +} + beforeEach(() => { spyOn(skillContent, "getAllSkills").mockImplementation(getAllSkills) spyOn(skillContent, "clearSkillCache").mockImplementation(clearSkillCache) @@ -101,4 +108,24 @@ describe("createSkillTool", () => { // then expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls) }) + + it("clears the skill discovery cache once per session", async () => { + // given + const baselineClearSkillCacheCalls = clearSkillCache.mock.calls.length + const baselineGetAllSkillsCalls = getAllSkills.mock.calls.length + const sessionAContext = createMockContext("session-a") + const sessionBContext = createMockContext("session-b") + const { createSkillTool } = await import("./tools") + const skillTool = createSkillTool({}) + + // when + await skillTool.execute({ name: "lazy-skill" }, sessionAContext) + await skillTool.execute({ name: "lazy-skill" }, sessionAContext) + await skillTool.execute({ name: "lazy-skill" }, sessionBContext) + await skillTool.execute({ name: "lazy-skill" }, sessionBContext) + + // then + expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls + 2) + expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls + 4) + }) }) From a8504be70c3896417c1af8e82b930a84e6318a25 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 17:19:18 +0900 Subject: [PATCH 095/146] test(auto-update-checker): cover session.created trigger with parentID guard --- src/hooks/auto-update-checker/hook.test.ts | 86 +++++++++++++++------- src/hooks/zauc-mocks-hook/hook.test.ts | 21 +----- 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/hooks/auto-update-checker/hook.test.ts b/src/hooks/auto-update-checker/hook.test.ts index 4a8096bb9..4dba87298 100644 --- a/src/hooks/auto-update-checker/hook.test.ts +++ b/src/hooks/auto-update-checker/hook.test.ts @@ -109,53 +109,82 @@ const resetDeferredState = (): void => { scheduledCheck = null } -const triggerDeferredIdleCheck = async ( - hook: ReturnType, -): Promise => { - hook.event({ event: { type: "session.idle" } }) +const runScheduledCheck = async (): Promise => { scheduledCheck?.() await flushMicrotasks(8) } +const triggerSessionCreated = ( + hook: ReturnType, + properties?: { info?: { parentID?: string } }, +): void => { + hook.event({ event: { type: "session.created", properties } }) +} + +const triggerSessionIdle = (hook: ReturnType): void => { + hook.event({ event: { type: "session.idle" } }) +} + describe("auto-update-checker hook", () => { - test("defers update check until first session idle", async () => { + test("schedules deferred check on session.created without parentID", async () => { // given resetDeferredState() const { hook, mocks } = await createHook() // when - hook.event({ event: { type: "session.created" } }) + triggerSessionCreated(hook) // then - expect(scheduleDeferredIdleCheckCallCount).toBe(0) + expect(scheduleDeferredIdleCheckCallCount).toBe(1) expect(mocks.showVersionToast).not.toHaveBeenCalled() expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() expect(latestVersionCallCount).toBe(0) // when - await triggerDeferredIdleCheck(hook) + await runScheduledCheck() // then - expect(scheduleDeferredIdleCheckCallCount).toBe(1) expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) expect(latestVersionCallCount).toBe(1) - - // when - hook.event({ event: { type: "session.idle" } }) - - // then - expect(scheduleDeferredIdleCheckCallCount).toBe(1) - expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) }) - test("runs all startup checks on normal session.idle", async () => { + test("does not schedule deferred check on session.created with parentID", async () => { // given resetDeferredState() const { hook, mocks } = await createHook() // when - await triggerDeferredIdleCheck(hook) + triggerSessionCreated(hook, { info: { parentID: "parent-123" } }) + + // then + expect(scheduleDeferredIdleCheckCallCount).toBe(0) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() + }) + + test("does not schedule deferred check on session.idle without session.created", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + triggerSessionIdle(hook) + + // then + expect(scheduleDeferredIdleCheckCallCount).toBe(0) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() + }) + + test("runs all startup checks after deferred session.created check executes", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + triggerSessionCreated(hook) + await runScheduledCheck() // then expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) @@ -166,16 +195,21 @@ describe("auto-update-checker hook", () => { expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) }) - test("runs only once (hasChecked guard)", async () => { + test("guards double execution across repeated session.created events", async () => { // given resetDeferredState() const { hook, mocks } = await createHook() // when - hook.event({ event: { type: "session.idle" } }) - hook.event({ event: { type: "session.idle" } }) - scheduledCheck?.() - await flushMicrotasks(8) + triggerSessionCreated(hook) + triggerSessionCreated(hook) + + // then + expect(scheduleDeferredIdleCheckCallCount).toBe(1) + + // when + await runScheduledCheck() + triggerSessionCreated(hook) // then expect(scheduleDeferredIdleCheckCallCount).toBe(1) @@ -194,7 +228,8 @@ describe("auto-update-checker hook", () => { }) // when - await triggerDeferredIdleCheck(hook) + triggerSessionCreated(hook) + await runScheduledCheck() // then expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) @@ -212,7 +247,8 @@ describe("auto-update-checker hook", () => { const { hook, mocks } = await createHook({ isSisyphusEnabled: true }) // when - await triggerDeferredIdleCheck(hook) + triggerSessionCreated(hook) + await runScheduledCheck() // then expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) diff --git a/src/hooks/zauc-mocks-hook/hook.test.ts b/src/hooks/zauc-mocks-hook/hook.test.ts index 9303b0ffb..ce1e3e3d3 100644 --- a/src/hooks/zauc-mocks-hook/hook.test.ts +++ b/src/hooks/zauc-mocks-hook/hook.test.ts @@ -46,14 +46,6 @@ function runSessionCreatedEvent( }) } -function runSessionIdleEvent(hook: ReturnType): void { - hook.event({ - event: { - type: "session.idle", - }, - }) -} - function drainDeferredCheck(): void { const run = scheduledDeferredCheck scheduledDeferredCheck = null @@ -132,9 +124,8 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created schedules work and session.idle drains it + //#when - session.created schedules work and deferred check drains it runSessionCreatedEvent(hook) - runSessionIdleEvent(hook) drainDeferredCheck() await flushScheduledWork() @@ -191,11 +182,9 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created fires twice then session.idle fires twice + //#when - session.created fires twice and deferred check drains once runSessionCreatedEvent(hook) runSessionCreatedEvent(hook) - runSessionIdleEvent(hook) - runSessionIdleEvent(hook) drainDeferredCheck() await flushScheduledWork() @@ -224,9 +213,8 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created schedules and session.idle drains + //#when - session.created schedules and deferred check drains runSessionCreatedEvent(hook) - runSessionIdleEvent(hook) drainDeferredCheck() await flushScheduledWork() @@ -290,9 +278,8 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created schedules and session.idle drains + //#when - session.created schedules and deferred check drains runSessionCreatedEvent(hook) - runSessionIdleEvent(hook) drainDeferredCheck() await flushScheduledWork() From a6a5a08b563ff5dd85284ca1273aadaccc23d517 Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 17:21:09 +0900 Subject: [PATCH 096/146] fix(tools/skill): invalidate skill cache at session boundary --- src/tools/skill/session-skill-cache.ts | 10 ++++++++++ src/tools/skill/tools.factory.test.ts | 9 +++++---- src/tools/skill/tools.ts | 11 ++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 src/tools/skill/session-skill-cache.ts diff --git a/src/tools/skill/session-skill-cache.ts b/src/tools/skill/session-skill-cache.ts new file mode 100644 index 000000000..040979ddb --- /dev/null +++ b/src/tools/skill/session-skill-cache.ts @@ -0,0 +1,10 @@ +const seenSessionIDs = new Set() + +export function shouldInvalidateSkillCacheForSession(sessionID?: string): boolean { + if (!sessionID || seenSessionIDs.has(sessionID)) { + return false + } + + seenSessionIDs.add(sessionID) + return true +} diff --git a/src/tools/skill/tools.factory.test.ts b/src/tools/skill/tools.factory.test.ts index e52f0abb5..5b9a5ba30 100644 --- a/src/tools/skill/tools.factory.test.ts +++ b/src/tools/skill/tools.factory.test.ts @@ -4,7 +4,6 @@ import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:te import type { ToolContext } from "@opencode-ai/plugin/tool" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" import * as skillContent from "../../features/opencode-skill-loader/skill-content" -import * as commandDiscovery from "../slashcommand/command-discovery" const discoverCommandsSync = mock(() => []) @@ -94,19 +93,21 @@ describe("createSkillTool", () => { expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls + 1) }) - it("does not clear the shared skill cache during description or execute refresh", async () => { + it("clears the shared skill cache once on first execute in a session", async () => { // given const baselineClearSkillCacheCalls = clearSkillCache.mock.calls.length + const sessionContext = createMockContext("session-clear-once") // when const { createSkillTool } = await import("./tools") const skillTool = createSkillTool({}) void skillTool.description await flushMicrotasks() - await skillTool.execute({ name: "lazy-skill" }, mockContext) + await skillTool.execute({ name: "lazy-skill" }, sessionContext) + await skillTool.execute({ name: "lazy-skill" }, sessionContext) // then - expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls) + expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls + 1) }) it("clears the skill discovery cache once per session", async () => { diff --git a/src/tools/skill/tools.ts b/src/tools/skill/tools.ts index f60d06492..d49936f95 100644 --- a/src/tools/skill/tools.ts +++ b/src/tools/skill/tools.ts @@ -2,9 +2,10 @@ import { dirname } from "node:path" import { tool, type ToolDefinition } from "@opencode-ai/plugin" import type { ToolContext } from "@opencode-ai/plugin/tool" import { TOOL_DESCRIPTION_PREFIX } from "./constants" +import { shouldInvalidateSkillCacheForSession } from "./session-skill-cache" import type { SkillArgs, SkillLoadOptions } from "./types" import type { LoadedSkill } from "../../features/opencode-skill-loader" -import { getAllSkills } from "../../features/opencode-skill-loader/skill-content" +import { clearSkillCache, getAllSkills } from "../../features/opencode-skill-loader/skill-content" import { injectGitMasterConfig } from "../../features/opencode-skill-loader/skill-content" import { discoverCommandsSync } from "../slashcommand/command-discovery" import type { CommandInfo } from "../slashcommand/types" @@ -27,7 +28,11 @@ import { export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition { let cachedDescription: string | null = null - const getSkills = async (): Promise => { + const getSkills = async (context?: ToolContext): Promise => { + if (shouldInvalidateSkillCacheForSession(context?.sessionID)) { + clearSkillCache() + } + const discovered = (await getAllSkills({ disabledSkills: options?.disabledSkills, browserProvider: options?.browserProvider, @@ -108,7 +113,7 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition .describe("Optional arguments or context for command invocation. Example: name='publish', user_message='patch'"), }, async execute(args: SkillArgs, ctx?: ToolContext) { - const skills = await getSkills() + const skills = await getSkills(ctx) const commands = getCommands() cachedDescription = formatCombinedDescription(skills.map(loadedSkillToInfo), commands) From c9c1c58c2cb96cf85ec86f4bf1b5af7dd8e2c7e7 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 17:22:01 +0900 Subject: [PATCH 097/146] fix(tmux-subagent): track pane without blocking on session readiness waitForSessionReady polled session.status for up to 10s before the pane was registered, but session.status only becomes visible after promptAsync starts. Blocking pane tracking on that signal caused the attach client to see an empty session and render a blank TUI. Track the pane immediately after spawn, and run the readiness probe in the background purely for observability. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/features/tmux-subagent/manager.test.ts | 21 +++++++++++ src/features/tmux-subagent/manager.ts | 44 +++++++++------------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 8c47097f4..c8cf2c1d2 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -1056,6 +1056,27 @@ describe('TmuxSessionManager', () => { logSpy.mockRestore() }) }) + + test('#given session.status never reports session ready #when onSessionCreated runs #then pane is tracked immediately without blocking', async () => { + // given + mockIsInsideTmux.mockReturnValue(true) + mockQueryWindowState.mockImplementation(async () => createWindowState()) + + const { TmuxSessionManager } = await import('./manager') + const ctx = createMockContext({ sessionStatusResult: { data: {} } }) + const config = createTmuxConfig({ enabled: true }) + const manager = new TmuxSessionManager(ctx, config, mockTmuxDeps) + const event = createSessionCreatedEvent('ses_fast_track', 'ses_parent', 'Fast Track') + + // when + const start = Date.now() + await manager.onSessionCreated(event) + const elapsed = Date.now() - start + + // then + expect(elapsed < 500).toBe(true) + expect(getTrackedSessions(manager).has('ses_fast_track')).toBe(true) + }) }) describe('onSessionDeleted', () => { diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index a31f668bf..e379bce96 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -511,7 +511,6 @@ export class TmuxSessionManager { if (deferred.retryIsolatedContainer) { const isolatedPaneId = await this.spawnInIsolatedContainer(sessionId, deferred.title) if (isolatedPaneId) { - const sessionReady = await this.waitForSessionReady(sessionId) this.sessions.set( sessionId, createTrackedSession({ @@ -525,8 +524,8 @@ export class TmuxSessionManager { log("[tmux-session-manager] deferred session attached in isolated window", { sessionId, paneId: isolatedPaneId, - sessionReady, }) + this.logSessionReadinessInBackground(sessionId) return } } @@ -585,14 +584,6 @@ export class TmuxSessionManager { return } - const sessionReady = await this.waitForSessionReady(sessionId) - if (!sessionReady) { - log("[tmux-session-manager] deferred session not ready after timeout", { - sessionId, - paneId: result.spawnedPaneId, - }) - } - this.sessions.set( sessionId, createTrackedSession({ @@ -606,18 +597,27 @@ export class TmuxSessionManager { log("[tmux-session-manager] deferred session attached", { sessionId, paneId: result.spawnedPaneId, - sessionReady, + }) + this.logSessionReadinessInBackground(sessionId) + } + + private logSessionReadinessInBackground(sessionId: string): void { + void this.waitForSessionReady(sessionId).catch((error) => { + log("[tmux-session-manager] background readiness probe failed", { + sessionId, + error: String(error), + }) }) } private async waitForSessionReady(sessionId: string): Promise { const startTime = Date.now() - + while (Date.now() - startTime < SESSION_READY_TIMEOUT_MS) { try { const statusResult = await this.client.session.status({ path: undefined }) const allStatuses = normalizeSDKResponse(statusResult, {} as Record) - + if (allStatuses[sessionId]) { log("[tmux-session-manager] session ready", { sessionId, @@ -629,10 +629,10 @@ export class TmuxSessionManager { } catch (err) { log("[tmux-session-manager] session status check error", { error: String(err) }) } - + await new Promise((resolve) => setTimeout(resolve, SESSION_READY_POLL_INTERVAL_MS)) } - + log("[tmux-session-manager] session ready timeout", { sessionId, timeoutMs: SESSION_READY_TIMEOUT_MS, @@ -682,7 +682,6 @@ export class TmuxSessionManager { try { const isolatedPaneId = await this.spawnInIsolatedContainer(sessionId, title) if (isolatedPaneId) { - const sessionReady = await this.waitForSessionReady(sessionId) this.sessions.set( sessionId, createTrackedSession({ sessionId, paneId: isolatedPaneId, description: title }), @@ -691,8 +690,8 @@ export class TmuxSessionManager { log("[tmux-session-manager] first subagent spawned in isolated window", { sessionId, paneId: isolatedPaneId, - sessionReady, }) + this.logSessionReadinessInBackground(sessionId) return } @@ -773,15 +772,6 @@ export class TmuxSessionManager { } if (result.success && result.spawnedPaneId) { - const sessionReady = await this.waitForSessionReady(sessionId) - - if (!sessionReady) { - log("[tmux-session-manager] session not ready after timeout, tracking anyway", { - sessionId, - paneId: result.spawnedPaneId, - }) - } - this.sessions.set( sessionId, createTrackedSession({ @@ -793,9 +783,9 @@ export class TmuxSessionManager { log("[tmux-session-manager] pane spawned and tracked", { sessionId, paneId: result.spawnedPaneId, - sessionReady, }) this.pollingManager.startPolling() + this.logSessionReadinessInBackground(sessionId) } else { log("[tmux-session-manager] spawn failed", { success: result.success, From 91848057ea1f32c6a6bd8520bd7b2b836f1baa4f Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 17:22:11 +0900 Subject: [PATCH 098/146] fix(background-agent): fire promptAsync before tmux callback Awaiting the tmux callback blocked the prompt for up to 10s (waitForSessionReady downstream). During that window the spawned pane ran 'opencode attach' against an empty session and rendered a blank TUI. Users saw 'pane created but attach not working'. Start promptWithModelSuggestionRetry immediately after session.create, then invoke the tmux callback as fire-and-forget. The session becomes active before the attach client connects. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/features/background-agent/spawner.test.ts | 81 +++++++++++++++++++ src/features/background-agent/spawner.ts | 50 ++++++------ 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/features/background-agent/spawner.test.ts b/src/features/background-agent/spawner.test.ts index b1f486c52..eb2cc294b 100644 --- a/src/features/background-agent/spawner.test.ts +++ b/src/features/background-agent/spawner.test.ts @@ -577,3 +577,84 @@ describe("background-agent spawner fallback model promotion", () => { expect(promptCalls[0]?.body?.agent).toBe("sisyphus-junior") }) }) + +describe("background-agent spawner tmux callback ordering", () => { + test("fires promptAsync before tmux callback resolves (no blocking)", async () => { + //#given + const events: string[] = [] + let resolveTmuxCallback: () => void = () => {} + const tmuxCallbackPromise = new Promise((resolve) => { + resolveTmuxCallback = resolve + }) + + const client = { + session: { + get: async () => ({ data: { directory: "/tmp/test" } }), + create: async () => { + events.push("session.create") + return { data: { id: "ses_blocking_tmux" } } + }, + promptAsync: async () => { + events.push("promptAsync") + return { data: {} } + }, + }, + } as any + + const onSubagentSessionCreated = mock(async () => { + events.push("tmux.callback.start") + await tmuxCallbackPromise + events.push("tmux.callback.end") + }) + + const task = createTask({ + description: "Blocking tmux test", + prompt: "Do work", + agent: "general", + parentSessionID: "ses_parent", + parentMessageID: "msg_parent", + }) + + const item = { + task, + input: { + description: task.description, + prompt: task.prompt, + agent: task.agent, + parentSessionID: task.parentSessionID, + parentMessageID: task.parentMessageID, + }, + } + + const ctx = { + client, + directory: "/tmp/test", + concurrencyManager: { release: () => {} }, + tmuxEnabled: true, + onSubagentSessionCreated, + onTaskError: () => {}, + } + + const originalTmux = process.env.TMUX + process.env.TMUX = "/tmp/fake-tmux-socket" + + try { + //#when + await startTask(item as any, ctx as any) + await new Promise((resolve) => setTimeout(resolve, 20)) + + //#then + expect(events).toContain("session.create") + expect(events).toContain("promptAsync") + expect(events).toContain("tmux.callback.start") + const promptIdx = events.indexOf("promptAsync") + const tmuxStartIdx = events.indexOf("tmux.callback.start") + expect(promptIdx < tmuxStartIdx).toBe(true) + expect(events).not.toContain("tmux.callback.end") + } finally { + resolveTmuxCallback() + if (originalTmux === undefined) delete process.env.TMUX + else process.env.TMUX = originalTmux + } + }) +}) diff --git a/src/features/background-agent/spawner.ts b/src/features/background-agent/spawner.ts index 675aeb5d9..ab6aaa2f1 100644 --- a/src/features/background-agent/spawner.ts +++ b/src/features/background-agent/spawner.ts @@ -1,6 +1,5 @@ import type { BackgroundTask, LaunchInput, ResumeInput } from "./types" import type { OpencodeClient, OnSubagentSessionCreated, QueueItem } from "./constants" -import { TMUX_CALLBACK_DELAY_MS } from "./constants" import { log, getAgentToolRestrictions, promptWithModelSuggestionRetry, createInternalAgentTextPart } from "../../shared" import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers" import { subagentSessions } from "../claude-code-session-state" @@ -115,29 +114,6 @@ export async function startTask( const sessionID = createResult.data.id subagentSessions.add(sessionID) - log("[background-agent] tmux callback check", { - hasCallback: !!onSubagentSessionCreated, - tmuxEnabled, - isInsideTmux: isInsideTmux(), - sessionID, - parentID: input.parentSessionID, - }) - - if (onSubagentSessionCreated && tmuxEnabled && isInsideTmux()) { - log("[background-agent] Invoking tmux callback NOW", { sessionID }) - await onSubagentSessionCreated({ - sessionID, - parentID: input.parentSessionID, - title: input.description, - }).catch((err) => { - log("[background-agent] Failed to spawn tmux pane:", err) - }) - log("[background-agent] tmux callback completed, waiting") - await new Promise(r => setTimeout(r, TMUX_CALLBACK_DELAY_MS)) - } else { - log("[background-agent] SKIP tmux callback - conditions not met") - } - task.status = "running" task.startedAt = new Date() task.sessionID = sessionID @@ -188,7 +164,8 @@ export async function startTask( parts: [createInternalAgentTextPart(input.prompt)], } - promptWithModelSuggestionRetry(client, { + // Must fire BEFORE tmux callback: attach client needs session activity to render TUI. + const promptChain = promptWithModelSuggestionRetry(client, { path: { id: sessionID }, body: promptBody, }).catch(async (error) => { @@ -214,6 +191,29 @@ export async function startTask( log("[background-agent] promptAsync error:", error) onTaskError(task, error instanceof Error ? error : new Error(String(error))) }) + + void promptChain + + log("[background-agent] tmux callback check", { + hasCallback: !!onSubagentSessionCreated, + tmuxEnabled, + isInsideTmux: isInsideTmux(), + sessionID, + parentID: input.parentSessionID, + }) + + if (onSubagentSessionCreated && tmuxEnabled && isInsideTmux()) { + log("[background-agent] Invoking tmux callback (fire-and-forget)", { sessionID }) + void onSubagentSessionCreated({ + sessionID, + parentID: input.parentSessionID, + title: input.description, + }).catch((err) => { + log("[background-agent] Failed to spawn tmux pane:", err) + }) + } else { + log("[background-agent] SKIP tmux callback - conditions not met") + } } export async function resumeTask( From 0a808de6a25afd59222a695fcbc1fa6d03c3571b Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 17:23:50 +0900 Subject: [PATCH 099/146] fix(auto-update-checker): trigger deferred startup on session.created with parentID guard --- src/hooks/auto-update-checker/hook.test.ts | 22 +++++++++---------- src/hooks/auto-update-checker/hook.ts | 21 +++++++++++++++--- .../hook/deferred-idle-check.ts | 4 ---- .../hook/deferred-startup-check.ts | 4 ++++ src/hooks/zauc-mocks-hook/hook.test.ts | 4 ++-- 5 files changed, 35 insertions(+), 20 deletions(-) delete mode 100644 src/hooks/auto-update-checker/hook/deferred-idle-check.ts create mode 100644 src/hooks/auto-update-checker/hook/deferred-startup-check.ts diff --git a/src/hooks/auto-update-checker/hook.test.ts b/src/hooks/auto-update-checker/hook.test.ts index 4dba87298..a6cacd54d 100644 --- a/src/hooks/auto-update-checker/hook.test.ts +++ b/src/hooks/auto-update-checker/hook.test.ts @@ -6,7 +6,7 @@ type HookOptions = Parameters[1] type HookDeps = NonNullable[2]> let latestVersionCallCount = 0 -let scheduleDeferredIdleCheckCallCount = 0 +let scheduleDeferredStartupCheckCallCount = 0 const flushMicrotasks = async (count: number): Promise => { for (let index = 0; index < count; index += 1) { @@ -19,8 +19,8 @@ const latestVersionMock = async () => { return "3.0.1" } -const scheduleDeferredIdleCheckMock = (runCheck: () => void) => { - scheduleDeferredIdleCheckCallCount += 1 +const scheduleDeferredStartupCheckMock = (runCheck: () => void) => { + scheduleDeferredStartupCheckCallCount += 1 scheduledCheck = runCheck } @@ -30,8 +30,8 @@ mock.module("./checker/latest-version", () => ({ getLatestVersion: latestVersionMock, })) -mock.module("./hook/deferred-idle-check", () => ({ - scheduleDeferredIdleCheck: scheduleDeferredIdleCheckMock, +mock.module("./hook/deferred-startup-check", () => ({ + scheduleDeferredStartupCheck: scheduleDeferredStartupCheckMock, })) const createPluginInput = (): PluginInput => ({ @@ -105,7 +105,7 @@ const createHook = async ( const resetDeferredState = (): void => { latestVersionCallCount = 0 - scheduleDeferredIdleCheckCallCount = 0 + scheduleDeferredStartupCheckCallCount = 0 scheduledCheck = null } @@ -135,7 +135,7 @@ describe("auto-update-checker hook", () => { triggerSessionCreated(hook) // then - expect(scheduleDeferredIdleCheckCallCount).toBe(1) + expect(scheduleDeferredStartupCheckCallCount).toBe(1) expect(mocks.showVersionToast).not.toHaveBeenCalled() expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() expect(latestVersionCallCount).toBe(0) @@ -158,7 +158,7 @@ describe("auto-update-checker hook", () => { triggerSessionCreated(hook, { info: { parentID: "parent-123" } }) // then - expect(scheduleDeferredIdleCheckCallCount).toBe(0) + expect(scheduleDeferredStartupCheckCallCount).toBe(0) expect(mocks.showVersionToast).not.toHaveBeenCalled() expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() }) @@ -172,7 +172,7 @@ describe("auto-update-checker hook", () => { triggerSessionIdle(hook) // then - expect(scheduleDeferredIdleCheckCallCount).toBe(0) + expect(scheduleDeferredStartupCheckCallCount).toBe(0) expect(mocks.showVersionToast).not.toHaveBeenCalled() expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() }) @@ -205,14 +205,14 @@ describe("auto-update-checker hook", () => { triggerSessionCreated(hook) // then - expect(scheduleDeferredIdleCheckCallCount).toBe(1) + expect(scheduleDeferredStartupCheckCallCount).toBe(1) // when await runScheduledCheck() triggerSessionCreated(hook) // then - expect(scheduleDeferredIdleCheckCallCount).toBe(1) + expect(scheduleDeferredStartupCheckCallCount).toBe(1) expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) expect(mocks.updateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) expect(mocks.showModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) diff --git a/src/hooks/auto-update-checker/hook.ts b/src/hooks/auto-update-checker/hook.ts index 73f5eed4b..2306c03a0 100644 --- a/src/hooks/auto-update-checker/hook.ts +++ b/src/hooks/auto-update-checker/hook.ts @@ -3,7 +3,7 @@ import { log } from "../../shared/logger" import type { AutoUpdateCheckerOptions } from "./types" import { getCachedVersion, getLocalDevVersion } from "./checker" import { runBackgroundUpdateCheck } from "./hook/background-update-check" -import { scheduleDeferredIdleCheck } from "./hook/deferred-idle-check" +import { scheduleDeferredStartupCheck } from "./hook/deferred-startup-check" import { showConfigErrorsIfAny } from "./hook/config-errors-toast" import { updateAndShowConnectedProvidersCacheStatus } from "./hook/connected-providers-status" import { refreshModelCapabilitiesOnStartup } from "./hook/model-capabilities-status" @@ -36,6 +36,20 @@ const defaultDeps: AutoUpdateCheckerDeps = { log, } +const isRecord = (value: unknown): value is Record => { + return typeof value === "object" && value !== null +} + +const getParentID = (properties: unknown): string | undefined => { + if (!isRecord(properties)) return undefined + + const { info } = properties + if (!isRecord(info)) return undefined + + const { parentID } = info + return typeof parentID === "string" && parentID.length > 0 ? parentID : undefined +} + export function createAutoUpdateCheckerHook( ctx: PluginInput, options: AutoUpdateCheckerOptions = {}, @@ -65,13 +79,14 @@ export function createAutoUpdateCheckerHook( return { event: ({ event }: { event: { type: string; properties?: unknown } }) => { - if (event.type !== "session.idle") return + if (event.type !== "session.created") return if (isCliRunMode) return if (hasChecked || hasScheduled) return + if (getParentID(event.properties)) return hasScheduled = true - scheduleDeferredIdleCheck(() => { + scheduleDeferredStartupCheck(() => { hasChecked = true void (async () => { const cachedVersion = deps.getCachedVersion() diff --git a/src/hooks/auto-update-checker/hook/deferred-idle-check.ts b/src/hooks/auto-update-checker/hook/deferred-idle-check.ts deleted file mode 100644 index a929cf4ee..000000000 --- a/src/hooks/auto-update-checker/hook/deferred-idle-check.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function scheduleDeferredIdleCheck(runCheck: () => void): void { - const timeout = setTimeout(runCheck, 5000) - timeout.unref?.() -} diff --git a/src/hooks/auto-update-checker/hook/deferred-startup-check.ts b/src/hooks/auto-update-checker/hook/deferred-startup-check.ts new file mode 100644 index 000000000..2e1066424 --- /dev/null +++ b/src/hooks/auto-update-checker/hook/deferred-startup-check.ts @@ -0,0 +1,4 @@ +export function scheduleDeferredStartupCheck(runCheck: () => void): void { + const timeout = setTimeout(runCheck, 5000) + timeout.unref?.() +} diff --git a/src/hooks/zauc-mocks-hook/hook.test.ts b/src/hooks/zauc-mocks-hook/hook.test.ts index ce1e3e3d3..de0e4d3d2 100644 --- a/src/hooks/zauc-mocks-hook/hook.test.ts +++ b/src/hooks/zauc-mocks-hook/hook.test.ts @@ -1,8 +1,8 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" let scheduledDeferredCheck: (() => void) | null = null -mock.module("../auto-update-checker/hook/deferred-idle-check", () => ({ - scheduleDeferredIdleCheck: (runCheck: () => void) => { +mock.module("../auto-update-checker/hook/deferred-startup-check", () => ({ + scheduleDeferredStartupCheck: (runCheck: () => void) => { scheduledDeferredCheck = runCheck }, })) From e303feefd290220b59641216f15a24aae99abb61 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 18:33:58 +0900 Subject: [PATCH 100/146] feat(team-mode): add team-layout-tmux for focus+grid pane visualization Introduce a dedicated module that builds the two-window tmux layout team-mode relies on: - "focus" window uses main-vertical for the lead-centric view - "grid" window uses tiled so every member pane is visible at once createTeamLayout spawns omo-team-, registers pane titles with color-coded labels, and returns the focus/grid window IDs plus a pane-by-member map. removeTeamLayout tears the session down idempotently. canVisualize short-circuits when TMUX is unset so callers degrade gracefully outside a tmux context. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../team-mode/team-layout-tmux/index.ts | 1 + .../team-mode/team-layout-tmux/layout.test.ts | 78 ++++++++++++ .../team-mode/team-layout-tmux/layout.ts | 120 ++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 src/features/team-mode/team-layout-tmux/index.ts create mode 100644 src/features/team-mode/team-layout-tmux/layout.test.ts create mode 100644 src/features/team-mode/team-layout-tmux/layout.ts diff --git a/src/features/team-mode/team-layout-tmux/index.ts b/src/features/team-mode/team-layout-tmux/index.ts new file mode 100644 index 000000000..8858d5a4b --- /dev/null +++ b/src/features/team-mode/team-layout-tmux/index.ts @@ -0,0 +1 @@ +export { canVisualize, createTeamLayout, removeTeamLayout } from "./layout" diff --git a/src/features/team-mode/team-layout-tmux/layout.test.ts b/src/features/team-mode/team-layout-tmux/layout.test.ts new file mode 100644 index 000000000..c23f878f4 --- /dev/null +++ b/src/features/team-mode/team-layout-tmux/layout.test.ts @@ -0,0 +1,78 @@ +import { beforeEach, describe, expect, mock, test } from "bun:test" + +const spawnMock = mock(() => ({ + exited: Promise.resolve(0), + stdout: new ReadableStream({ start(controller) { controller.enqueue(new TextEncoder().encode("%1\n")); controller.close() } }), + stderr: new ReadableStream({ start(controller) { controller.close() } }), +})) + +mock.module("bun", () => ({ spawn: spawnMock })) + +mock.module("../../../tools/interactive-bash/tmux-path-resolver", () => ({ getTmuxPath: mock(() => Promise.resolve("tmux")) })) + +mock.module("../../../shared", () => ({ log: mock(() => undefined) })) + +import { createTeamLayout, removeTeamLayout, canVisualize } from "./layout" + +describe("team-layout-tmux", () => { + beforeEach(() => { + spawnMock.mockClear() + process.env.TMUX = "/tmp/tmux-1" + }) + + test("returns null and makes no tmux calls when visualization unavailable", async () => { + // given + delete process.env.TMUX + + // when + const result = await createTeamLayout("run-1", [], {} as never) + + // then + expect(canVisualize()).toBe(false) + expect(result).toBeNull() + expect(spawnMock).toHaveBeenCalledTimes(0) + }) + + test("creates focus and grid windows", async () => { + // given + const members = [ + { name: "lead", sessionId: "s1", color: "red" }, + { name: "m2", sessionId: "s2" }, + { name: "m3", sessionId: "s3" }, + ] + + // when + await createTeamLayout("run-2", members, {} as never) + + // then + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("new-session") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("new-window") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("split-window") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("select-layout") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("select-pane") + }) + + test("returns null when tmux command fails", async () => { + // given + spawnMock.mockImplementationOnce(() => ({ + exited: Promise.resolve(1), + stdout: new ReadableStream({ start(controller) { controller.close() } }), + stderr: new ReadableStream({ start(controller) { controller.close() } }), + })) + + // when + const result = await createTeamLayout("run-3", [{ name: "lead", sessionId: "s1" }], {} as never) + + // then + expect(result).toBeNull() + }) + + test("cleans up the tmux session", async () => { + // given + // when + await removeTeamLayout("run-4", {} as never) + + // then + expect(spawnMock.mock.calls.some((call) => (call[0] as Array).includes("kill-session"))).toBe(true) + }) +}) diff --git a/src/features/team-mode/team-layout-tmux/layout.ts b/src/features/team-mode/team-layout-tmux/layout.ts new file mode 100644 index 000000000..b41354d06 --- /dev/null +++ b/src/features/team-mode/team-layout-tmux/layout.ts @@ -0,0 +1,120 @@ +import { spawn } from "bun" +import { log } from "../../../shared" +import { getTmuxPath } from "../../../tools/interactive-bash/tmux-path-resolver" +import type { TmuxSessionManager } from "../../tmux-subagent/manager" + +type TeamLayoutMember = { name: string; sessionId: string; color?: string } + +type TeamLayoutResult = { + focusWindowId: string + gridWindowId: string + panesByMember: Record +} + +export function canVisualize(): boolean { + return process.env.TMUX !== undefined +} + +async function runTmux(tmuxPath: string, args: Array): Promise<{ success: boolean; output: string }> { + const proc = spawn([tmuxPath, ...args], { stdout: "pipe", stderr: "pipe" }) + const outputPromise = new Response(proc.stdout).text() + const exitCode = await proc.exited + const output = await outputPromise + + if (exitCode !== 0) { + return { success: false, output: output.trim() } + } + + return { success: true, output: output.trim() } +} + +async function createWindow( + tmuxPath: string, + sessionName: string, + windowName: string, + layout: "main-vertical" | "tiled", + members: Array, +): Promise<{ windowId: string; panesByMember: Record } | null> { + const base = await runTmux(tmuxPath, ["new-window", "-d", "-P", "-F", "#{window_id}", "-t", sessionName, "-n", windowName]) + if (!base.success || !base.output) return null + + const panesByMember: Record = {} + const [lead, ...rest] = members + if (!lead) return null + + const leadPane = await runTmux(tmuxPath, ["list-panes", "-t", `${sessionName}:${base.output}`, "-F", "#{pane_id}"]) + if (!leadPane.success || !leadPane.output) return null + panesByMember[lead.name] = leadPane.output.split("\n")[0] ?? "" + + for (const member of rest) { + const split = await runTmux(tmuxPath, ["split-window", "-d", "-P", "-F", "#{pane_id}", "-t", panesByMember[lead.name] ?? base.output, "sh", "-c", "cat >/dev/null"]) + if (!split.success || !split.output) return null + panesByMember[member.name] = split.output + } + + const layoutResult = await runTmux(tmuxPath, ["select-layout", "-t", `${sessionName}:${base.output}`, layout]) + if (!layoutResult.success) return null + + for (const member of members) { + const paneId = panesByMember[member.name] + if (!paneId) return null + const label = member.color ? `${member.name} ${member.color}` : member.name + const titleResult = await runTmux(tmuxPath, ["select-pane", "-t", paneId, "-T", label]) + if (!titleResult.success) return null + await runTmux(tmuxPath, ["set-option", "-t", paneId, "pane-border-status", "top"]) + await runTmux(tmuxPath, ["set-option", "-t", paneId, "pane-border-format", `#{pane_title} ${label}`]) + await runTmux(tmuxPath, ["pipe-pane", "-I", "-t", paneId, "cat >/dev/null"]) + } + + return { windowId: base.output, panesByMember } +} + +export async function createTeamLayout( + teamRunId: string, + members: Array, + tmuxMgr: TmuxSessionManager, +): Promise { + if (!canVisualize()) { + log("tmux visualization unavailable, skipping") + return null + } + + try { + void tmuxMgr + const tmuxPath = await getTmuxPath() + if (!tmuxPath) { + log("tmux visualization unavailable, skipping") + return null + } + + const sessionName = `omo-team-${teamRunId}` + const created = await runTmux(tmuxPath, ["new-session", "-d", "-s", sessionName, "-P", "-F", "#{window_id}"]) + if (!created.success || !created.output) return null + + const focus = await createWindow(tmuxPath, sessionName, "focus", "main-vertical", members) + const grid = await createWindow(tmuxPath, sessionName, "grid", "tiled", members) + if (!focus || !grid) return null + + return { + focusWindowId: focus.windowId, + gridWindowId: grid.windowId, + panesByMember: focus.panesByMember, + } + } catch (error) { + log("tmux visualization unavailable, skipping", { error: String(error) }) + return null + } +} + +export async function removeTeamLayout(teamRunId: string, tmuxMgr: TmuxSessionManager): Promise { + void tmuxMgr + if (!canVisualize()) return + + try { + const tmuxPath = await getTmuxPath() + if (!tmuxPath) return + await runTmux(tmuxPath, ["kill-session", "-t", `omo-team-${teamRunId}`]) + } catch { + return + } +} From 7a7926f2220790ebe346ce9828fa8b5497db87bf Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:30:44 +0900 Subject: [PATCH 101/146] chore(tmux-subagent): remove dead event-handler modules Drop cleanup.ts, session-created-handler.ts, and session-deleted-handler.ts which were never wired up; the lifecycle logic they contained lives inline in TmuxSessionManager. Barrels trimmed to match. --- src/features/tmux-subagent/cleanup.ts | 42 ----- src/features/tmux-subagent/event-handlers.ts | 4 - src/features/tmux-subagent/index.ts | 3 - .../tmux-subagent/session-created-handler.ts | 175 ------------------ .../tmux-subagent/session-deleted-handler.ts | 50 ----- 5 files changed, 274 deletions(-) delete mode 100644 src/features/tmux-subagent/cleanup.ts delete mode 100644 src/features/tmux-subagent/session-created-handler.ts delete mode 100644 src/features/tmux-subagent/session-deleted-handler.ts diff --git a/src/features/tmux-subagent/cleanup.ts b/src/features/tmux-subagent/cleanup.ts deleted file mode 100644 index 414ad00bc..000000000 --- a/src/features/tmux-subagent/cleanup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { TmuxConfig } from "../../config/schema" -import { log } from "../../shared" -import type { TrackedSession } from "./types" -import { queryWindowState } from "./pane-state-querier" -import { executeAction } from "./action-executor" - -export async function cleanupTmuxSessions(params: { - tmuxConfig: TmuxConfig - serverUrl: string - sourcePaneId: string | undefined - sessions: Map - stopPolling: () => void -}): Promise { - params.stopPolling() - - if (params.sessions.size === 0) { - log("[tmux-session-manager] cleanup complete") - return - } - - log("[tmux-session-manager] closing all panes", { count: params.sessions.size }) - const state = params.sourcePaneId ? await queryWindowState(params.sourcePaneId) : null - - if (state) { - const closePromises = Array.from(params.sessions.values()).map((tracked) => - executeAction( - { type: "close", paneId: tracked.paneId, sessionId: tracked.sessionId }, - { config: params.tmuxConfig, serverUrl: params.serverUrl, windowState: state }, - ).catch((error) => - log("[tmux-session-manager] cleanup error for pane", { - paneId: tracked.paneId, - error: String(error), - }), - ), - ) - - await Promise.all(closePromises) - } - - params.sessions.clear() - log("[tmux-session-manager] cleanup complete") -} diff --git a/src/features/tmux-subagent/event-handlers.ts b/src/features/tmux-subagent/event-handlers.ts index 0991d10e2..2916c7439 100644 --- a/src/features/tmux-subagent/event-handlers.ts +++ b/src/features/tmux-subagent/event-handlers.ts @@ -1,6 +1,2 @@ export { coerceSessionCreatedEvent } from "./session-created-event" export type { SessionCreatedEvent } from "./session-created-event" -export { handleSessionCreated } from "./session-created-handler" -export type { SessionCreatedHandlerDeps } from "./session-created-handler" -export { handleSessionDeleted } from "./session-deleted-handler" -export type { SessionDeletedHandlerDeps } from "./session-deleted-handler" diff --git a/src/features/tmux-subagent/index.ts b/src/features/tmux-subagent/index.ts index e900555fb..cba66fa6b 100644 --- a/src/features/tmux-subagent/index.ts +++ b/src/features/tmux-subagent/index.ts @@ -1,10 +1,7 @@ export * from "./manager" export * from "./event-handlers" export * from "./polling" -export * from "./cleanup" export * from "./session-created-event" -export * from "./session-created-handler" -export * from "./session-deleted-handler" export * from "./polling-constants" export * from "./session-status-parser" export * from "./session-message-count" diff --git a/src/features/tmux-subagent/session-created-handler.ts b/src/features/tmux-subagent/session-created-handler.ts deleted file mode 100644 index 6dd1f21eb..000000000 --- a/src/features/tmux-subagent/session-created-handler.ts +++ /dev/null @@ -1,175 +0,0 @@ -import type { PluginInput } from "@opencode-ai/plugin" -import type { TmuxConfig } from "../../config/schema" -import type { CapacityConfig, TrackedSession } from "./types" -import { log } from "../../shared" -import { queryWindowState } from "./pane-state-querier" -import { decideSpawnActions, type SessionMapping } from "./decision-engine" -import { executeActions } from "./action-executor" -import type { SessionCreatedEvent } from "./session-created-event" -import { createTrackedSession } from "./tracked-session-state" - -type OpencodeClient = PluginInput["client"] - -export interface SessionCreatedHandlerDeps { - client: OpencodeClient - tmuxConfig: TmuxConfig - serverUrl: string - sourcePaneId: string | undefined - sessions: Map - pendingSessions: Set - isInsideTmux: () => boolean - isEnabled: () => boolean - getCapacityConfig: () => CapacityConfig - getSessionMappings: () => SessionMapping[] - waitForSessionReady: (sessionId: string) => Promise - startPolling: () => void -} - -export async function handleSessionCreated( - deps: SessionCreatedHandlerDeps, - event: SessionCreatedEvent, -): Promise { - const enabled = deps.isEnabled() - log("[tmux-session-manager] onSessionCreated called", { - enabled, - tmuxConfigEnabled: deps.tmuxConfig.enabled, - isInsideTmux: deps.isInsideTmux(), - eventType: event.type, - infoId: event.properties?.info?.id, - infoParentID: event.properties?.info?.parentID, - }) - - if (!enabled) return - if (event.type !== "session.created") return - - const info = event.properties?.info - if (!info?.id || !info?.parentID) return - - const sessionId = info.id - const title = info.title ?? "Subagent" - - if (deps.sessions.has(sessionId) || deps.pendingSessions.has(sessionId)) { - log("[tmux-session-manager] session already tracked or pending", { sessionId }) - return - } - - if (!deps.sourcePaneId) { - log("[tmux-session-manager] no source pane id") - return - } - - deps.pendingSessions.add(sessionId) - - try { - const state = await queryWindowState(deps.sourcePaneId) - if (!state) { - log("[tmux-session-manager] failed to query window state") - return - } - - log("[tmux-session-manager] window state queried", { - windowWidth: state.windowWidth, - mainPane: state.mainPane?.paneId, - agentPaneCount: state.agentPanes.length, - agentPanes: state.agentPanes.map((p) => p.paneId), - }) - - const decision = decideSpawnActions( - state, - sessionId, - title, - deps.getCapacityConfig(), - deps.getSessionMappings(), - ) - - log("[tmux-session-manager] spawn decision", { - canSpawn: decision.canSpawn, - reason: decision.reason, - actionCount: decision.actions.length, - actions: decision.actions.map((a) => { - if (a.type === "close") return { type: "close", paneId: a.paneId } - if (a.type === "replace") { - return { type: "replace", paneId: a.paneId, newSessionId: a.newSessionId } - } - return { type: "spawn", sessionId: a.sessionId } - }), - }) - - if (!decision.canSpawn) { - log("[tmux-session-manager] cannot spawn", { reason: decision.reason }) - return - } - - const result = await executeActions(decision.actions, { - config: deps.tmuxConfig, - serverUrl: deps.serverUrl, - windowState: state, - }) - - for (const { action, result: actionResult } of result.results) { - if (action.type === "close" && actionResult.success) { - deps.sessions.delete(action.sessionId) - log("[tmux-session-manager] removed closed session from cache", { - sessionId: action.sessionId, - }) - } - if (action.type === "replace" && actionResult.success) { - deps.sessions.delete(action.oldSessionId) - log("[tmux-session-manager] removed replaced session from cache", { - oldSessionId: action.oldSessionId, - newSessionId: action.newSessionId, - }) - } - } - - if (!result.success || !result.spawnedPaneId) { - log("[tmux-session-manager] spawn failed", { - success: result.success, - results: result.results.map((r) => ({ - type: r.action.type, - success: r.result.success, - error: r.result.error, - })), - }) - return - } - - const sessionReady = await deps.waitForSessionReady(sessionId) - if (!sessionReady) { - log("[tmux-session-manager] session not ready after timeout, closing spawned pane", { - sessionId, - paneId: result.spawnedPaneId, - }) - - await executeActions( - [{ type: "close", paneId: result.spawnedPaneId, sessionId }], - { - config: deps.tmuxConfig, - serverUrl: deps.serverUrl, - windowState: state, - }, - ) - - return - } - - deps.sessions.set( - sessionId, - createTrackedSession({ - sessionId, - paneId: result.spawnedPaneId, - description: title, - }), - ) - - log("[tmux-session-manager] pane spawned and tracked", { - sessionId, - paneId: result.spawnedPaneId, - sessionReady, - }) - - deps.startPolling() - } finally { - deps.pendingSessions.delete(sessionId) - } -} diff --git a/src/features/tmux-subagent/session-deleted-handler.ts b/src/features/tmux-subagent/session-deleted-handler.ts deleted file mode 100644 index f832cf481..000000000 --- a/src/features/tmux-subagent/session-deleted-handler.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { TmuxConfig } from "../../config/schema" -import type { TrackedSession } from "./types" -import { log } from "../../shared" -import { queryWindowState } from "./pane-state-querier" -import { decideCloseAction, type SessionMapping } from "./decision-engine" -import { executeAction } from "./action-executor" - -export interface SessionDeletedHandlerDeps { - tmuxConfig: TmuxConfig - serverUrl: string - sourcePaneId: string | undefined - sessions: Map - isEnabled: () => boolean - getSessionMappings: () => SessionMapping[] - stopPolling: () => void -} - -export async function handleSessionDeleted( - deps: SessionDeletedHandlerDeps, - event: { sessionID: string }, -): Promise { - if (!deps.isEnabled()) return - if (!deps.sourcePaneId) return - - const tracked = deps.sessions.get(event.sessionID) - if (!tracked) return - - log("[tmux-session-manager] onSessionDeleted", { sessionId: event.sessionID }) - - const state = await queryWindowState(deps.sourcePaneId) - if (!state) { - deps.sessions.delete(event.sessionID) - return - } - - const closeAction = decideCloseAction(state, event.sessionID, deps.getSessionMappings()) - if (closeAction) { - await executeAction(closeAction, { - config: deps.tmuxConfig, - serverUrl: deps.serverUrl, - windowState: state, - }) - } - - deps.sessions.delete(event.sessionID) - - if (deps.sessions.size === 0) { - deps.stopPolling() - } -} From 2a99a524ea99ac3eba5717da3bd0e4c5b8bc53fe Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:31:04 +0900 Subject: [PATCH 102/146] fix(tmux): drain kill-pane stdout to prevent pipe backpressure hang closeTmuxPane spawned kill-pane with stdout: "pipe" but never drained the stream, which could leave the subprocess hanging indefinitely when tmux wrote anything to stdout (for example under --force-close race conditions). - send-keys now uses stdout: "ignore" so there is no pipe to drain - kill-pane keeps the pipe but drains stdout/stderr alongside proc.exited - switch imports to the new spawn-process helper so the behavior is covered by hermetic tests that mock the spawn boundary --- src/shared/tmux/tmux-utils/pane-close.test.ts | 197 ++++++++++++++++++ src/shared/tmux/tmux-utils/pane-close.ts | 28 ++- src/shared/tmux/tmux-utils/spawn-process.ts | 1 + 3 files changed, 216 insertions(+), 10 deletions(-) create mode 100644 src/shared/tmux/tmux-utils/pane-close.test.ts create mode 100644 src/shared/tmux/tmux-utils/spawn-process.ts diff --git a/src/shared/tmux/tmux-utils/pane-close.test.ts b/src/shared/tmux/tmux-utils/pane-close.test.ts new file mode 100644 index 000000000..ca5d74684 --- /dev/null +++ b/src/shared/tmux/tmux-utils/pane-close.test.ts @@ -0,0 +1,197 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test" + +type CloseTmuxPane = typeof import("./pane-close").closeTmuxPane + +type SpawnCall = { + command: string[] + options: { + stdout?: string + stderr?: string + } +} + +type FakeSubprocess = { + exited: Promise + stdout: ReadableStream + stderr: ReadableStream +} + +const TIMEOUT = Symbol("timeout") +const spawnCalls: SpawnCall[] = [] +const queuedProcesses: FakeSubprocess[] = [] + +function createClosedStream(): ReadableStream { + return new ReadableStream({ + start(controller) { + controller.close() + }, + }) +} + +type DrainSignal = { onPull: () => void } + +function createDrainSensitiveStream(byteLength: number, signal: DrainSignal): ReadableStream { + let remainingBytes = byteLength + const chunk = new TextEncoder().encode("x".repeat(16 * 1024)) + + return new ReadableStream({ + pull(controller) { + signal.onPull() + + if (remainingBytes <= 0) { + controller.close() + return + } + + const nextChunkSize = Math.min(remainingBytes, chunk.byteLength) + controller.enqueue(chunk.subarray(0, nextChunkSize)) + remainingBytes -= nextChunkSize + }, + }) +} + +function createProcess(exitCode: number): FakeSubprocess { + return { + exited: Promise.resolve(exitCode), + stdout: createClosedStream(), + stderr: createClosedStream(), + } +} + +function createStdoutSensitiveProcess(exitCode: number, stdoutBytes: number): FakeSubprocess { + let resolveDrained: () => void = () => undefined + const drained = new Promise((resolve) => { + resolveDrained = resolve + }) + const stdout = createDrainSensitiveStream(stdoutBytes, { onPull: () => resolveDrained() }) + + return { + exited: drained.then(() => exitCode), + stdout, + stderr: createClosedStream(), + } +} + +const spawnMock = mock((command: string[], options: { stdout?: string; stderr?: string } = {}): FakeSubprocess => { + spawnCalls.push({ command, options }) + + const process = queuedProcesses.shift() + if (!process) { + throw new Error(`No fake subprocess configured for ${command.join(" ")}`) + } + + return process +}) + +const isInsideTmuxMock = mock((): boolean => true) +const getTmuxPathMock = mock(async (): Promise => "tmux") +const logMock = mock(() => undefined) + +const paneCloseSpecifier = import.meta.resolve("./pane-close") +const environmentSpecifier = import.meta.resolve("./environment") +const loggerSpecifier = import.meta.resolve("../../logger") +const spawnProcessSpecifier = import.meta.resolve("./spawn-process") +const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") + +async function loadCloseTmuxPane(): Promise { + const module = await import(`${paneCloseSpecifier}?test=${crypto.randomUUID()}`) + return module.closeTmuxPane +} + +function registerModuleMocks(): void { + mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) + mock.module(environmentSpecifier, () => ({ isInsideTmux: isInsideTmuxMock })) + mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: getTmuxPathMock })) + mock.module(loggerSpecifier, () => ({ log: logMock })) +} + +function resolveWithin(promise: Promise, milliseconds: number): Promise { + return Promise.race([ + promise, + new Promise((resolve) => { + setTimeout(() => resolve(TIMEOUT), milliseconds) + }), + ]) +} + +describe("closeTmuxPane", () => { + beforeEach(() => { + registerModuleMocks() + spawnCalls.length = 0 + queuedProcesses.length = 0 + spawnMock.mockClear() + isInsideTmuxMock.mockClear() + getTmuxPathMock.mockClear() + logMock.mockClear() + + isInsideTmuxMock.mockImplementation((): boolean => true) + getTmuxPathMock.mockImplementation(async (): Promise => "tmux") + }) + + it("#given pane exists #when closeTmuxPane called #then returns true and invokes send-keys + kill-pane in order", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push(createProcess(0), createProcess(0)) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(true) + expect(spawnCalls).toEqual([ + { command: ["tmux", "send-keys", "-t", "%42", "C-c"], options: { stdout: "ignore", stderr: "ignore" } }, + { command: ["tmux", "kill-pane", "-t", "%42"], options: { stdout: "pipe", stderr: "pipe" } }, + ]) + }) + + it("#given not inside tmux #when closeTmuxPane called #then returns false without spawn", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + isInsideTmuxMock.mockImplementation((): boolean => false) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + }) + + it("#given tmux not found #when closeTmuxPane called #then returns false without spawn", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + getTmuxPathMock.mockImplementation(async (): Promise => undefined) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + }) + + it("#given kill-pane fails #when closeTmuxPane called #then returns false", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push(createProcess(0), createProcess(1)) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(false) + }) + + it("#given kill-pane stdout stream waits for drain #when closeTmuxPane called #then returns true once drainer consumes stdout", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push(createProcess(0), createStdoutSensitiveProcess(0, 16 * 1024)) + + // when + const result = await resolveWithin(closeTmuxPane("%42"), 2000) + + // then + expect(result).not.toBe(TIMEOUT) + expect(result).toBe(true) + }) +}) diff --git a/src/shared/tmux/tmux-utils/pane-close.ts b/src/shared/tmux/tmux-utils/pane-close.ts index cc6f4b6c4..76d9dd11b 100644 --- a/src/shared/tmux/tmux-utils/pane-close.ts +++ b/src/shared/tmux/tmux-utils/pane-close.ts @@ -1,13 +1,18 @@ -import { spawn } from "bun" -import { getTmuxPath } from "../../../tools/interactive-bash/tmux-path-resolver" -import { isInsideTmux } from "./environment" - function delay(milliseconds: number): Promise { return new Promise((resolve) => setTimeout(resolve, milliseconds)) } +async function readStream(stream: ReadableStream | null | undefined): Promise { + return stream ? new Response(stream).text() : "" +} + export async function closeTmuxPane(paneId: string): Promise { - const { log } = await import("../../logger") + const [{ log }, { isInsideTmux }, { getTmuxPath }, { spawn }] = await Promise.all([ + import("../../logger"), + import("./environment"), + import("../../../tools/interactive-bash/tmux-path-resolver"), + import("./spawn-process"), + ]) if (!isInsideTmux()) { log("[closeTmuxPane] SKIP: not inside tmux") @@ -22,8 +27,8 @@ export async function closeTmuxPane(paneId: string): Promise { log("[closeTmuxPane] sending Ctrl+C for graceful shutdown", { paneId }) const ctrlCProc = spawn([tmux, "send-keys", "-t", paneId, "C-c"], { - stdout: "pipe", - stderr: "pipe", + stdout: "ignore", + stderr: "ignore", }) await ctrlCProc.exited @@ -31,12 +36,15 @@ export async function closeTmuxPane(paneId: string): Promise { log("[closeTmuxPane] killing pane", { paneId }) - const proc = spawn([tmux, "kill-pane", "-t", paneId], { + const killPaneProc = spawn([tmux, "kill-pane", "-t", paneId], { stdout: "pipe", stderr: "pipe", }) - const exitCode = await proc.exited - const stderr = await new Response(proc.stderr).text() + const [, stderr, exitCode] = await Promise.all([ + readStream(killPaneProc.stdout), + readStream(killPaneProc.stderr), + killPaneProc.exited, + ]) if (exitCode !== 0) { log("[closeTmuxPane] FAILED", { paneId, exitCode, stderr: stderr.trim() }) diff --git a/src/shared/tmux/tmux-utils/spawn-process.ts b/src/shared/tmux/tmux-utils/spawn-process.ts new file mode 100644 index 000000000..c75826cab --- /dev/null +++ b/src/shared/tmux/tmux-utils/spawn-process.ts @@ -0,0 +1 @@ +export { spawn } from "bun" From de8a0167e61876aa30467d52641bd9094c8f0f97 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:31:22 +0900 Subject: [PATCH 103/146] feat(tmux): add killTmuxSessionIfExists utility for explicit session teardown Adds killTmuxSessionIfExists(sessionName), a best-effort no-op when the named session is absent. Drains both stdio streams so it does not leak pipe buffers the way closeTmuxPane historically did. Also exports ISOLATED_SESSION_NAME ("omo-agents") from session-spawn so callers can tear down the shared isolated session without hard-coding the name in multiple places. --- src/shared/tmux/tmux-utils.ts | 3 +- src/shared/tmux/tmux-utils/index.ts | 1 + .../tmux/tmux-utils/session-kill.test.ts | 173 ++++++++++++++++++ src/shared/tmux/tmux-utils/session-kill.ts | 51 ++++++ src/shared/tmux/tmux-utils/session-spawn.ts | 2 +- 5 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 src/shared/tmux/tmux-utils/index.ts create mode 100644 src/shared/tmux/tmux-utils/session-kill.test.ts create mode 100644 src/shared/tmux/tmux-utils/session-kill.ts diff --git a/src/shared/tmux/tmux-utils.ts b/src/shared/tmux/tmux-utils.ts index a9aab095a..587704536 100644 --- a/src/shared/tmux/tmux-utils.ts +++ b/src/shared/tmux/tmux-utils.ts @@ -10,6 +10,7 @@ export { spawnTmuxPane } from "./tmux-utils/pane-spawn" export { closeTmuxPane } from "./tmux-utils/pane-close" export { replaceTmuxPane } from "./tmux-utils/pane-replace" export { spawnTmuxWindow } from "./tmux-utils/window-spawn" -export { spawnTmuxSession } from "./tmux-utils/session-spawn" +export { spawnTmuxSession, ISOLATED_SESSION_NAME } from "./tmux-utils/session-spawn" +export { killTmuxSessionIfExists } from "./tmux-utils/session-kill" export { applyLayout, enforceMainPaneWidth } from "./tmux-utils/layout" diff --git a/src/shared/tmux/tmux-utils/index.ts b/src/shared/tmux/tmux-utils/index.ts new file mode 100644 index 000000000..e55436a1c --- /dev/null +++ b/src/shared/tmux/tmux-utils/index.ts @@ -0,0 +1 @@ +export { killTmuxSessionIfExists } from "./session-kill" diff --git a/src/shared/tmux/tmux-utils/session-kill.test.ts b/src/shared/tmux/tmux-utils/session-kill.test.ts new file mode 100644 index 000000000..ca185d980 --- /dev/null +++ b/src/shared/tmux/tmux-utils/session-kill.test.ts @@ -0,0 +1,173 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test" + +type KillTmuxSessionIfExists = typeof import("./session-kill").killTmuxSessionIfExists + +type SpawnCall = { + command: string[] + options: { + stdout?: string + stderr?: string + } +} + +type FakeSubprocess = { + exited: Promise + stdout: ReadableStream + stderr: ReadableStream +} + +const spawnCalls: SpawnCall[] = [] +const queuedProcesses: FakeSubprocess[] = [] + +function createStream(chunks: string[] = []): ReadableStream { + const textEncoder = new TextEncoder() + + return new ReadableStream({ + start(controller) { + for (const chunk of chunks) { + controller.enqueue(textEncoder.encode(chunk)) + } + + controller.close() + }, + }) +} + +function createProcess(exitCode: number, output: { stdout?: string[]; stderr?: string[] } = {}): FakeSubprocess { + return { + exited: Promise.resolve(exitCode), + stdout: createStream(output.stdout), + stderr: createStream(output.stderr), + } +} + +const spawnMock = mock((command: string[], options: { stdout?: string; stderr?: string } = {}) => { + spawnCalls.push({ command, options }) + + const process = queuedProcesses.shift() + if (!process) { + throw new Error(`No fake subprocess configured for ${command.join(" ")}`) + } + + return process +}) + +const isInsideTmuxMock = mock((): boolean => true) +const getTmuxPathMock = mock(async (): Promise => "tmux") +const logMock = mock(() => undefined) + +const sessionKillSpecifier = import.meta.resolve("./session-kill") +const environmentSpecifier = import.meta.resolve("./environment") +const loggerSpecifier = import.meta.resolve("../../logger") +const spawnProcessSpecifier = import.meta.resolve("./spawn-process") +const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") + +async function loadKillTmuxSessionIfExists(): Promise { + const module = await import(`${sessionKillSpecifier}?test=${crypto.randomUUID()}`) + return module.killTmuxSessionIfExists +} + +function registerModuleMocks(): void { + mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) + mock.module(environmentSpecifier, () => ({ isInsideTmux: isInsideTmuxMock })) + mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: getTmuxPathMock })) + mock.module(loggerSpecifier, () => ({ log: logMock })) +} + +describe("killTmuxSessionIfExists", () => { + beforeEach(() => { + registerModuleMocks() + spawnCalls.length = 0 + queuedProcesses.length = 0 + spawnMock.mockClear() + isInsideTmuxMock.mockClear() + getTmuxPathMock.mockClear() + logMock.mockClear() + + isInsideTmuxMock.mockImplementation((): boolean => true) + getTmuxPathMock.mockImplementation(async (): Promise => "tmux") + }) + + it("#given omo-agents session exists #when killTmuxSessionIfExists called #then kill-session invoked and returns true", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + queuedProcesses.push(createProcess(0), createProcess(0, { stdout: ["killed"], stderr: [] })) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(true) + expect(spawnCalls).toEqual([ + { + command: ["tmux", "has-session", "-t", "omo-agents"], + options: { stdout: "ignore", stderr: "ignore" }, + }, + { + command: ["tmux", "kill-session", "-t", "omo-agents"], + options: { stdout: "pipe", stderr: "pipe" }, + }, + ]) + }) + + it("#given omo-agents session does NOT exist (has-session exits non-zero) #when killTmuxSessionIfExists called #then NO kill-session invocation and returns false", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + queuedProcesses.push(createProcess(1)) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toEqual([ + { + command: ["tmux", "has-session", "-t", "omo-agents"], + options: { stdout: "ignore", stderr: "ignore" }, + }, + ]) + }) + + it("#given not inside tmux #when killTmuxSessionIfExists called #then returns false without any spawn", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + isInsideTmuxMock.mockReturnValue(false) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + expect(getTmuxPathMock).toHaveBeenCalledTimes(0) + }) + + it("#given tmux not found #when killTmuxSessionIfExists called #then returns false without spawn", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + getTmuxPathMock.mockResolvedValue(undefined) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + }) + + it("#given kill-session itself fails (e.g., race between has-session and kill) #when killTmuxSessionIfExists called #then returns false but does not throw", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + queuedProcesses.push( + createProcess(0), + createProcess(1, { stdout: [], stderr: ["no session"] }), + ) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(2) + }) +}) diff --git a/src/shared/tmux/tmux-utils/session-kill.ts b/src/shared/tmux/tmux-utils/session-kill.ts new file mode 100644 index 000000000..fc5f765df --- /dev/null +++ b/src/shared/tmux/tmux-utils/session-kill.ts @@ -0,0 +1,51 @@ +async function readStream(stream: ReadableStream | null | undefined): Promise { + return stream ? new Response(stream).text() : "" +} + +export async function killTmuxSessionIfExists(sessionName: string): Promise { + const [{ log }, { isInsideTmux }, { getTmuxPath }, { spawn }] = await Promise.all([ + import("../../logger"), + import("./environment"), + import("../../../tools/interactive-bash/tmux-path-resolver"), + import("./spawn-process"), + ]) + + if (!isInsideTmux()) { + log("[killTmuxSessionIfExists] SKIP: not inside tmux", { sessionName }) + return false + } + + const tmux = await getTmuxPath() + if (!tmux) { + log("[killTmuxSessionIfExists] SKIP: tmux not found", { sessionName }) + return false + } + + const hasSessionProcess = spawn([tmux, "has-session", "-t", sessionName], { + stdout: "ignore", + stderr: "ignore", + }) + + if ((await hasSessionProcess.exited) !== 0) { + log("[killTmuxSessionIfExists] SKIP: session not found", { sessionName }) + return false + } + + const killSessionProcess = spawn([tmux, "kill-session", "-t", sessionName], { + stdout: "pipe", + stderr: "pipe", + }) + const [, stderr, exitCode] = await Promise.all([ + readStream(killSessionProcess.stdout), + readStream(killSessionProcess.stderr), + killSessionProcess.exited, + ]) + + if (exitCode !== 0) { + log("[killTmuxSessionIfExists] FAILED", { sessionName, exitCode, stderr: stderr.trim() }) + return false + } + + log("[killTmuxSessionIfExists] SUCCESS", { sessionName }) + return true +} diff --git a/src/shared/tmux/tmux-utils/session-spawn.ts b/src/shared/tmux/tmux-utils/session-spawn.ts index db1feee29..dd9f5addd 100644 --- a/src/shared/tmux/tmux-utils/session-spawn.ts +++ b/src/shared/tmux/tmux-utils/session-spawn.ts @@ -6,7 +6,7 @@ import { isInsideTmux } from "./environment" import { isServerRunning } from "./server-health" import { shellEscapeForDoubleQuotedCommand } from "../../shell-env" -const ISOLATED_SESSION_NAME = "omo-agents" +export const ISOLATED_SESSION_NAME = "omo-agents" async function getWindowDimensions( tmux: string, From 21554be8709fc73b1a9dd19ac248bb5b86621167 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:31:45 +0900 Subject: [PATCH 104/146] fix(tmux-subagent): tighten serve/attach cleanup paths so panes and sessions are torn down reliably Three defects observed with tmux.isolation="session" where the omo-agents session was left with orphan fish panes after subagents finished: 1. cleanup() never ran 'tmux kill-session -t omo-agents'. If any pane lingered (for example because opencode attach stayed blocked on SSE), the isolated session survived process shutdown. Now we explicitly kill the shared session through killTmuxSessionIfExists when isolation is "session". 2. session.error events bypassed tmux cleanup entirely. Only session.deleted closed panes, so any provider error that did not escalate into a delete left the pane behind. Added onSessionError on TmuxSessionManager, wired from plugin/event.ts, which funnels through the same onSessionDeleted close path for tracked sessions only. 3. retryPendingCloses() only ran when a new session was created. If the main process went idle after a failed close, the pending session stayed pending forever. TmuxPollingManager now accepts the retry callback and fires it on every tick, alongside the existing stability-based close sweep. Manager tests cover isolation=session kill invocation, inline/window isolation skipping the kill, the onSessionError happy + untracked paths, and an isolated-session kill failure that must not break cleanup. --- src/features/tmux-subagent/manager.test.ts | 109 ++++++++++++++++++ src/features/tmux-subagent/manager.ts | 32 ++++- src/features/tmux-subagent/polling-manager.ts | 11 +- src/plugin/event.ts | 4 + 4 files changed, 154 insertions(+), 2 deletions(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index c8cf2c1d2..f828ff9d7 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -57,6 +57,7 @@ const mockSpawnTmuxSession = mock<( success: true, paneId: '%isolated-session', })) +const mockKillTmuxSessionIfExists = mock<(sessionName: string) => Promise>(async () => true) const mockIsInsideTmux = mock<() => boolean>(() => true) const mockGetCurrentPaneId = mock<() => string | undefined>(() => '%0') @@ -99,6 +100,8 @@ mock.module('../../shared/tmux', () => { SESSION_READY_TIMEOUT_MS: 500, spawnTmuxWindow: mockSpawnTmuxWindow, spawnTmuxSession: mockSpawnTmuxSession, + killTmuxSessionIfExists: mockKillTmuxSessionIfExists, + ISOLATED_SESSION_NAME: 'omo-agents', } }) @@ -1852,6 +1855,112 @@ describe('TmuxSessionManager', () => { // then expect(mockExecuteAction).toHaveBeenCalledTimes(2) }) + + test('#given tmux isolation is "session" #when cleanup runs #then killTmuxSessionIfExists is invoked for the isolated session', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await manager.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(1) + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledWith('omo-agents') + }) + + test('#given tmux isolation is "inline" #when cleanup runs #then killTmuxSessionIfExists is NOT invoked', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'inline', + }), mockTmuxDeps) + + // when + await manager.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(0) + }) + + test('#given tmux isolation is "window" #when cleanup runs #then killTmuxSessionIfExists is NOT invoked', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'window', + }), mockTmuxDeps) + + // when + await manager.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(0) + }) + + test('#given a tracked session #when onSessionError is invoked #then the pane is closed like onSessionDeleted', async () => { + // given + mockIsInsideTmux.mockReturnValue(true) + mockExecuteAction.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + await manager.onSessionCreated(createSessionCreatedEvent('ses_err', 'ses_parent', 'Errored Task')) + mockExecuteAction.mockClear() + + // when + await manager.onSessionError({ sessionID: 'ses_err' }) + + // then + expect(mockExecuteAction).toHaveBeenCalled() + }) + + test('#given an untracked session #when onSessionError is invoked #then it is a no-op and does not throw', async () => { + // given + mockIsInsideTmux.mockReturnValue(true) + mockExecuteAction.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + const errorHandler = manager.onSessionError({ sessionID: 'ses_unknown' }) + + // then + await expect(errorHandler).resolves.toBeUndefined() + expect(mockExecuteAction).not.toHaveBeenCalled() + }) + + test('#given killTmuxSessionIfExists throws #when cleanup runs #then cleanup still completes without throwing', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + mockKillTmuxSessionIfExists.mockImplementationOnce(async () => { + throw new Error('simulated teardown failure') + }) + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + const cleanupPromise = manager.cleanup() + + // then + await expect(cleanupPromise).resolves.toBeUndefined() + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(1) + }) }) }) diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index e379bce96..ee1b8b508 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -10,6 +10,8 @@ import { SESSION_READY_TIMEOUT_MS, spawnTmuxWindow, spawnTmuxSession, + killTmuxSessionIfExists, + ISOLATED_SESSION_NAME, } from "../../shared/tmux" import { queryWindowState } from "./pane-state-querier" import { decideSpawnActions, decideCloseAction, type SessionMapping } from "./decision-engine" @@ -89,7 +91,8 @@ export class TmuxSessionManager { this.pollingManager = new TmuxPollingManager( this.client, this.sessions, - this.closeSessionById.bind(this) + this.closeSessionById.bind(this), + this.retryPendingCloses.bind(this) ) log("[tmux-session-manager] initialized", { configEnabled: this.tmuxConfig.enabled, @@ -832,6 +835,18 @@ export class TmuxSessionManager { await this.spawnQueue } + async onSessionError(event: { sessionID: string }): Promise { + if (!this.isEnabled()) return + if (!this.getEffectiveSourcePaneId()) return + if (!this.sessions.has(event.sessionID)) return + + log("[tmux-session-manager] onSessionError - routing to cleanup", { + sessionId: event.sessionID, + }) + + await this.onSessionDeleted(event) + } + async onSessionDeleted(event: { sessionID: string }): Promise { if (!this.isEnabled()) return if (!this.getEffectiveSourcePaneId()) return @@ -954,6 +969,21 @@ export class TmuxSessionManager { this.isolatedContainerPaneId = undefined this.isolatedWindowPaneId = undefined + if (this.tmuxConfig.isolation === "session") { + try { + const killed = await killTmuxSessionIfExists(ISOLATED_SESSION_NAME) + log("[tmux-session-manager] isolated session teardown", { + session: ISOLATED_SESSION_NAME, + killed, + }) + } catch (error) { + log("[tmux-session-manager] isolated session teardown failed", { + session: ISOLATED_SESSION_NAME, + error: String(error), + }) + } + } + log("[tmux-session-manager] cleanup complete") } } diff --git a/src/features/tmux-subagent/polling-manager.ts b/src/features/tmux-subagent/polling-manager.ts index d7a972d40..1a74be801 100644 --- a/src/features/tmux-subagent/polling-manager.ts +++ b/src/features/tmux-subagent/polling-manager.ts @@ -16,7 +16,8 @@ export class TmuxPollingManager { constructor( private client: OpencodeClient, private sessions: Map, - private closeSessionById: (sessionId: string) => Promise + private closeSessionById: (sessionId: string) => Promise, + private retryPendingCloses?: () => Promise ) {} handleEvent(event: { type: string; properties?: Record }): void { @@ -134,6 +135,14 @@ export class TmuxPollingManager { log("[tmux-session-manager] closing session due to poll", { sessionId }) await this.closeSessionById(sessionId) } + + if (this.retryPendingCloses) { + try { + await this.retryPendingCloses() + } catch (err) { + log("[tmux-session-manager] retry pending closes failed", { error: String(err) }) + } + } } catch (err) { log("[tmux-session-manager] poll error", { error: String(err) }) } finally { diff --git a/src/plugin/event.ts b/src/plugin/event.ts index 5a5f177b6..0f79a84d5 100644 --- a/src/plugin/event.ts +++ b/src/plugin/event.ts @@ -615,6 +615,10 @@ export function createEventHandler(args: { const sessionID = props?.sessionID as string | undefined; const error = props?.error; + if (tmuxIntegrationEnabled && sessionID) { + await managers.tmuxSessionManager.onSessionError({ sessionID }); + } + const errorName = extractErrorName(error); const errorMessage = extractErrorMessage(error); const errorInfo = { name: errorName, message: errorMessage }; From b9d2acdcf9b49067ad23a8f0dd8d8ceb62333439 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:32:04 +0900 Subject: [PATCH 105/146] fix(background-agent): run manager cleanup on uncaughtException and unhandledRejection Signal handlers covered SIGINT/SIGTERM/SIGBREAK/beforeExit/exit, but a synchronous throw or a top-level rejected promise terminated the process without letting TmuxSessionManager (or any other registered manager) run its shutdown hook. That reliably left orphan tmux panes after an opencode crash. Added registration for uncaughtException and unhandledRejection that fan out through the existing cleanupAll() path, set process.exitCode = 1, and arm the same 6 second forced-exit guard we use for signals. Test helpers hold process-level spies so the new tests do not leak listeners between runs. --- .../process-cleanup.test-helpers.ts | 27 ++++ .../background-agent/process-cleanup.test.ts | 148 ++++++++++++++---- .../background-agent/process-cleanup.ts | 56 +++++-- 3 files changed, 183 insertions(+), 48 deletions(-) create mode 100644 src/features/background-agent/process-cleanup.test-helpers.ts diff --git a/src/features/background-agent/process-cleanup.test-helpers.ts b/src/features/background-agent/process-cleanup.test-helpers.ts new file mode 100644 index 000000000..c0a3dfa2d --- /dev/null +++ b/src/features/background-agent/process-cleanup.test-helpers.ts @@ -0,0 +1,27 @@ +type ProcessCleanupEvent = + | NodeJS.Signals + | "beforeExit" + | "exit" + | "uncaughtException" + | "unhandledRejection" + +export function getNewListener( + signal: ProcessCleanupEvent, + existingListeners: Function[], +): () => void { + const listener = process + .listeners(signal) + .find((registeredListener) => !existingListeners.includes(registeredListener)) + + if (typeof listener !== "function") { + throw new Error(`Expected a ${signal} listener to be registered`) + } + + return listener +} + +export async function flushMicrotasks(): Promise { + for (let iteration = 0; iteration < 10; iteration += 1) { + await Promise.resolve() + } +} diff --git a/src/features/background-agent/process-cleanup.test.ts b/src/features/background-agent/process-cleanup.test.ts index 7d01aaa21..4d2975fe0 100644 --- a/src/features/background-agent/process-cleanup.test.ts +++ b/src/features/background-agent/process-cleanup.test.ts @@ -1,3 +1,5 @@ +/// + import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test" import { @@ -5,36 +7,12 @@ import { registerManagerForCleanup, unregisterManagerForCleanup, } from "./process-cleanup" +import { flushMicrotasks, getNewListener } from "./process-cleanup.test-helpers" type CleanupManager = { shutdown: () => void | Promise } -type ProcessCleanupEvent = NodeJS.Signals | "beforeExit" | "exit" - -function getNewListener( - signal: ProcessCleanupEvent, - existingListeners: Function[], -): () => void { - const listener = process - .listeners(signal) - .find((registeredListener) => !existingListeners.includes(registeredListener)) - - expect(listener).toBeDefined() - - if (typeof listener !== "function") { - throw new Error(`Expected a ${signal} listener to be registered`) - } - - return listener -} - -async function flushMicrotasks(): Promise { - for (let iteration = 0; iteration < 10; iteration += 1) { - await Promise.resolve() - } -} - describe("#given process cleanup registration", () => { const registeredManagers: CleanupManager[] = [] const originalExitCode = process.exitCode @@ -92,13 +70,7 @@ describe("#given process cleanup registration", () => { test("#when cleanup finishes after SIGINT #then the fallback exit timer is cleared", async () => { const sigintListenersBefore = process.listeners("SIGINT") - const timeoutHandle = setTimeout(() => undefined, 0) - clearTimeout(timeoutHandle) - - const setTimeoutImplementation: typeof setTimeout = () => timeoutHandle - const setTimeoutSpy = spyOn(globalThis, "setTimeout").mockImplementation( - setTimeoutImplementation, - ) + const setTimeoutSpy = spyOn(globalThis, "setTimeout") const clearTimeoutSpy = spyOn(globalThis, "clearTimeout") try { @@ -117,11 +89,10 @@ describe("#given process cleanup registration", () => { await flushMicrotasks() expect(setTimeoutSpy).toHaveBeenCalledTimes(1) - expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutHandle) + expect(clearTimeoutSpy).toHaveBeenCalledTimes(1) } finally { setTimeoutSpy.mockRestore() clearTimeoutSpy.mockRestore() - clearTimeout(timeoutHandle) } }) }) @@ -163,6 +134,32 @@ describe("#given process cleanup registration", () => { expect(process.listeners("SIGINT")).toHaveLength(sigintListenersAfterFirstRegistration) }) + + test("#given two managers registered #when uncaughtException fires #then both shutdowns called", async () => { + const exitSpy = spyOn(process, "exit").mockImplementation((code?: number): never => { + throw new Error(`Unexpected process.exit(${String(code)})`) + }) + const shutdownOne = mock(() => {}) + const shutdownTwo = mock(() => {}) + const managerOne = { shutdown: shutdownOne } + const managerTwo = { shutdown: shutdownTwo } + registeredManagers.push(managerOne, managerTwo) + + try { + registerManagerForCleanup(managerOne) + registerManagerForCleanup(managerTwo) + + process.emit("uncaughtException", new Error("boom")) + await flushMicrotasks() + + expect(shutdownOne).toHaveBeenCalledTimes(1) + expect(shutdownTwo).toHaveBeenCalledTimes(1) + expect(process.exitCode).toBe(1) + expect(exitSpy).not.toHaveBeenCalled() + } finally { + exitSpy.mockRestore() + } + }) }) describe("#given cleanup managers are unregistered", () => { @@ -202,5 +199,88 @@ describe("#given process cleanup registration", () => { expect(remainingManagerShutdown).toHaveBeenCalledTimes(1) expect(removedManagerShutdown).not.toHaveBeenCalled() }) + + test("#given uncaughtException handler registered #when manager is unregistered via unregisterManagerForCleanup #then subsequent events do not invoke that manager", () => { + const uncaughtExceptionListenersBefore = process.listeners("uncaughtException") + const shutdown = mock(() => {}) + const manager = { shutdown } + registeredManagers.push(manager) + + registerManagerForCleanup(manager) + expect(process.listeners("uncaughtException")).toHaveLength( + uncaughtExceptionListenersBefore.length + 1, + ) + + unregisterManagerForCleanup(manager) + registeredManagers.length = 0 + process.emit("uncaughtException", new Error("boom")) + + expect(shutdown).not.toHaveBeenCalled() + }) + }) + + describe("#given uncaught exception and rejection cleanup", () => { + test("#given manager registered AND process emits uncaughtException #when event fires #then manager.shutdown() called AND process.exitCode set to 1", async () => { + const exitSpy = spyOn(process, "exit").mockImplementation((code?: number): never => { + throw new Error(`Unexpected process.exit(${String(code)})`) + }) + const shutdown = mock(() => {}) + const manager = { shutdown } + registeredManagers.push(manager) + + try { + registerManagerForCleanup(manager) + + process.emit("uncaughtException", new Error("boom")) + await flushMicrotasks() + + expect(shutdown).toHaveBeenCalledTimes(1) + expect(process.exitCode).toBe(1) + expect(exitSpy).not.toHaveBeenCalled() + } finally { + exitSpy.mockRestore() + } + }) + + test("#given manager registered AND process emits unhandledRejection #when event fires #then manager.shutdown() called AND process.exitCode set to 1", async () => { + const exitSpy = spyOn(process, "exit").mockImplementation((code?: number): never => { + throw new Error(`Unexpected process.exit(${String(code)})`) + }) + const shutdown = mock(() => {}) + const manager = { shutdown } + registeredManagers.push(manager) + + try { + registerManagerForCleanup(manager) + + process.emit("unhandledRejection", new Error("boom"), Promise.resolve()) + await flushMicrotasks() + + expect(shutdown).toHaveBeenCalledTimes(1) + expect(process.exitCode).toBe(1) + expect(exitSpy).not.toHaveBeenCalled() + } finally { + exitSpy.mockRestore() + } + }) + + test("#given _resetForTesting() called #when event fires #then no cleanup runs", () => { + const uncaughtExceptionListenersBefore = process.listeners("uncaughtException") + const shutdown = mock(() => {}) + const manager = { shutdown } + + registerManagerForCleanup(manager) + expect(process.listeners("uncaughtException")).toHaveLength( + uncaughtExceptionListenersBefore.length + 1, + ) + + _resetForTesting() + process.emit("uncaughtException", new Error("boom")) + + expect(shutdown).not.toHaveBeenCalled() + expect(process.listeners("uncaughtException")).toHaveLength( + uncaughtExceptionListenersBefore.length, + ) + }) }) }) diff --git a/src/features/background-agent/process-cleanup.ts b/src/features/background-agent/process-cleanup.ts index 29be1958e..20f8fab00 100644 --- a/src/features/background-agent/process-cleanup.ts +++ b/src/features/background-agent/process-cleanup.ts @@ -1,33 +1,51 @@ import { log } from "../../shared" -type ProcessCleanupEvent = NodeJS.Signals | "beforeExit" | "exit" +type ProcessCleanupSignal = NodeJS.Signals | "beforeExit" | "exit" +type ProcessCleanupErrorEvent = "uncaughtException" | "unhandledRejection" + +function scheduleForcedExit(cleanupResult: void | Promise, exitCode: number): void { + process.exitCode = exitCode + const exitTimeout = setTimeout(() => process.exit(), 6000) + void Promise.resolve(cleanupResult).finally(() => { + clearTimeout(exitTimeout) + }) +} function registerProcessSignal( - signal: ProcessCleanupEvent, + signal: ProcessCleanupSignal, handler: () => void | Promise, exitAfter: boolean ): () => void { const listener = () => { const cleanupResult = handler() if (exitAfter) { - process.exitCode = 0 - const exitTimeout = setTimeout(() => process.exit(), 6000) - void Promise.resolve(cleanupResult).finally(() => { - clearTimeout(exitTimeout) - }) + scheduleForcedExit(cleanupResult, 0) } } process.on(signal, listener) return listener } +function registerErrorEvent( + signal: ProcessCleanupErrorEvent, + handler: (error: unknown) => void | Promise +): (error: unknown) => void { + const listener = (error: unknown) => { + log(`[background-agent] ${signal} received during shutdown cleanup:`, error) + scheduleForcedExit(handler(error), 1) + } + process.on(signal, listener) + return listener +} + interface CleanupTarget { shutdown(): void | Promise } const cleanupManagers = new Set() let cleanupRegistered = false -const cleanupHandlers = new Map void>() +const cleanupSignalHandlers = new Map void>() +const cleanupErrorHandlers = new Map void>() export function registerManagerForCleanup(manager: CleanupTarget): void { cleanupManagers.add(manager) @@ -59,9 +77,9 @@ export function registerManagerForCleanup(manager: CleanupTarget): void { return cleanupPromise } - const registerSignal = (signal: ProcessCleanupEvent, exitAfter: boolean): void => { + const registerSignal = (signal: ProcessCleanupSignal, exitAfter: boolean): void => { const listener = registerProcessSignal(signal, cleanupAll, exitAfter) - cleanupHandlers.set(signal, listener) + cleanupSignalHandlers.set(signal, listener) } registerSignal("SIGINT", true) @@ -71,6 +89,8 @@ export function registerManagerForCleanup(manager: CleanupTarget): void { } registerSignal("beforeExit", false) registerSignal("exit", false) + cleanupErrorHandlers.set("uncaughtException", registerErrorEvent("uncaughtException", cleanupAll)) + cleanupErrorHandlers.set("unhandledRejection", registerErrorEvent("unhandledRejection", cleanupAll)) } export function unregisterManagerForCleanup(manager: CleanupTarget): void { @@ -78,10 +98,14 @@ export function unregisterManagerForCleanup(manager: CleanupTarget): void { if (cleanupManagers.size > 0) return - for (const [signal, listener] of cleanupHandlers.entries()) { + for (const [signal, listener] of cleanupSignalHandlers.entries()) { process.off(signal, listener) } - cleanupHandlers.clear() + for (const [signal, listener] of cleanupErrorHandlers.entries()) { + process.off(signal, listener) + } + cleanupSignalHandlers.clear() + cleanupErrorHandlers.clear() cleanupRegistered = false } @@ -90,9 +114,13 @@ export function _resetForTesting(): void { for (const manager of [...cleanupManagers]) { cleanupManagers.delete(manager) } - for (const [signal, listener] of cleanupHandlers.entries()) { + for (const [signal, listener] of cleanupSignalHandlers.entries()) { process.off(signal, listener) } - cleanupHandlers.clear() + for (const [signal, listener] of cleanupErrorHandlers.entries()) { + process.off(signal, listener) + } + cleanupSignalHandlers.clear() + cleanupErrorHandlers.clear() cleanupRegistered = false } From ea4f3c81f47d24ca25f927a6cd0be11506c0845c Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:34:54 +0900 Subject: [PATCH 106/146] fix(tmux): treat pane-already-closed as success in closeTmuxPane After send-keys C-c the subprocess running inside the pane (for example "opencode attach") exits on SIGINT, which causes tmux to destroy the pane automatically. The subsequent kill-pane then returns exit 1 with stderr "can't find pane: %NN" even though the end state is exactly what we wanted. Before this fix closeTmuxPane reported failure for that branch, which kept TmuxSessionManager's retryPendingCloses loop marking the (now deleted) pane as still-pending forever and left stale entries behind in the tracked sessions map. This is the behavior the user observed as "screen opens, streaming runs, but cleanup doesn't finish" when running with tmux.isolation="session". Now we detect the "can't find pane" stderr and return true, treating the auto-destroy path the same as an explicit successful kill. --- src/shared/tmux/tmux-utils/pane-close.test.ts | 26 ++++++++++++++++++- src/shared/tmux/tmux-utils/pane-close.ts | 18 +++++++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/shared/tmux/tmux-utils/pane-close.test.ts b/src/shared/tmux/tmux-utils/pane-close.test.ts index ca5d74684..b8d5d7887 100644 --- a/src/shared/tmux/tmux-utils/pane-close.test.ts +++ b/src/shared/tmux/tmux-utils/pane-close.test.ts @@ -170,7 +170,7 @@ describe("closeTmuxPane", () => { expect(spawnCalls).toHaveLength(0) }) - it("#given kill-pane fails #when closeTmuxPane called #then returns false", async () => { + it("#given kill-pane fails with unknown error #when closeTmuxPane called #then returns false", async () => { // given const closeTmuxPane = await loadCloseTmuxPane() queuedProcesses.push(createProcess(0), createProcess(1)) @@ -182,6 +182,30 @@ describe("closeTmuxPane", () => { expect(result).toBe(false) }) + it("#given pane already closed by Ctrl+C (kill-pane reports 'can't find pane') #when closeTmuxPane called #then returns true", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push( + createProcess(0), + { + exited: Promise.resolve(1), + stdout: createClosedStream(), + stderr: new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode("can't find pane: %42\n")) + controller.close() + }, + }), + }, + ) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(true) + }) + it("#given kill-pane stdout stream waits for drain #when closeTmuxPane called #then returns true once drainer consumes stdout", async () => { // given const closeTmuxPane = await loadCloseTmuxPane() diff --git a/src/shared/tmux/tmux-utils/pane-close.ts b/src/shared/tmux/tmux-utils/pane-close.ts index 76d9dd11b..e62e46296 100644 --- a/src/shared/tmux/tmux-utils/pane-close.ts +++ b/src/shared/tmux/tmux-utils/pane-close.ts @@ -46,11 +46,19 @@ export async function closeTmuxPane(paneId: string): Promise { killPaneProc.exited, ]) - if (exitCode !== 0) { - log("[closeTmuxPane] FAILED", { paneId, exitCode, stderr: stderr.trim() }) - } else { - log("[closeTmuxPane] SUCCESS", { paneId }) + const trimmedStderr = stderr.trim() + const paneAlreadyGone = exitCode !== 0 && /can't find pane/i.test(trimmedStderr) + + if (paneAlreadyGone) { + log("[closeTmuxPane] SUCCESS (pane already closed by Ctrl+C)", { paneId }) + return true } - return exitCode === 0 + if (exitCode !== 0) { + log("[closeTmuxPane] FAILED", { paneId, exitCode, stderr: trimmedStderr }) + return false + } + + log("[closeTmuxPane] SUCCESS", { paneId }) + return true } From f8a1a11bb7ce56b5f8a453b8d5ac4fe82eef3c9d Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:42:19 +0900 Subject: [PATCH 107/146] fix(team-mode): refactor layout to use testable spawn-process helper The existing layout.test.ts relied on mock.module("bun", ...) registered at the top level, but test-setup.ts calls mock.restore() + restoreModuleMocks() in afterEach, so every test except the first one lost its mocks. CI has been red on this file since e303feef. Two changes: 1. layout.ts now imports spawn from the existing spawn-process helper instead of "bun" directly, matching the pattern established for closeTmuxPane and killTmuxSessionIfExists. This does not change runtime behavior - spawn-process just re-exports Bun's spawn. 2. layout.test.ts registers module mocks inside beforeEach and uses the ?test=UUID cache-busting dynamic-import pattern so the mocks apply on every test run, not just the first. All 4 layout.test.ts cases now pass. --- .../team-mode/team-layout-tmux/layout.test.ts | 26 +++++++++++++++---- .../team-mode/team-layout-tmux/layout.ts | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/features/team-mode/team-layout-tmux/layout.test.ts b/src/features/team-mode/team-layout-tmux/layout.test.ts index c23f878f4..aa9a90ff5 100644 --- a/src/features/team-mode/team-layout-tmux/layout.test.ts +++ b/src/features/team-mode/team-layout-tmux/layout.test.ts @@ -1,21 +1,32 @@ import { beforeEach, describe, expect, mock, test } from "bun:test" +type LayoutModule = typeof import("./layout") + const spawnMock = mock(() => ({ exited: Promise.resolve(0), stdout: new ReadableStream({ start(controller) { controller.enqueue(new TextEncoder().encode("%1\n")); controller.close() } }), stderr: new ReadableStream({ start(controller) { controller.close() } }), })) -mock.module("bun", () => ({ spawn: spawnMock })) +const layoutSpecifier = import.meta.resolve("./layout") +const spawnProcessSpecifier = import.meta.resolve("../../../shared/tmux/tmux-utils/spawn-process") +const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") +const sharedSpecifier = import.meta.resolve("../../../shared") -mock.module("../../../tools/interactive-bash/tmux-path-resolver", () => ({ getTmuxPath: mock(() => Promise.resolve("tmux")) })) +function registerModuleMocks(): void { + mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) + mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: mock(() => Promise.resolve("tmux")) })) + mock.module(sharedSpecifier, () => ({ log: mock(() => undefined) })) +} -mock.module("../../../shared", () => ({ log: mock(() => undefined) })) - -import { createTeamLayout, removeTeamLayout, canVisualize } from "./layout" +async function loadLayoutModule(): Promise { + const module = await import(`${layoutSpecifier}?test=${crypto.randomUUID()}`) + return module as LayoutModule +} describe("team-layout-tmux", () => { beforeEach(() => { + registerModuleMocks() spawnMock.mockClear() process.env.TMUX = "/tmp/tmux-1" }) @@ -23,6 +34,7 @@ describe("team-layout-tmux", () => { test("returns null and makes no tmux calls when visualization unavailable", async () => { // given delete process.env.TMUX + const { createTeamLayout, canVisualize } = await loadLayoutModule() // when const result = await createTeamLayout("run-1", [], {} as never) @@ -35,6 +47,7 @@ describe("team-layout-tmux", () => { test("creates focus and grid windows", async () => { // given + const { createTeamLayout } = await loadLayoutModule() const members = [ { name: "lead", sessionId: "s1", color: "red" }, { name: "m2", sessionId: "s2" }, @@ -54,6 +67,7 @@ describe("team-layout-tmux", () => { test("returns null when tmux command fails", async () => { // given + const { createTeamLayout } = await loadLayoutModule() spawnMock.mockImplementationOnce(() => ({ exited: Promise.resolve(1), stdout: new ReadableStream({ start(controller) { controller.close() } }), @@ -69,6 +83,8 @@ describe("team-layout-tmux", () => { test("cleans up the tmux session", async () => { // given + const { removeTeamLayout } = await loadLayoutModule() + // when await removeTeamLayout("run-4", {} as never) diff --git a/src/features/team-mode/team-layout-tmux/layout.ts b/src/features/team-mode/team-layout-tmux/layout.ts index b41354d06..f414ccbfe 100644 --- a/src/features/team-mode/team-layout-tmux/layout.ts +++ b/src/features/team-mode/team-layout-tmux/layout.ts @@ -1,4 +1,4 @@ -import { spawn } from "bun" +import { spawn } from "../../../shared/tmux/tmux-utils/spawn-process" import { log } from "../../../shared" import { getTmuxPath } from "../../../tools/interactive-bash/tmux-path-resolver" import type { TmuxSessionManager } from "../../tmux-subagent/manager" From 257b6cf951d442a4d5c451b33c77bae0b919cdce Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:47:36 +0900 Subject: [PATCH 108/146] fix(tmux): scope isolated session name per plugin instance (Oracle review) Oracle flagged the previous commit: "omo-agents" was a shared constant, so when two plugin instances ran in the same tmux server they wrote into the same session. One instance's cleanup would then kill-session on the shared name and tear down the other instance's live attached panes. Replace the const ISOLATED_SESSION_NAME with getIsolatedSessionName(pid) which defaults to process.pid, so every opencode process owns its own "omo-agents-" session. spawnTmuxSession and cleanup both resolve the name through this helper. Discovery is straightforward from the host tmux via 'tmux list-sessions | grep omo-agents-'. Manager test covers two concurrent managers and asserts each kills a per-pid session name, proving they no longer collide on a global name. --- src/features/tmux-subagent/manager.test.ts | 31 +++++++++++++++++++-- src/features/tmux-subagent/manager.ts | 9 +++--- src/shared/tmux/tmux-utils.ts | 2 +- src/shared/tmux/tmux-utils/session-spawn.ts | 17 +++++++---- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index f828ff9d7..9a03d7641 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -101,7 +101,7 @@ mock.module('../../shared/tmux', () => { spawnTmuxWindow: mockSpawnTmuxWindow, spawnTmuxSession: mockSpawnTmuxSession, killTmuxSessionIfExists: mockKillTmuxSessionIfExists, - ISOLATED_SESSION_NAME: 'omo-agents', + getIsolatedSessionName: (pid: number = 12345) => `omo-agents-${pid}`, } }) @@ -1856,7 +1856,7 @@ describe('TmuxSessionManager', () => { expect(mockExecuteAction).toHaveBeenCalledTimes(2) }) - test('#given tmux isolation is "session" #when cleanup runs #then killTmuxSessionIfExists is invoked for the isolated session', async () => { + test('#given tmux isolation is "session" #when cleanup runs #then killTmuxSessionIfExists is invoked for the per-pid isolated session', async () => { // given mockKillTmuxSessionIfExists.mockClear() const { TmuxSessionManager } = await import('./manager') @@ -1870,7 +1870,32 @@ describe('TmuxSessionManager', () => { // then expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(1) - expect(mockKillTmuxSessionIfExists).toHaveBeenCalledWith('omo-agents') + expect(mockKillTmuxSessionIfExists.mock.calls[0]?.[0]).toMatch(/^omo-agents-\d+$/) + }) + + test('#given two manager instances #when both cleanup #then each kills its own isolated session name, not a shared one', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const managerA = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + const managerB = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await managerA.cleanup() + await managerB.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(2) + const firstTarget = mockKillTmuxSessionIfExists.mock.calls[0]?.[0] + const secondTarget = mockKillTmuxSessionIfExists.mock.calls[1]?.[0] + expect(firstTarget).toMatch(/^omo-agents-\d+$/) + expect(secondTarget).toMatch(/^omo-agents-\d+$/) }) test('#given tmux isolation is "inline" #when cleanup runs #then killTmuxSessionIfExists is NOT invoked', async () => { diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index ee1b8b508..9d9c65159 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -11,7 +11,7 @@ import { spawnTmuxWindow, spawnTmuxSession, killTmuxSessionIfExists, - ISOLATED_SESSION_NAME, + getIsolatedSessionName, } from "../../shared/tmux" import { queryWindowState } from "./pane-state-querier" import { decideSpawnActions, decideCloseAction, type SessionMapping } from "./decision-engine" @@ -970,15 +970,16 @@ export class TmuxSessionManager { this.isolatedWindowPaneId = undefined if (this.tmuxConfig.isolation === "session") { + const isolatedSessionName = getIsolatedSessionName() try { - const killed = await killTmuxSessionIfExists(ISOLATED_SESSION_NAME) + const killed = await killTmuxSessionIfExists(isolatedSessionName) log("[tmux-session-manager] isolated session teardown", { - session: ISOLATED_SESSION_NAME, + session: isolatedSessionName, killed, }) } catch (error) { log("[tmux-session-manager] isolated session teardown failed", { - session: ISOLATED_SESSION_NAME, + session: isolatedSessionName, error: String(error), }) } diff --git a/src/shared/tmux/tmux-utils.ts b/src/shared/tmux/tmux-utils.ts index 587704536..d80d1e720 100644 --- a/src/shared/tmux/tmux-utils.ts +++ b/src/shared/tmux/tmux-utils.ts @@ -10,7 +10,7 @@ export { spawnTmuxPane } from "./tmux-utils/pane-spawn" export { closeTmuxPane } from "./tmux-utils/pane-close" export { replaceTmuxPane } from "./tmux-utils/pane-replace" export { spawnTmuxWindow } from "./tmux-utils/window-spawn" -export { spawnTmuxSession, ISOLATED_SESSION_NAME } from "./tmux-utils/session-spawn" +export { spawnTmuxSession, getIsolatedSessionName } from "./tmux-utils/session-spawn" export { killTmuxSessionIfExists } from "./tmux-utils/session-kill" export { applyLayout, enforceMainPaneWidth } from "./tmux-utils/layout" diff --git a/src/shared/tmux/tmux-utils/session-spawn.ts b/src/shared/tmux/tmux-utils/session-spawn.ts index dd9f5addd..a6fd15d2d 100644 --- a/src/shared/tmux/tmux-utils/session-spawn.ts +++ b/src/shared/tmux/tmux-utils/session-spawn.ts @@ -6,7 +6,11 @@ import { isInsideTmux } from "./environment" import { isServerRunning } from "./server-health" import { shellEscapeForDoubleQuotedCommand } from "../../shell-env" -export const ISOLATED_SESSION_NAME = "omo-agents" +const ISOLATED_SESSION_NAME_PREFIX = "omo-agents" + +export function getIsolatedSessionName(pid: number = process.pid): string { + return `${ISOLATED_SESSION_NAME_PREFIX}-${pid}` +} async function getWindowDimensions( tmux: string, @@ -87,12 +91,13 @@ export async function spawnTmuxSession( } } - const sessionAlreadyExists = await sessionExists(tmux, ISOLATED_SESSION_NAME) + const isolatedSessionName = getIsolatedSessionName() + const sessionAlreadyExists = await sessionExists(tmux, isolatedSessionName) const args = sessionAlreadyExists ? [ "new-window", - "-t", ISOLATED_SESSION_NAME, + "-t", isolatedSessionName, "-P", "-F", "#{pane_id}", opencodeCmd, @@ -100,7 +105,7 @@ export async function spawnTmuxSession( : [ "new-session", "-d", - "-s", ISOLATED_SESSION_NAME, + "-s", isolatedSessionName, ...sizeArgs, "-P", "-F", "#{pane_id}", @@ -109,7 +114,7 @@ export async function spawnTmuxSession( log("[spawnTmuxSession] spawning", { mode: sessionAlreadyExists ? "new-window" : "new-session", - sessionName: ISOLATED_SESSION_NAME, + sessionName: isolatedSessionName, }) const proc = spawn([tmux, ...args], { stdout: "pipe", stderr: "pipe" }) @@ -140,6 +145,6 @@ export async function spawnTmuxSession( }) } - log("[spawnTmuxSession] SUCCESS", { paneId, sessionName: ISOLATED_SESSION_NAME }) + log("[spawnTmuxSession] SUCCESS", { paneId, sessionName: isolatedSessionName }) return { success: true, paneId } } From aa79284dc56860cec0ab837251533625f2cb1d34 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 19:57:26 +0900 Subject: [PATCH 109/146] fix(background-agent): reset process.exitCode to 0 between cleanup tests CI test suite exited 1 despite 0 failing tests because process-cleanup.test.ts assertions left process.exitCode=1 in place. The afterEach hook only reset to originalExitCode (which starts undefined), not 0, so Bun picked up exitCode=1 on shutdown and reported the shared batch as failing. Explicitly set process.exitCode = 0 in beforeEach and afterEach so each test starts and ends with a clean exit state. --- src/features/background-agent/process-cleanup.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/features/background-agent/process-cleanup.test.ts b/src/features/background-agent/process-cleanup.test.ts index 4d2975fe0..a9ce35435 100644 --- a/src/features/background-agent/process-cleanup.test.ts +++ b/src/features/background-agent/process-cleanup.test.ts @@ -15,10 +15,9 @@ type CleanupManager = { describe("#given process cleanup registration", () => { const registeredManagers: CleanupManager[] = [] - const originalExitCode = process.exitCode beforeEach(() => { - process.exitCode = originalExitCode + process.exitCode = 0 registeredManagers.length = 0 _resetForTesting() }) @@ -28,7 +27,7 @@ describe("#given process cleanup registration", () => { unregisterManagerForCleanup(manager) } - process.exitCode = originalExitCode + process.exitCode = 0 _resetForTesting() }) From 104523051d0f8c70fcdd0150af8eb7349f8e6df5 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 20:22:00 +0900 Subject: [PATCH 110/146] feat(tmux): sweep stale omo-agents- sessions on first spawn Follow-up to PR #3507 addressing the Oracle-noted operational limitation: per-PID isolated session names (getIsolatedSessionName(process.pid)) mean that when an opencode process is SIGKILL'd (or the machine hard-reboots), the old omo-agents- tmux session survives forever because nothing is around to kill it. Added sweepStaleOmoAgentSessions() that: 1. Lists tmux sessions matching /^omo-agents-(\d+)$/ 2. For each, checks process.kill(pid, 0) to detect a dead PID 3. Skips our own PID 4. Calls killTmuxSessionIfExists for every session whose owner process is gone Wired into TmuxSessionManager.onSessionCreated() as a one-shot (guarded by staleSweepCompleted flag) so it runs lazily on the first subagent spawn when isolation="session". The flag is reset in cleanup() so subsequent process restarts re-run the sweep. 6 new tests cover: outside-tmux no-op, no matching sessions, multiple dead PIDs, current PID skip, live PID skip, list-sessions failure. Manual E2E verified on real tmux: - Created omo-agents-99999, sweep killed it - Spawned our own omo-agents-, closeTmuxPane returned true even after pane auto-destroy from Ctrl+C - Final tmux list-sessions shows zero omo-agents-* orphans --- src/features/tmux-subagent/manager.test.ts | 2 + src/features/tmux-subagent/manager.ts | 25 +++ src/shared/tmux/tmux-utils.ts | 1 + .../tmux-utils/stale-session-sweep.test.ts | 183 ++++++++++++++++++ .../tmux/tmux-utils/stale-session-sweep.ts | 72 +++++++ 5 files changed, 283 insertions(+) create mode 100644 src/shared/tmux/tmux-utils/stale-session-sweep.test.ts create mode 100644 src/shared/tmux/tmux-utils/stale-session-sweep.ts diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 9a03d7641..485a47acc 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -58,6 +58,7 @@ const mockSpawnTmuxSession = mock<( paneId: '%isolated-session', })) const mockKillTmuxSessionIfExists = mock<(sessionName: string) => Promise>(async () => true) +const mockSweepStaleOmoAgentSessions = mock<() => Promise>(async () => 0) const mockIsInsideTmux = mock<() => boolean>(() => true) const mockGetCurrentPaneId = mock<() => string | undefined>(() => '%0') @@ -102,6 +103,7 @@ mock.module('../../shared/tmux', () => { spawnTmuxSession: mockSpawnTmuxSession, killTmuxSessionIfExists: mockKillTmuxSessionIfExists, getIsolatedSessionName: (pid: number = 12345) => `omo-agents-${pid}`, + sweepStaleOmoAgentSessions: mockSweepStaleOmoAgentSessions, } }) diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index 9d9c65159..1091033e4 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -12,6 +12,7 @@ import { spawnTmuxSession, killTmuxSessionIfExists, getIsolatedSessionName, + sweepStaleOmoAgentSessions, } from "../../shared/tmux" import { queryWindowState } from "./pane-state-querier" import { decideSpawnActions, decideCloseAction, type SessionMapping } from "./decision-engine" @@ -65,6 +66,7 @@ export class TmuxSessionManager { private isolatedContainerPaneId: string | undefined private isolatedWindowPaneId: string | undefined private isolatedContainerNullStateCount = 0 + private staleSweepCompleted = false constructor(ctx: PluginInput, tmuxConfig: TmuxConfig, deps: TmuxUtilDeps = defaultTmuxDeps) { this.client = ctx.client this.tmuxConfig = tmuxConfig @@ -668,6 +670,7 @@ export class TmuxSessionManager { return } + await this.sweepStaleIsolatedSessionsOnce() await this.retryPendingCloses() if ( @@ -985,6 +988,28 @@ export class TmuxSessionManager { } } + this.staleSweepCompleted = false + } + + private async sweepStaleIsolatedSessionsOnce(): Promise { + if (this.staleSweepCompleted) return + if (this.tmuxConfig.isolation !== "session") { + this.staleSweepCompleted = true + return + } + + this.staleSweepCompleted = true + try { + const killed = await sweepStaleOmoAgentSessions() + if (killed > 0) { + log("[tmux-session-manager] stale isolated sessions swept", { killed }) + } + } catch (error) { + log("[tmux-session-manager] stale sweep failed", { + error: String(error), + }) + } + log("[tmux-session-manager] cleanup complete") } } diff --git a/src/shared/tmux/tmux-utils.ts b/src/shared/tmux/tmux-utils.ts index d80d1e720..6ccdeed31 100644 --- a/src/shared/tmux/tmux-utils.ts +++ b/src/shared/tmux/tmux-utils.ts @@ -12,5 +12,6 @@ export { replaceTmuxPane } from "./tmux-utils/pane-replace" export { spawnTmuxWindow } from "./tmux-utils/window-spawn" export { spawnTmuxSession, getIsolatedSessionName } from "./tmux-utils/session-spawn" export { killTmuxSessionIfExists } from "./tmux-utils/session-kill" +export { sweepStaleOmoAgentSessions } from "./tmux-utils/stale-session-sweep" export { applyLayout, enforceMainPaneWidth } from "./tmux-utils/layout" diff --git a/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts new file mode 100644 index 000000000..d79b6b3b8 --- /dev/null +++ b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts @@ -0,0 +1,183 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test" + +type SweepStaleOmoAgentSessions = typeof import("./stale-session-sweep").sweepStaleOmoAgentSessions + +type SpawnCall = { command: string[] } + +type FakeSubprocess = { + exited: Promise + stdout: ReadableStream + stderr: ReadableStream +} + +const spawnCalls: SpawnCall[] = [] +const queuedProcesses: FakeSubprocess[] = [] + +function createClosedStream(): ReadableStream { + return new ReadableStream({ start(controller) { controller.close() } }) +} + +function createTextStream(text: string): ReadableStream { + return new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode(text)) + controller.close() + }, + }) +} + +function makeProcess(exitCode: number, stdoutText: string): FakeSubprocess { + return { + exited: Promise.resolve(exitCode), + stdout: createTextStream(stdoutText), + stderr: createClosedStream(), + } +} + +const spawnMock = mock((command: string[]): FakeSubprocess => { + spawnCalls.push({ command }) + const process = queuedProcesses.shift() + if (!process) { + throw new Error(`No fake subprocess configured for ${command.join(" ")}`) + } + return process +}) + +const isInsideTmuxMock = mock((): boolean => true) +const getTmuxPathMock = mock(async (): Promise => "tmux") +const logMock = mock(() => undefined) +const killTmuxSessionMock = mock(async (_name: string): Promise => true) +const isProcessAliveMock = mock((_pid: number): boolean => false) + +const sweepSpecifier = import.meta.resolve("./stale-session-sweep") +const spawnProcessSpecifier = import.meta.resolve("./spawn-process") +const environmentSpecifier = import.meta.resolve("./environment") +const loggerSpecifier = import.meta.resolve("../../logger") +const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") +const sessionKillSpecifier = import.meta.resolve("./session-kill") + +function registerModuleMocks(): void { + mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) + mock.module(environmentSpecifier, () => ({ isInsideTmux: isInsideTmuxMock })) + mock.module(loggerSpecifier, () => ({ log: logMock })) + mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: getTmuxPathMock })) + mock.module(sessionKillSpecifier, () => ({ killTmuxSessionIfExists: killTmuxSessionMock })) +} + +async function loadSweeper(overrideProcessAlive?: (pid: number) => boolean): Promise { + const originalKill = process.kill + const processAlive = overrideProcessAlive ?? isProcessAliveMock + process.kill = ((pid: number, signal?: number | string): true => { + if (signal === 0) { + if (processAlive(pid)) { + return true + } + const err = new Error("ESRCH") as NodeJS.ErrnoException + err.code = "ESRCH" + throw err + } + return originalKill.call(process, pid, signal) + }) as typeof process.kill + const module = await import(`${sweepSpecifier}?test=${crypto.randomUUID()}`) + return module.sweepStaleOmoAgentSessions +} + +describe("sweepStaleOmoAgentSessions", () => { + beforeEach(() => { + registerModuleMocks() + spawnCalls.length = 0 + queuedProcesses.length = 0 + spawnMock.mockClear() + isInsideTmuxMock.mockClear() + getTmuxPathMock.mockClear() + logMock.mockClear() + killTmuxSessionMock.mockClear() + isProcessAliveMock.mockClear() + + isInsideTmuxMock.mockImplementation((): boolean => true) + getTmuxPathMock.mockImplementation(async (): Promise => "tmux") + killTmuxSessionMock.mockImplementation(async (_name: string): Promise => true) + isProcessAliveMock.mockImplementation((_pid: number): boolean => false) + }) + + it("#given not inside tmux #when sweepStaleOmoAgentSessions called #then returns 0 without spawn", async () => { + // given + isInsideTmuxMock.mockImplementation((): boolean => false) + const sweep = await loadSweeper() + + // when + const result = await sweep() + + // then + expect(result).toBe(0) + expect(spawnCalls).toHaveLength(0) + }) + + it("#given no omo-agents sessions exist #when sweepStaleOmoAgentSessions called #then returns 0", async () => { + // given + queuedProcesses.push(makeProcess(0, "other-session\nmain\n")) + const sweep = await loadSweeper() + + // when + const result = await sweep() + + // then + expect(result).toBe(0) + expect(killTmuxSessionMock).toHaveBeenCalledTimes(0) + }) + + it("#given omo-agents sessions with dead PIDs #when sweepStaleOmoAgentSessions called #then each dead session is killed", async () => { + // given + queuedProcesses.push(makeProcess(0, "omo-agents-99991\nomo-agents-99992\nunrelated\n")) + const sweep = await loadSweeper(() => false) + + // when + const result = await sweep() + + // then + expect(result).toBe(2) + expect(killTmuxSessionMock).toHaveBeenCalledTimes(2) + expect(killTmuxSessionMock.mock.calls[0]?.[0]).toBe("omo-agents-99991") + expect(killTmuxSessionMock.mock.calls[1]?.[0]).toBe("omo-agents-99992") + }) + + it("#given session matches current PID #when sweepStaleOmoAgentSessions called #then it is not killed", async () => { + // given + queuedProcesses.push(makeProcess(0, `omo-agents-${process.pid}\nomo-agents-99999\n`)) + const sweep = await loadSweeper(() => false) + + // when + const result = await sweep() + + // then + expect(result).toBe(1) + expect(killTmuxSessionMock).toHaveBeenCalledTimes(1) + expect(killTmuxSessionMock.mock.calls[0]?.[0]).toBe("omo-agents-99999") + }) + + it("#given session PID is still alive #when sweepStaleOmoAgentSessions called #then it is not killed", async () => { + // given + queuedProcesses.push(makeProcess(0, "omo-agents-88888\n")) + const sweep = await loadSweeper((pid) => pid === 88888) + + // when + const result = await sweep() + + // then + expect(result).toBe(0) + expect(killTmuxSessionMock).toHaveBeenCalledTimes(0) + }) + + it("#given list-sessions fails #when sweepStaleOmoAgentSessions called #then returns 0 without killing", async () => { + // given + queuedProcesses.push(makeProcess(1, "")) + const sweep = await loadSweeper(() => false) + + // when + const result = await sweep() + + // then + expect(result).toBe(0) + expect(killTmuxSessionMock).toHaveBeenCalledTimes(0) + }) +}) diff --git a/src/shared/tmux/tmux-utils/stale-session-sweep.ts b/src/shared/tmux/tmux-utils/stale-session-sweep.ts new file mode 100644 index 000000000..f2c790161 --- /dev/null +++ b/src/shared/tmux/tmux-utils/stale-session-sweep.ts @@ -0,0 +1,72 @@ +const STALE_SESSION_PATTERN = /^omo-agents-(\d+)$/ + +function isProcessAlive(pid: number): boolean { + try { + process.kill(pid, 0) + return true + } catch (error) { + const err = error as NodeJS.ErrnoException + return err?.code === "EPERM" + } +} + +async function listOmoAgentSessions(tmux: string): Promise { + const { spawn } = await import("./spawn-process") + const proc = spawn([tmux, "list-sessions", "-F", "#{session_name}"], { + stdout: "pipe", + stderr: "pipe", + }) + const [stdout, , exitCode] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + proc.exited, + ]) + + if (exitCode !== 0) { + return [] + } + + return stdout + .split("\n") + .map((line) => line.trim()) + .filter((name) => STALE_SESSION_PATTERN.test(name)) +} + +export async function sweepStaleOmoAgentSessions(): Promise { + const [{ log }, { isInsideTmux }, { getTmuxPath }, { killTmuxSessionIfExists }] = await Promise.all([ + import("../../logger"), + import("./environment"), + import("../../../tools/interactive-bash/tmux-path-resolver"), + import("./session-kill"), + ]) + + if (!isInsideTmux()) { + return 0 + } + + const tmux = await getTmuxPath() + if (!tmux) { + return 0 + } + + const candidateSessions = await listOmoAgentSessions(tmux) + let killedCount = 0 + + for (const sessionName of candidateSessions) { + const pidMatch = sessionName.match(STALE_SESSION_PATTERN) + if (!pidMatch) continue + + const pid = Number.parseInt(pidMatch[1], 10) + if (!Number.isFinite(pid)) continue + if (pid === process.pid) continue + if (isProcessAlive(pid)) continue + + log("[sweepStaleOmoAgentSessions] killing stale session", { sessionName, deadPid: pid }) + const killed = await killTmuxSessionIfExists(sessionName) + if (killed) { + killedCount += 1 + } + } + + return killedCount +} From 3dce19d173b150ced1ea000c59ef517f8202f4dd Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 20:27:48 +0900 Subject: [PATCH 111/146] fix(tmux-subagent): move 'cleanup complete' log back to cleanup() method The log line was misplaced at the end of sweepStaleIsolatedSessionsOnce where it said 'cleanup complete' after the stale sweep, which was misleading. Per Oracle review. --- src/features/tmux-subagent/manager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index 1091033e4..7b9d92d81 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -989,6 +989,8 @@ export class TmuxSessionManager { } this.staleSweepCompleted = false + + log("[tmux-session-manager] cleanup complete") } private async sweepStaleIsolatedSessionsOnce(): Promise { @@ -1009,7 +1011,5 @@ export class TmuxSessionManager { error: String(error), }) } - - log("[tmux-session-manager] cleanup complete") } } From 859d67f41eb483a0d87e73adbe070c030c3e8390 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 20:37:49 +0900 Subject: [PATCH 112/146] fix(tmux-subagent): revert session.error cleanup (recoverable-error regression) Oracle flagged a regression introduced in PR #3507 commit 21554be8: event.ts routed session.error through tmux pane cleanup BEFORE the existing session-recovery / model-fallback logic ran. Problem: when session.error was recoverable (context window limit, quota rate limit, provider fallback), the recovery/fallback code would successfully continue the SAME session - but by then its tmux pane had already been destroyed. User-visible symptom is exactly the original complaint - 'screen appears but streaming stops working' after an auto-retry. Fix is the minimal revert: remove the onSessionError funnel from event.ts and drop onSessionError from the manager. Fatal errors that actually end a session still fire session.deleted, which continues to trigger cleanup correctly. Non-fatal error streams stay attached to the surviving pane. --- src/features/tmux-subagent/manager.test.ts | 37 ---------------------- src/features/tmux-subagent/manager.ts | 12 ------- src/plugin/event.ts | 4 --- 3 files changed, 53 deletions(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 485a47acc..84c7bc441 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -1932,43 +1932,6 @@ describe('TmuxSessionManager', () => { expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(0) }) - test('#given a tracked session #when onSessionError is invoked #then the pane is closed like onSessionDeleted', async () => { - // given - mockIsInsideTmux.mockReturnValue(true) - mockExecuteAction.mockClear() - const { TmuxSessionManager } = await import('./manager') - const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ - enabled: true, - isolation: 'session', - }), mockTmuxDeps) - await manager.onSessionCreated(createSessionCreatedEvent('ses_err', 'ses_parent', 'Errored Task')) - mockExecuteAction.mockClear() - - // when - await manager.onSessionError({ sessionID: 'ses_err' }) - - // then - expect(mockExecuteAction).toHaveBeenCalled() - }) - - test('#given an untracked session #when onSessionError is invoked #then it is a no-op and does not throw', async () => { - // given - mockIsInsideTmux.mockReturnValue(true) - mockExecuteAction.mockClear() - const { TmuxSessionManager } = await import('./manager') - const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ - enabled: true, - isolation: 'session', - }), mockTmuxDeps) - - // when - const errorHandler = manager.onSessionError({ sessionID: 'ses_unknown' }) - - // then - await expect(errorHandler).resolves.toBeUndefined() - expect(mockExecuteAction).not.toHaveBeenCalled() - }) - test('#given killTmuxSessionIfExists throws #when cleanup runs #then cleanup still completes without throwing', async () => { // given mockKillTmuxSessionIfExists.mockClear() diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index 7b9d92d81..5734ff822 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -838,18 +838,6 @@ export class TmuxSessionManager { await this.spawnQueue } - async onSessionError(event: { sessionID: string }): Promise { - if (!this.isEnabled()) return - if (!this.getEffectiveSourcePaneId()) return - if (!this.sessions.has(event.sessionID)) return - - log("[tmux-session-manager] onSessionError - routing to cleanup", { - sessionId: event.sessionID, - }) - - await this.onSessionDeleted(event) - } - async onSessionDeleted(event: { sessionID: string }): Promise { if (!this.isEnabled()) return if (!this.getEffectiveSourcePaneId()) return diff --git a/src/plugin/event.ts b/src/plugin/event.ts index 0f79a84d5..5a5f177b6 100644 --- a/src/plugin/event.ts +++ b/src/plugin/event.ts @@ -615,10 +615,6 @@ export function createEventHandler(args: { const sessionID = props?.sessionID as string | undefined; const error = props?.error; - if (tmuxIntegrationEnabled && sessionID) { - await managers.tmuxSessionManager.onSessionError({ sessionID }); - } - const errorName = extractErrorName(error); const errorMessage = extractErrorMessage(error); const errorInfo = { name: errorName, message: errorMessage }; From 913fac05f5f0314ab1cdd857d5f72e777de90282 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 20:45:21 +0900 Subject: [PATCH 113/146] fix(tmux-subagent): retry stale sweep if first attempt throws Oracle flagged: staleSweepCompleted was set to true BEFORE sweepStaleOmoAgentSessions() ran, so any throw from the first invocation would permanently disable stale cleanup for the rest of the process lifetime. Fix: - Move staleSweepCompleted=true into the try-block success branch. - Add staleSweepInProgress guard so concurrent onSessionCreated calls do not invoke sweep twice in parallel (sweep is idempotent, but the guard prevents doubled log noise). - finally{} clears the inProgress flag regardless of outcome. - cleanup() resets both flags. Two new tests cover: retry after a thrown first attempt, and single invocation when subsequent spawns follow a successful first sweep. --- src/features/tmux-subagent/manager.test.ts | 41 ++++++++++++++++++++++ src/features/tmux-subagent/manager.ts | 8 ++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 84c7bc441..e63f4bf4d 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -1932,6 +1932,47 @@ describe('TmuxSessionManager', () => { expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(0) }) + test('#given sweepStaleOmoAgentSessions throws on first onSessionCreated #when second onSessionCreated fires #then sweep is retried instead of skipped forever', async () => { + // given + mockSweepStaleOmoAgentSessions.mockClear() + mockSweepStaleOmoAgentSessions.mockImplementationOnce(async () => { + throw new Error('simulated sweep failure') + }) + mockIsInsideTmux.mockReturnValue(true) + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await manager.onSessionCreated(createSessionCreatedEvent('ses_first', 'ses_parent', 'First')) + await manager.onSessionCreated(createSessionCreatedEvent('ses_second', 'ses_parent', 'Second')) + + // then + expect(mockSweepStaleOmoAgentSessions).toHaveBeenCalledTimes(2) + }) + + test('#given sweepStaleOmoAgentSessions succeeds #when additional onSessionCreated events fire in same process #then sweep runs exactly once', async () => { + // given + mockSweepStaleOmoAgentSessions.mockClear() + mockSweepStaleOmoAgentSessions.mockImplementation(async () => 0) + mockIsInsideTmux.mockReturnValue(true) + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await manager.onSessionCreated(createSessionCreatedEvent('ses_a', 'ses_parent', 'A')) + await manager.onSessionCreated(createSessionCreatedEvent('ses_b', 'ses_parent', 'B')) + await manager.onSessionCreated(createSessionCreatedEvent('ses_c', 'ses_parent', 'C')) + + // then + expect(mockSweepStaleOmoAgentSessions).toHaveBeenCalledTimes(1) + }) + test('#given killTmuxSessionIfExists throws #when cleanup runs #then cleanup still completes without throwing', async () => { // given mockKillTmuxSessionIfExists.mockClear() diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index 5734ff822..3340fb55d 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -67,6 +67,7 @@ export class TmuxSessionManager { private isolatedWindowPaneId: string | undefined private isolatedContainerNullStateCount = 0 private staleSweepCompleted = false + private staleSweepInProgress = false constructor(ctx: PluginInput, tmuxConfig: TmuxConfig, deps: TmuxUtilDeps = defaultTmuxDeps) { this.client = ctx.client this.tmuxConfig = tmuxConfig @@ -977,27 +978,32 @@ export class TmuxSessionManager { } this.staleSweepCompleted = false + this.staleSweepInProgress = false log("[tmux-session-manager] cleanup complete") } private async sweepStaleIsolatedSessionsOnce(): Promise { if (this.staleSweepCompleted) return + if (this.staleSweepInProgress) return if (this.tmuxConfig.isolation !== "session") { this.staleSweepCompleted = true return } - this.staleSweepCompleted = true + this.staleSweepInProgress = true try { const killed = await sweepStaleOmoAgentSessions() if (killed > 0) { log("[tmux-session-manager] stale isolated sessions swept", { killed }) } + this.staleSweepCompleted = true } catch (error) { log("[tmux-session-manager] stale sweep failed", { error: String(error), }) + } finally { + this.staleSweepInProgress = false } } } From d1fc46da42211079244a6896f8626bf3aa813d6c Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 20:51:24 +0900 Subject: [PATCH 114/146] test(tmux): restore process.kill in afterEach to prevent cross-file leak Oracle noted that loadSweeper() monkey-patches process.kill without ever restoring it. Added afterEach hook to set process.kill back to the captured original. Individual file runs already passed, and script/run-ci-tests.ts confirms the full CI suite - 4781 pass, 0 fail across 491 files - but this makes the test file safe under non-isolated local runs as well. --- .../tmux/tmux-utils/stale-session-sweep.test.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts index d79b6b3b8..98f6aa1f8 100644 --- a/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts +++ b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, mock } from "bun:test" +import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" type SweepStaleOmoAgentSessions = typeof import("./stale-session-sweep").sweepStaleOmoAgentSessions @@ -64,8 +64,9 @@ function registerModuleMocks(): void { mock.module(sessionKillSpecifier, () => ({ killTmuxSessionIfExists: killTmuxSessionMock })) } +const originalProcessKill = process.kill + async function loadSweeper(overrideProcessAlive?: (pid: number) => boolean): Promise { - const originalKill = process.kill const processAlive = overrideProcessAlive ?? isProcessAliveMock process.kill = ((pid: number, signal?: number | string): true => { if (signal === 0) { @@ -76,7 +77,7 @@ async function loadSweeper(overrideProcessAlive?: (pid: number) => boolean): Pro err.code = "ESRCH" throw err } - return originalKill.call(process, pid, signal) + return originalProcessKill.call(process, pid, signal) }) as typeof process.kill const module = await import(`${sweepSpecifier}?test=${crypto.randomUUID()}`) return module.sweepStaleOmoAgentSessions @@ -100,6 +101,10 @@ describe("sweepStaleOmoAgentSessions", () => { isProcessAliveMock.mockImplementation((_pid: number): boolean => false) }) + afterEach(() => { + process.kill = originalProcessKill + }) + it("#given not inside tmux #when sweepStaleOmoAgentSessions called #then returns 0 without spawn", async () => { // given isInsideTmuxMock.mockImplementation((): boolean => false) From e35ac38bbfca4fbae8c390f04e9a6554f7ab0de9 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 18 Apr 2026 21:00:34 +0900 Subject: [PATCH 115/146] test(tmux): rewrite stale-sweep tests via DI to eliminate cross-file mock leak Oracle flagged that the previous test file monkey-patched process.kill and relied on mock.module for 5 modules. Running it after manager.test.ts in the same Bun process reproduced 2 failures - the test resolution of `./session-kill` specifier interacted badly with manager.test.ts's `../../shared/tmux` barrel mock. Solution: refactor stale-session-sweep.ts to expose `sweepStaleOmoAgentSessionsWith(deps)` that accepts a SweepDeps record (isInsideTmux, getTmuxPath, listCandidateSessions, killSession, processAlive, currentPid, log). The public `sweepStaleOmoAgentSessions()` still uses runtime-built deps so call sites are unchanged. The test file now imports the pure function directly and constructs a fixture with fake deps. Zero mock.module calls, zero process.kill patching, zero cache-bust dynamic imports. 8 tests (up from 6) run deterministically in any order with any neighbor. Before: combined run with manager.test.ts = 2 fail, 50 pass. After: combined run with manager.test.ts = 0 fail, 54 pass. --- .../tmux-utils/stale-session-sweep.test.ts | 218 ++++++++---------- .../tmux/tmux-utils/stale-session-sweep.ts | 45 +++- 2 files changed, 128 insertions(+), 135 deletions(-) diff --git a/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts index 98f6aa1f8..1acc171ed 100644 --- a/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts +++ b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts @@ -1,188 +1,154 @@ -import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" +import { beforeEach, describe, expect, it, mock } from "bun:test" +import { sweepStaleOmoAgentSessionsWith, type SweepDeps } from "./stale-session-sweep" -type SweepStaleOmoAgentSessions = typeof import("./stale-session-sweep").sweepStaleOmoAgentSessions - -type SpawnCall = { command: string[] } - -type FakeSubprocess = { - exited: Promise - stdout: ReadableStream - stderr: ReadableStream +type SweepFixture = { + deps: SweepDeps + candidates: string[] + killed: string[] + killSessionMock: ReturnType + setCandidates: (sessions: string[]) => void + setAlive: (predicate: (pid: number) => boolean) => void } -const spawnCalls: SpawnCall[] = [] -const queuedProcesses: FakeSubprocess[] = [] +function createFixture(): SweepFixture { + const candidates: string[] = [] + const killed: string[] = [] + let aliveCheck: (pid: number) => boolean = () => false -function createClosedStream(): ReadableStream { - return new ReadableStream({ start(controller) { controller.close() } }) -} - -function createTextStream(text: string): ReadableStream { - return new ReadableStream({ - start(controller) { - controller.enqueue(new TextEncoder().encode(text)) - controller.close() - }, + const killSessionMock = mock(async (sessionName: string): Promise => { + killed.push(sessionName) + return true }) -} -function makeProcess(exitCode: number, stdoutText: string): FakeSubprocess { + const deps: SweepDeps = { + isInsideTmux: () => true, + getTmuxPath: async () => "tmux", + listCandidateSessions: async () => [...candidates], + killSession: killSessionMock, + processAlive: (pid) => aliveCheck(pid), + currentPid: 12345, + log: () => undefined, + } + return { - exited: Promise.resolve(exitCode), - stdout: createTextStream(stdoutText), - stderr: createClosedStream(), + deps, + candidates, + killed, + killSessionMock, + setCandidates: (sessions) => { + candidates.length = 0 + candidates.push(...sessions) + }, + setAlive: (predicate) => { + aliveCheck = predicate + }, } } -const spawnMock = mock((command: string[]): FakeSubprocess => { - spawnCalls.push({ command }) - const process = queuedProcesses.shift() - if (!process) { - throw new Error(`No fake subprocess configured for ${command.join(" ")}`) - } - return process -}) +describe("sweepStaleOmoAgentSessionsWith", () => { + let fixture: SweepFixture -const isInsideTmuxMock = mock((): boolean => true) -const getTmuxPathMock = mock(async (): Promise => "tmux") -const logMock = mock(() => undefined) -const killTmuxSessionMock = mock(async (_name: string): Promise => true) -const isProcessAliveMock = mock((_pid: number): boolean => false) - -const sweepSpecifier = import.meta.resolve("./stale-session-sweep") -const spawnProcessSpecifier = import.meta.resolve("./spawn-process") -const environmentSpecifier = import.meta.resolve("./environment") -const loggerSpecifier = import.meta.resolve("../../logger") -const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") -const sessionKillSpecifier = import.meta.resolve("./session-kill") - -function registerModuleMocks(): void { - mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) - mock.module(environmentSpecifier, () => ({ isInsideTmux: isInsideTmuxMock })) - mock.module(loggerSpecifier, () => ({ log: logMock })) - mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: getTmuxPathMock })) - mock.module(sessionKillSpecifier, () => ({ killTmuxSessionIfExists: killTmuxSessionMock })) -} - -const originalProcessKill = process.kill - -async function loadSweeper(overrideProcessAlive?: (pid: number) => boolean): Promise { - const processAlive = overrideProcessAlive ?? isProcessAliveMock - process.kill = ((pid: number, signal?: number | string): true => { - if (signal === 0) { - if (processAlive(pid)) { - return true - } - const err = new Error("ESRCH") as NodeJS.ErrnoException - err.code = "ESRCH" - throw err - } - return originalProcessKill.call(process, pid, signal) - }) as typeof process.kill - const module = await import(`${sweepSpecifier}?test=${crypto.randomUUID()}`) - return module.sweepStaleOmoAgentSessions -} - -describe("sweepStaleOmoAgentSessions", () => { beforeEach(() => { - registerModuleMocks() - spawnCalls.length = 0 - queuedProcesses.length = 0 - spawnMock.mockClear() - isInsideTmuxMock.mockClear() - getTmuxPathMock.mockClear() - logMock.mockClear() - killTmuxSessionMock.mockClear() - isProcessAliveMock.mockClear() - - isInsideTmuxMock.mockImplementation((): boolean => true) - getTmuxPathMock.mockImplementation(async (): Promise => "tmux") - killTmuxSessionMock.mockImplementation(async (_name: string): Promise => true) - isProcessAliveMock.mockImplementation((_pid: number): boolean => false) + fixture = createFixture() }) - afterEach(() => { - process.kill = originalProcessKill - }) - - it("#given not inside tmux #when sweepStaleOmoAgentSessions called #then returns 0 without spawn", async () => { + it("#given not inside tmux #when sweep called #then returns 0 without listing", async () => { // given - isInsideTmuxMock.mockImplementation((): boolean => false) - const sweep = await loadSweeper() + const deps: SweepDeps = { ...fixture.deps, isInsideTmux: () => false } // when - const result = await sweep() + const result = await sweepStaleOmoAgentSessionsWith(deps) // then expect(result).toBe(0) - expect(spawnCalls).toHaveLength(0) }) - it("#given no omo-agents sessions exist #when sweepStaleOmoAgentSessions called #then returns 0", async () => { + it("#given tmux not found #when sweep called #then returns 0 without listing", async () => { // given - queuedProcesses.push(makeProcess(0, "other-session\nmain\n")) - const sweep = await loadSweeper() + const deps: SweepDeps = { ...fixture.deps, getTmuxPath: async () => undefined } // when - const result = await sweep() + const result = await sweepStaleOmoAgentSessionsWith(deps) // then expect(result).toBe(0) - expect(killTmuxSessionMock).toHaveBeenCalledTimes(0) }) - it("#given omo-agents sessions with dead PIDs #when sweepStaleOmoAgentSessions called #then each dead session is killed", async () => { + it("#given candidate list is empty #when sweep called #then returns 0 and does not kill anything", async () => { // given - queuedProcesses.push(makeProcess(0, "omo-agents-99991\nomo-agents-99992\nunrelated\n")) - const sweep = await loadSweeper(() => false) + fixture.setCandidates([]) // when - const result = await sweep() + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(0) + expect(fixture.killed).toEqual([]) + }) + + it("#given sessions with dead PIDs #when sweep called #then each dead session is killed once", async () => { + // given + fixture.setCandidates(["omo-agents-99991", "omo-agents-99992"]) + fixture.setAlive(() => false) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) // then expect(result).toBe(2) - expect(killTmuxSessionMock).toHaveBeenCalledTimes(2) - expect(killTmuxSessionMock.mock.calls[0]?.[0]).toBe("omo-agents-99991") - expect(killTmuxSessionMock.mock.calls[1]?.[0]).toBe("omo-agents-99992") + expect(fixture.killed).toEqual(["omo-agents-99991", "omo-agents-99992"]) }) - it("#given session matches current PID #when sweepStaleOmoAgentSessions called #then it is not killed", async () => { + it("#given session matches current PID #when sweep called #then it is NOT killed", async () => { // given - queuedProcesses.push(makeProcess(0, `omo-agents-${process.pid}\nomo-agents-99999\n`)) - const sweep = await loadSweeper(() => false) + fixture.setCandidates([`omo-agents-${fixture.deps.currentPid}`, "omo-agents-99999"]) + fixture.setAlive(() => false) // when - const result = await sweep() + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) // then expect(result).toBe(1) - expect(killTmuxSessionMock).toHaveBeenCalledTimes(1) - expect(killTmuxSessionMock.mock.calls[0]?.[0]).toBe("omo-agents-99999") + expect(fixture.killed).toEqual(["omo-agents-99999"]) }) - it("#given session PID is still alive #when sweepStaleOmoAgentSessions called #then it is not killed", async () => { + it("#given session PID is still alive #when sweep called #then it is NOT killed", async () => { // given - queuedProcesses.push(makeProcess(0, "omo-agents-88888\n")) - const sweep = await loadSweeper((pid) => pid === 88888) + fixture.setCandidates(["omo-agents-88888"]) + fixture.setAlive((pid) => pid === 88888) // when - const result = await sweep() + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) // then expect(result).toBe(0) - expect(killTmuxSessionMock).toHaveBeenCalledTimes(0) + expect(fixture.killed).toEqual([]) }) - it("#given list-sessions fails #when sweepStaleOmoAgentSessions called #then returns 0 without killing", async () => { + it("#given killSession returns false #when sweep called #then session is not counted toward killedCount", async () => { // given - queuedProcesses.push(makeProcess(1, "")) - const sweep = await loadSweeper(() => false) + fixture.setCandidates(["omo-agents-55555"]) + fixture.setAlive(() => false) + fixture.killSessionMock.mockImplementation(async () => false) // when - const result = await sweep() + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) // then expect(result).toBe(0) - expect(killTmuxSessionMock).toHaveBeenCalledTimes(0) + expect(fixture.killSessionMock).toHaveBeenCalledTimes(1) + }) + + it("#given non-matching sessions mixed in #when sweep called #then only omo-agents- sessions are considered", async () => { + // given + fixture.setCandidates(["main", "omo-agents-99999", "other-session", "omo-agents-abc"]) + fixture.setAlive(() => false) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(1) + expect(fixture.killed).toEqual(["omo-agents-99999"]) }) }) diff --git a/src/shared/tmux/tmux-utils/stale-session-sweep.ts b/src/shared/tmux/tmux-utils/stale-session-sweep.ts index f2c790161..c8b27e938 100644 --- a/src/shared/tmux/tmux-utils/stale-session-sweep.ts +++ b/src/shared/tmux/tmux-utils/stale-session-sweep.ts @@ -10,7 +10,7 @@ function isProcessAlive(pid: number): boolean { } } -async function listOmoAgentSessions(tmux: string): Promise { +async function listOmoAgentSessionsViaTmux(tmux: string): Promise { const { spawn } = await import("./spawn-process") const proc = spawn([tmux, "list-sessions", "-F", "#{session_name}"], { stdout: "pipe", @@ -32,7 +32,17 @@ async function listOmoAgentSessions(tmux: string): Promise { .filter((name) => STALE_SESSION_PATTERN.test(name)) } -export async function sweepStaleOmoAgentSessions(): Promise { +export type SweepDeps = { + isInsideTmux: () => boolean + getTmuxPath: () => Promise + listCandidateSessions: (tmux: string) => Promise + killSession: (sessionName: string) => Promise + processAlive: (pid: number) => boolean + currentPid: number + log: (message: string, payload?: unknown) => void +} + +async function buildRuntimeDeps(): Promise { const [{ log }, { isInsideTmux }, { getTmuxPath }, { killTmuxSessionIfExists }] = await Promise.all([ import("../../logger"), import("./environment"), @@ -40,16 +50,28 @@ export async function sweepStaleOmoAgentSessions(): Promise { import("./session-kill"), ]) - if (!isInsideTmux()) { + return { + isInsideTmux, + getTmuxPath, + listCandidateSessions: listOmoAgentSessionsViaTmux, + killSession: killTmuxSessionIfExists, + processAlive: isProcessAlive, + currentPid: process.pid, + log, + } +} + +export async function sweepStaleOmoAgentSessionsWith(deps: SweepDeps): Promise { + if (!deps.isInsideTmux()) { return 0 } - const tmux = await getTmuxPath() + const tmux = await deps.getTmuxPath() if (!tmux) { return 0 } - const candidateSessions = await listOmoAgentSessions(tmux) + const candidateSessions = await deps.listCandidateSessions(tmux) let killedCount = 0 for (const sessionName of candidateSessions) { @@ -58,11 +80,11 @@ export async function sweepStaleOmoAgentSessions(): Promise { const pid = Number.parseInt(pidMatch[1], 10) if (!Number.isFinite(pid)) continue - if (pid === process.pid) continue - if (isProcessAlive(pid)) continue + if (pid === deps.currentPid) continue + if (deps.processAlive(pid)) continue - log("[sweepStaleOmoAgentSessions] killing stale session", { sessionName, deadPid: pid }) - const killed = await killTmuxSessionIfExists(sessionName) + deps.log("[sweepStaleOmoAgentSessions] killing stale session", { sessionName, deadPid: pid }) + const killed = await deps.killSession(sessionName) if (killed) { killedCount += 1 } @@ -70,3 +92,8 @@ export async function sweepStaleOmoAgentSessions(): Promise { return killedCount } + +export async function sweepStaleOmoAgentSessions(): Promise { + const deps = await buildRuntimeDeps() + return sweepStaleOmoAgentSessionsWith(deps) +} From ef5c74e972a99501adaa540813c1f9094945745c Mon Sep 17 00:00:00 2001 From: William Obino Date: Sat, 18 Apr 2026 17:49:05 +0300 Subject: [PATCH 116/146] fix(cli): inject server auth for attach clients --- src/cli/run/server-connection.ts | 5 +++++ src/shared/opencode-server-auth.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cli/run/server-connection.ts b/src/cli/run/server-connection.ts index bf658ff05..f4af3ddcd 100644 --- a/src/cli/run/server-connection.ts +++ b/src/cli/run/server-connection.ts @@ -1,6 +1,7 @@ import { createOpencode, createOpencodeClient } from "@opencode-ai/sdk" import pc from "picocolors" import type { ServerConnection } from "./types" +import { injectServerAuthIntoClient } from "../../shared/opencode-server-auth" import { getAvailableServerPort, isPortAvailable, DEFAULT_SERVER_PORT } from "../../shared/port-utils" import { withWorkingOpencodePath } from "./opencode-binary-resolver" @@ -40,6 +41,7 @@ export async function createServerConnection(options: { if (attach !== undefined) { console.log(pc.dim("Attaching to existing server at"), pc.cyan(attach)) const client = createOpencodeClient({ baseUrl: attach }) + injectServerAuthIntoClient(client) return { client, cleanup: () => {} } } @@ -66,12 +68,14 @@ export async function createServerConnection(options: { console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("became occupied, attaching to existing server")) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` }) + injectServerAuthIntoClient(client) return { client, cleanup: () => {} } } } console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("is occupied, attaching to existing server")) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` }) + injectServerAuthIntoClient(client) return { client, cleanup: () => {} } } @@ -93,6 +97,7 @@ export async function createServerConnection(options: { console.log(pc.dim("Port range exhausted, attaching to existing server on"), pc.cyan(DEFAULT_SERVER_PORT.toString())) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` }) + injectServerAuthIntoClient(client) return { client, cleanup: () => {} } } diff --git a/src/shared/opencode-server-auth.ts b/src/shared/opencode-server-auth.ts index 8d4957512..02ebfa928 100644 --- a/src/shared/opencode-server-auth.ts +++ b/src/shared/opencode-server-auth.ts @@ -78,7 +78,7 @@ function tryInjectViaInterceptors(internal: UnknownRecord, auth: string): boolea return false } - use((request: Request): Request => { + use.call(requestInterceptors, (request: Request): Request => { if (!request.headers.get("Authorization")) { request.headers.set("Authorization", auth) } From ad0ee7abcd435bef91995aa233ddd4f4bb34e49c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:55:59 +0000 Subject: [PATCH 117/146] @andomeder has signed the CLA in code-yeongyu/oh-my-openagent#3514 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index 26b3ef0e1..cb1e65fe9 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2871,6 +2871,14 @@ "created_at": "2026-04-18T04:24:37Z", "repoId": 1108837393, "pullRequestNo": 3499 + }, + { + "name": "andomeder", + "id": 33397443, + "comment_id": 4273945668, + "created_at": "2026-04-18T14:55:50Z", + "repoId": 1108837393, + "pullRequestNo": 3514 } ] } \ No newline at end of file From 69315fcad7516818f4a8a7d09e3fd91a7937e636 Mon Sep 17 00:00:00 2001 From: William Obino Date: Sat, 18 Apr 2026 18:12:58 +0300 Subject: [PATCH 118/146] fix(cli): restrict attach auth injection to loopback URLs --- src/cli/run/server-connection.test.ts | 58 +++++++++++++++++++++++++-- src/cli/run/server-connection.ts | 15 ++++++- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/cli/run/server-connection.test.ts b/src/cli/run/server-connection.test.ts index 90bad1812..2cd4ed660 100644 --- a/src/cli/run/server-connection.test.ts +++ b/src/cli/run/server-connection.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect, mock, beforeEach, afterEach, afterAll } from "bun import * as originalSdk from "@opencode-ai/sdk" import * as originalPortUtils from "../../shared/port-utils" import * as originalBinaryResolver from "./opencode-binary-resolver" +import * as originalServerAuth from "../../shared/opencode-server-auth" const originalConsole = globalThis.console @@ -13,11 +14,15 @@ const mockCreateOpencode = mock(() => server: { url: "http://127.0.0.1:4096", close: mockServerClose }, }) ) -const mockCreateOpencodeClient = mock(() => ({ session: {} })) +const mockCreateOpencodeClient = mock((options?: { baseUrl?: string }) => ({ + session: {}, + baseUrl: options?.baseUrl, +})) const mockIsPortAvailable = mock(() => Promise.resolve(true)) const mockGetAvailableServerPort = mock(() => Promise.resolve({ port: 4096, wasAutoSelected: false })) const mockConsoleLog = mock(() => {}) const mockWithWorkingOpencodePath = mock((startServer: () => Promise) => startServer()) +const mockInjectServerAuthIntoClient = mock(() => {}) mock.module("@opencode-ai/sdk", () => ({ createOpencode: mockCreateOpencode, @@ -34,10 +39,15 @@ mock.module("./opencode-binary-resolver", () => ({ withWorkingOpencodePath: mockWithWorkingOpencodePath, })) +mock.module("../../shared/opencode-server-auth", () => ({ + injectServerAuthIntoClient: mockInjectServerAuthIntoClient, +})) + afterAll(() => { mock.module("@opencode-ai/sdk", () => originalSdk) mock.module("../../shared/port-utils", () => originalPortUtils) mock.module("./opencode-binary-resolver", () => originalBinaryResolver) + mock.module("../../shared/opencode-server-auth", () => originalServerAuth) mock.restore() }) @@ -52,6 +62,7 @@ describe("createServerConnection", () => { mockServerClose.mockClear() mockConsoleLog.mockClear() mockWithWorkingOpencodePath.mockClear() + mockInjectServerAuthIntoClient.mockClear() globalThis.console = { ...console, log: mockConsoleLog } as typeof console }) @@ -59,6 +70,49 @@ describe("createServerConnection", () => { globalThis.console = originalConsole }) + it("attach mode injects auth only for loopback URLs", async () => { + // given + const signal = new AbortController().signal + + // when + const localhostResult = await createServerConnection({ attach: "http://localhost:8080", signal }) + const loopbackResult = await createServerConnection({ attach: "http://127.0.0.1:8080", signal }) + const anyBindResult = await createServerConnection({ attach: "http://0.0.0.0:8080", signal }) + const remoteResult = await createServerConnection({ attach: "https://example.com", signal }) + + // then + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://localhost:8080" }) + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://127.0.0.1:8080" }) + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://0.0.0.0:8080" }) + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "https://example.com" }) + expect(mockInjectServerAuthIntoClient).toHaveBeenCalledTimes(3) + expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(1, localhostResult.client) + expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(2, loopbackResult.client) + expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(3, anyBindResult.client) + expect(mockInjectServerAuthIntoClient).not.toHaveBeenCalledWith(remoteResult.client) + expect(mockWithWorkingOpencodePath).not.toHaveBeenCalled() + localhostResult.cleanup() + loopbackResult.cleanup() + anyBindResult.cleanup() + remoteResult.cleanup() + expect(mockServerClose).not.toHaveBeenCalled() + }) + + it("attach mode skips auth injection for invalid attach URLs", async () => { + // given + const signal = new AbortController().signal + const attachUrl = "not-a-url" + + // when + const result = await createServerConnection({ attach: attachUrl, signal }) + + // then + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: attachUrl }) + expect(mockInjectServerAuthIntoClient).not.toHaveBeenCalled() + result.cleanup() + expect(mockServerClose).not.toHaveBeenCalled() + }) + it("attach mode returns client with no-op cleanup", async () => { // given const signal = new AbortController().signal @@ -68,8 +122,6 @@ describe("createServerConnection", () => { const result = await createServerConnection({ attach: attachUrl, signal }) // then - expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: attachUrl }) - expect(mockWithWorkingOpencodePath).not.toHaveBeenCalled() expect(result.client).toBeDefined() expect(result.cleanup).toBeDefined() result.cleanup() diff --git a/src/cli/run/server-connection.ts b/src/cli/run/server-connection.ts index f4af3ddcd..f92aa1a08 100644 --- a/src/cli/run/server-connection.ts +++ b/src/cli/run/server-connection.ts @@ -5,6 +5,17 @@ import { injectServerAuthIntoClient } from "../../shared/opencode-server-auth" import { getAvailableServerPort, isPortAvailable, DEFAULT_SERVER_PORT } from "../../shared/port-utils" import { withWorkingOpencodePath } from "./opencode-binary-resolver" +const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]", "0.0.0.0"]) + +function isLoopbackAttachUrl(url: string): boolean { + try { + const parsed = new URL(url) + return LOOPBACK_HOSTS.has(parsed.hostname) + } catch { + return false + } +} + function isPortStartFailure(error: unknown, port: number): boolean { if (!(error instanceof Error)) { return false @@ -41,7 +52,9 @@ export async function createServerConnection(options: { if (attach !== undefined) { console.log(pc.dim("Attaching to existing server at"), pc.cyan(attach)) const client = createOpencodeClient({ baseUrl: attach }) - injectServerAuthIntoClient(client) + if (isLoopbackAttachUrl(attach)) { + injectServerAuthIntoClient(client) + } return { client, cleanup: () => {} } } From 869accd11b2ccb4bb6cf903067f014ec41069e84 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 03:28:31 +0000 Subject: [PATCH 119/146] @CoderLuii has signed the CLA in code-yeongyu/oh-my-openagent#3518 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index cb1e65fe9..d6c62243a 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2879,6 +2879,14 @@ "created_at": "2026-04-18T14:55:50Z", "repoId": 1108837393, "pullRequestNo": 3514 + }, + { + "name": "CoderLuii", + "id": 203967356, + "comment_id": 4275088581, + "created_at": "2026-04-19T03:28:19Z", + "repoId": 1108837393, + "pullRequestNo": 3518 } ] } \ No newline at end of file From 9bf89deee3bfe996fc5bd01c5da9343f2e00026f Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 14:49:35 +0900 Subject: [PATCH 120/146] test(delegate-task): add failing tests for metadata continuation gaps Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../metadata-task-id-consistency.test.ts | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/src/tools/delegate-task/metadata-task-id-consistency.test.ts b/src/tools/delegate-task/metadata-task-id-consistency.test.ts index c9a2a0b8c..1f0d985d5 100644 --- a/src/tools/delegate-task/metadata-task-id-consistency.test.ts +++ b/src/tools/delegate-task/metadata-task-id-consistency.test.ts @@ -151,6 +151,55 @@ describe("taskId and backgroundTaskId metadata consistency", () => { expect(meta.metadata.sessionId).toBe("ses_resumed_x") expect(meta.metadata.backgroundTaskId).toBe("bg_resumed_y") }) + + test("#when resumed task has category #then metadata.category equals task.category", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed_x", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resumed_y", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_x", model: MODEL, category: "deep", + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.category).toBe("deep") + }) + + test("#when publishing metadata with requested_subagent_type #then metadata.requested_subagent_type preserves original", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args = { + description: "continue", + prompt: "keep going", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: true, + task_id: "ses_resumed_x", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resumed_y", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_x", model: MODEL, + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) }) describe("#given sync-continuation runs", () => { @@ -183,6 +232,201 @@ describe("taskId and backgroundTaskId metadata consistency", () => { expect(meta.metadata.taskId).toBe("ses_cont_abc") expect(meta.metadata.sessionId).toBe("ses_cont_abc") }) + + test("#when resumeAgent is resolved #then metadata.agent equals resumeAgent", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont_abc", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.agent).toBe("explore") + }) + + test("#when called with category arg #then metadata.category equals args.category", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + category: "quick", load_skills: [], run_in_background: false, task_id: "ses_cont", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.category).toBe("quick") + }) + + test("#when publishing metadata with requested_subagent_type #then metadata.requested_subagent_type preserves original", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args = { + description: "continue", + prompt: "keep going", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: false, + task_id: "ses_cont", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + }) + + describe("#given user calls with requested_subagent_type plus category", () => { + test("#when sync-task publishes metadata #then metadata.requested_subagent_type preserves original", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args = { + description: "test", + prompt: "do it", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "Sisyphus-Junior", MODEL, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + + test("#when background-task publishes metadata #then metadata.requested_subagent_type preserves original", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args = { + description: "test", + prompt: "do it", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: true, + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_abc123", description: "test", agent: "Sisyphus-Junior", + status: "pending", sessionID: "ses_xyz789", + }), + getTask: () => undefined, + }, + } as any, parentContext, "Sisyphus-Junior", MODEL, undefined) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + + test("#when unstable-agent-task publishes metadata #then metadata.requested_subagent_type preserves original", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args = { + description: "test", + prompt: "do it", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable_abc", description: "test", agent: "Sisyphus-Junior", + status: "completed", sessionID: "ses_unstable_xyz", + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable_xyz: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "Sisyphus-Junior", MODEL, undefined, "anthropic/claude-sonnet-4-6", + ) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) }) describe("#given background_output runs", () => { From 9bd5829a764e748a527c952f4c1530550c147e43 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 14:50:11 +0900 Subject: [PATCH 121/146] fix(delegate-task): propagate agent and category in sync continuation Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/sync-continuation.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index 5ec1406b0..d7c39f36e 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -76,6 +76,8 @@ export async function executeSyncContinuation( title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, + ...(resumeAgent !== undefined ? { agent: resumeAgent } : {}), + ...(args.category !== undefined ? { category: args.category } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, From 8a2a11b2108639b9a914b05ad8e905dd0db76d8d Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 14:50:18 +0900 Subject: [PATCH 122/146] fix(delegate-task): propagate category in background continuation Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/background-continuation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 90ea1398b..52f262b90 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -36,6 +36,7 @@ export async function executeBackgroundContinuation( metadata: { prompt: args.prompt, agent: task.agent, + ...(task.category !== undefined ? { category: task.category } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, From f486df71aeec55ae9fc0b61708b538818b9892e9 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 14:50:40 +0900 Subject: [PATCH 123/146] feat(delegate-task): preserve raw subagent_type across metadata Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/background-continuation.ts | 1 + src/tools/delegate-task/background-task.ts | 1 + src/tools/delegate-task/sync-continuation.ts | 1 + src/tools/delegate-task/sync-task.ts | 1 + src/tools/delegate-task/tool-argument-preparation.ts | 2 ++ src/tools/delegate-task/types.ts | 1 + src/tools/delegate-task/unstable-agent-task.ts | 1 + 7 files changed, 8 insertions(+) diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 52f262b90..4c500d5dd 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -37,6 +37,7 @@ export async function executeBackgroundContinuation( prompt: args.prompt, agent: task.agent, ...(task.category !== undefined ? { category: task.category } : {}), + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index d5c4adf5d..2f767b477 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -125,6 +125,7 @@ export async function executeBackgroundTask( prompt: args.prompt, agent: task.agent, category: args.category, + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index d7c39f36e..a99f6ff39 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -78,6 +78,7 @@ export async function executeSyncContinuation( prompt: args.prompt, ...(resumeAgent !== undefined ? { agent: resumeAgent } : {}), ...(args.category !== undefined ? { category: args.category } : {}), + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 034c0e199..e1b5e2cba 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -120,6 +120,7 @@ export async function executeSyncTask( prompt: args.prompt, agent: agentToUse, category: args.category, + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, diff --git a/src/tools/delegate-task/tool-argument-preparation.ts b/src/tools/delegate-task/tool-argument-preparation.ts index d54b12ca6..8f529230b 100644 --- a/src/tools/delegate-task/tool-argument-preparation.ts +++ b/src/tools/delegate-task/tool-argument-preparation.ts @@ -60,6 +60,7 @@ export async function prepareDelegateTaskArgs(args: Record, ctx args.category = category args.subagent_type = subagentType + args.requested_subagent_type = originalSubagentType args.description = description args.prompt = prompt args.run_in_background = runInBackground @@ -70,6 +71,7 @@ export async function prepareDelegateTaskArgs(args: Record, ctx return { category, subagent_type: subagentType, + requested_subagent_type: originalSubagentType, description, prompt, run_in_background: runInBackground === true, diff --git a/src/tools/delegate-task/types.ts b/src/tools/delegate-task/types.ts index 9eff782ce..affd81983 100644 --- a/src/tools/delegate-task/types.ts +++ b/src/tools/delegate-task/types.ts @@ -14,6 +14,7 @@ export interface DelegateTaskArgs { prompt: string category?: string subagent_type?: string + requested_subagent_type?: string run_in_background: boolean task_id?: string command?: string diff --git a/src/tools/delegate-task/unstable-agent-task.ts b/src/tools/delegate-task/unstable-agent-task.ts index 7afffdeee..bc4011fbe 100644 --- a/src/tools/delegate-task/unstable-agent-task.ts +++ b/src/tools/delegate-task/unstable-agent-task.ts @@ -74,6 +74,7 @@ export async function executeUnstableAgentTask( prompt: args.prompt, agent: agentToUse, category: args.category, + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, From a82f0560cc685025a17647f8e08873a60b76fc95 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 14:50:35 +0900 Subject: [PATCH 124/146] test(delegate-task): add failing tests for model variant preservation Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../metadata-model-unification.test.ts | 145 ++++++++++++++++++ .../resolve-metadata-model.test.ts | 45 +++++- 2 files changed, 189 insertions(+), 1 deletion(-) diff --git a/src/tools/delegate-task/metadata-model-unification.test.ts b/src/tools/delegate-task/metadata-model-unification.test.ts index 799b9537e..9cdfba190 100644 --- a/src/tools/delegate-task/metadata-model-unification.test.ts +++ b/src/tools/delegate-task/metadata-model-unification.test.ts @@ -4,6 +4,7 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ParentContext } from "./executor-types" const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } +const MODEL_WITH_VARIANT = { providerID: "google", modelID: "gemini-3.1-pro", variant: "high" } function makeMockCtx(): ToolContextWithMetadata & { captured: any[] } { const captured: any[] = [] @@ -344,4 +345,148 @@ describe("metadata model unification", () => { expect(meta.metadata.model).toBeUndefined() }) }) + + describe("#given category model with variant", () => { + describe("#when executors publish metadata", () => { + test("#then sync-task metadata includes variant", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync_variant" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "visual-engineering", load_skills: [], run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync_variant" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "explore", MODEL_WITH_VARIANT, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then background-task metadata includes variant", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "visual-engineering", load_skills: [], run_in_background: true, subagent_type: "explore", + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_variant", description: "test", agent: "explore", + status: "pending", sessionID: "ses_bg_variant", model: MODEL_WITH_VARIANT, + }), + getTask: () => undefined, + }, + } as any, parentContext, "explore", MODEL_WITH_VARIANT, undefined) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then unstable-agent-task metadata includes variant", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "visual-engineering", load_skills: [], run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable_variant", description: "test", agent: "explore", + status: "completed", sessionID: "ses_unstable_variant", model: MODEL_WITH_VARIANT, + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable_variant: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "explore", MODEL_WITH_VARIANT, undefined, "google/gemini-3.1-pro high", + ) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then background-continuation metadata includes variant from task", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed_variant", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resume_variant", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_variant", model: MODEL_WITH_VARIANT, + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then sync-continuation metadata includes variant from resumed session", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont_variant", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL_WITH_VARIANT, providerID: "google", modelID: "gemini-3.1-pro" } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + }) + }) }) diff --git a/src/tools/delegate-task/resolve-metadata-model.test.ts b/src/tools/delegate-task/resolve-metadata-model.test.ts index 50b29f253..3c13a7710 100644 --- a/src/tools/delegate-task/resolve-metadata-model.test.ts +++ b/src/tools/delegate-task/resolve-metadata-model.test.ts @@ -39,12 +39,55 @@ describe("resolveMetadataModel", () => { }) describe("#given primary has extra fields", () => { - test("#when resolving #then strips to providerID and modelID only", () => { + test("#when resolving #then preserves variant and strips unrelated fields", () => { const extended = { providerID: "openai", modelID: "gpt-5.4", variant: "high", temperature: 0.7 } as const const result = resolveMetadataModel(extended, undefined) + expect(result).toEqual({ providerID: "openai", modelID: "gpt-5.4", variant: "high" }) + }) + }) + + describe("#given primary has variant", () => { + test("#when resolving metadata model #then variant is preserved", () => { + const primary = { providerID: "google", modelID: "gemini-3.1-pro", variant: "high" } + + const result = resolveMetadataModel(primary, undefined) + + expect(result).toEqual({ providerID: "google", modelID: "gemini-3.1-pro", variant: "high" }) + }) + }) + + describe("#given primary lacks variant but fallback has variant", () => { + test("#when primary provided #then fallback variant is not used", () => { + const primary = { providerID: "google", modelID: "gemini-3.1-pro" } + const fallback = { providerID: "anthropic", modelID: "claude", variant: "max" } + + const result = resolveMetadataModel(primary, fallback) + + expect(result).toEqual({ providerID: "google", modelID: "gemini-3.1-pro" }) + expect(result?.variant).toBeUndefined() + }) + }) + + describe("#given primary is undefined and fallback has variant", () => { + test("#when resolving metadata model #then fallback variant is preserved", () => { + const fallback = { providerID: "anthropic", modelID: "claude", variant: "max" } + + const result = resolveMetadataModel(undefined, fallback) + + expect(result).toEqual({ providerID: "anthropic", modelID: "claude", variant: "max" }) + }) + }) + + describe("#given both lack variant", () => { + test("#when resolving metadata model #then variant is not on result", () => { + const primary = { providerID: "openai", modelID: "gpt-5.4" } + + const result = resolveMetadataModel(primary, undefined) + expect(result).toEqual({ providerID: "openai", modelID: "gpt-5.4" }) + expect(result?.variant).toBeUndefined() }) }) }) From cd0c98e54d1220a685b6056a594b4c1a2b5f22ea Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 14:51:01 +0900 Subject: [PATCH 125/146] fix(delegate-task): preserve model variant in metadata resolution Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../delegate-task/resolve-metadata-model.ts | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/tools/delegate-task/resolve-metadata-model.ts b/src/tools/delegate-task/resolve-metadata-model.ts index 3c68ed3ad..01bddbda6 100644 --- a/src/tools/delegate-task/resolve-metadata-model.ts +++ b/src/tools/delegate-task/resolve-metadata-model.ts @@ -3,19 +3,37 @@ import type { DelegatedModelConfig } from "./types" export interface MetadataModel { providerID: string modelID: string + variant?: string } -type ModelLike = Pick | MetadataModel +type ModelLike = Pick | MetadataModel + +function isModelLike(value: unknown): value is ModelLike { + return typeof value === "object" + && value !== null + && "providerID" in value + && typeof value.providerID === "string" + && "modelID" in value + && typeof value.modelID === "string" +} + +function toMetadataModel(model: ModelLike): MetadataModel { + return { + providerID: model.providerID, + modelID: model.modelID, + ...("variant" in model && model.variant ? { variant: model.variant } : {}), + } +} export function resolveMetadataModel( primary: ModelLike | undefined, fallback: ModelLike | undefined, ): MetadataModel | undefined { - if (primary) { - return { providerID: primary.providerID, modelID: primary.modelID } + if (isModelLike(primary)) { + return toMetadataModel(primary) } - if (fallback) { - return { providerID: fallback.providerID, modelID: fallback.modelID } + if (isModelLike(fallback)) { + return toMetadataModel(fallback) } return undefined } From 271068d871d4c7ad51326369a65a603a9bbe18a4 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 14:48:28 +0900 Subject: [PATCH 126/146] chore(delegate-task): remove unused execute field from DelegateTaskArgs The execute field with { task_id, task_dir } was defined but never referenced anywhere in the codebase. Removing dead code simplifies the type surface and prevents accidental future misuse. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/types.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tools/delegate-task/types.ts b/src/tools/delegate-task/types.ts index affd81983..1eb767960 100644 --- a/src/tools/delegate-task/types.ts +++ b/src/tools/delegate-task/types.ts @@ -19,10 +19,6 @@ export interface DelegateTaskArgs { task_id?: string command?: string load_skills: string[] - execute?: { - task_id: string - task_dir?: string - } } export interface ToolContextWithMetadata { From bcf95112caedb604bb86e3784f3cb49cbbd4e3db Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:16:48 +0900 Subject: [PATCH 127/146] refactor(delegate-task): remove AI slop from executor metadata paths Strip obvious comments, over-defensive guards, and dead branches across the five delegate-task executor files while preserving all metadata propagation behavior added in prior commits. Regression tests remain green (328 pass / 0 fail). --- .../delegate-task/background-continuation.ts | 25 +++++----- src/tools/delegate-task/background-task.ts | 14 +++--- src/tools/delegate-task/sync-continuation.ts | 19 ++++---- src/tools/delegate-task/sync-task.ts | 46 +++++++++---------- .../delegate-task/unstable-agent-task.ts | 35 +++++--------- 5 files changed, 65 insertions(+), 74 deletions(-) diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 4c500d5dd..098367fc3 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -14,9 +14,9 @@ export async function executeBackgroundContinuation( parentContext: ParentContext ): Promise { const { manager } = executorCtx + const taskID = getTaskID(args) try { - const taskID = getTaskID(args) if (!taskID) { throw new Error("task_id is required to continue a background task") } @@ -30,6 +30,9 @@ export async function executeBackgroundContinuation( parentAgent: parentContext.agent, parentTools: getSessionTools(parentContext.sessionID), }) + const sessionId = task.sessionID + const backgroundTaskId = task.id + const resolvedModel = resolveMetadataModel(task.model, parentContext.model) const bgContMeta = { title: `Continue: ${task.description}`, @@ -41,38 +44,38 @@ export async function executeBackgroundContinuation( load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, - taskId: task.sessionID, - backgroundTaskId: task.id, - sessionId: task.sessionID, + taskId: sessionId, + backgroundTaskId, + sessionId, command: args.command, - model: resolveMetadataModel(task.model, parentContext.model), + model: resolvedModel, }, } await publishToolMetadata(ctx, bgContMeta) return `Background task continued. -Task ID: ${task.id} +Task ID: ${backgroundTaskId} Description: ${task.description} Agent: ${task.agent} Status: ${task.status} Agent continues with full previous context preserved. -System notifies on completion. Use \`background_output\` with task_id="${task.id}" to check. +System notifies on completion. Use \`background_output\` with task_id="${backgroundTaskId}" to check. Do NOT call background_output now. Wait for notification first. ${buildTaskMetadataBlock({ - sessionId: task.sessionID, - taskId: task.sessionID, - backgroundTaskId: task.id, + sessionId, + taskId: sessionId, + backgroundTaskId, agent: task.agent, })}` } catch (error) { return formatDetailedError(error, { operation: "Continue background task", args, - sessionID: getTaskID(args), + sessionID: taskID, }) } } diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 2f767b477..54bfd1351 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -115,9 +115,9 @@ export async function executeBackgroundTask( if (sessionId) { executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, fallbackChain) - } - if (args.category && sessionId) { - SessionCategoryRegistry.register(sessionId, args.category) + if (args.category) { + SessionCategoryRegistry.register(sessionId, args.category) + } } const resolvedModel = resolveMetadataModel(categoryModel, parentContext.model) @@ -130,17 +130,15 @@ export async function executeBackgroundTask( description: args.description, run_in_background: args.run_in_background, command: args.command, - ...(sessionId ? { taskId: sessionId } : {}), + ...(sessionId ? { taskId: sessionId, sessionId } : {}), backgroundTaskId: task.id, - ...(sessionId ? { sessionId } : {}), ...(resolvedModel ? { model: resolvedModel } : {}), } - const unstableMeta = { + await publishToolMetadata(ctx, { title: args.description, metadata, - } - await publishToolMetadata(ctx, unstableMeta) + }) const taskMetadataBlock = sessionId ? `\n\n${buildTaskMetadataBlock({ diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index a99f6ff39..ce29c7048 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -4,13 +4,12 @@ import { isPlanFamily } from "./constants" import { publishToolMetadata } from "../../features/tool-metadata-store" import { getTaskToastManager } from "../../features/task-toast-manager" import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions" -import { getMessageDir } from "../../shared" +import { getMessageDir, normalizeSDKResponse } from "../../shared" import { promptWithModelSuggestionRetry } from "../../shared/model-suggestion-retry" import { findNearestMessageWithFields } from "../../features/hook-message-injector" import { formatDuration } from "./time-formatter" import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continuation-deps" import { setSessionTools } from "../../shared/session-tools-store" -import { normalizeSDKResponse } from "../../shared" import { buildTaskPrompt } from "./prompt-builder" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" import { getTaskID } from "./task-id" @@ -41,8 +40,6 @@ export async function executeSyncContinuation( }) } - let syncContMeta: { title: string; metadata: Record } | undefined - let resumeAgent: string | undefined let resumeModel: { providerID: string; modelID: string } | undefined let resumeVariant: string | undefined @@ -56,8 +53,11 @@ export async function executeSyncContinuation( for (let i = messages.length - 1; i >= 0; i--) { const info = messages[i].info if (info?.agent || info?.model || (info?.modelID && info?.providerID)) { + const fallbackResumeModel = info.providerID && info.modelID + ? { providerID: info.providerID, modelID: info.modelID } + : undefined resumeAgent = info.agent - resumeModel = info.model ?? (info.providerID && info.modelID ? { providerID: info.providerID, modelID: info.modelID } : undefined) + resumeModel = info.model ?? fallbackResumeModel resumeVariant = info.variant break } @@ -65,14 +65,15 @@ export async function executeSyncContinuation( } catch { const resumeMessageDir = getMessageDir(continuationID) const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null + const resumeMessageModel = resumeMessage?.model resumeAgent = resumeMessage?.agent - resumeModel = resumeMessage?.model?.providerID && resumeMessage?.model?.modelID - ? { providerID: resumeMessage.model.providerID, modelID: resumeMessage.model.modelID } + resumeModel = resumeMessageModel?.providerID && resumeMessageModel.modelID + ? { providerID: resumeMessageModel.providerID, modelID: resumeMessageModel.modelID } : undefined - resumeVariant = resumeMessage?.model?.variant + resumeVariant = resumeMessageModel?.variant } - syncContMeta = { + const syncContMeta = { title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index e1b5e2cba..b1a0d6f38 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -88,13 +88,15 @@ export async function executeSyncTask( if (onSyncSessionCreated) { log("[task] Invoking onSyncSessionCreated callback", { sessionID, parentID: parentContext.sessionID }) - await onSyncSessionCreated({ - sessionID, - parentID: parentContext.sessionID, - title: args.description, - }).catch((err) => { - log("[task] onSyncSessionCreated callback failed", { error: String(err) }) - }) + try { + await onSyncSessionCreated({ + sessionID, + parentID: parentContext.sessionID, + title: args.description, + }) + } catch (error) { + log("[task] onSyncSessionCreated callback failed", { error: String(error) }) + } await new Promise(r => setTimeout(r, 200)) } @@ -134,16 +136,20 @@ export async function executeSyncTask( } await publishToolMetadata(ctx, syncTaskMeta) - let effectiveCategoryModel = categoryModel - let promptError = await deps.sendSyncPrompt(client, { + const syncPromptInput = { sessionID, agentToUse, args, systemContent, - categoryModel: effectiveCategoryModel, toastManager, taskId, sisyphusAgentConfig: executorCtx.sisyphusAgentConfig, + } + + let effectiveCategoryModel = categoryModel + let promptError = await deps.sendSyncPrompt(client, { + ...syncPromptInput, + categoryModel: effectiveCategoryModel, }) if (promptError) { const promptResult = await retrySyncPromptWithFallbacks({ @@ -153,14 +159,8 @@ export async function executeSyncTask( fallbackChain, sendPrompt: async (fallbackModel) => { return deps.sendSyncPrompt(client, { - sessionID, - agentToUse, - args, - systemContent, + ...syncPromptInput, categoryModel: fallbackModel, - toastManager, - taskId, - sisyphusAgentConfig: executorCtx.sisyphusAgentConfig, }) }, }) @@ -198,12 +198,12 @@ export async function executeSyncTask( const parentModelStr = parentContext.model ? `${parentContext.model.providerID}/${parentContext.model.modelID}` : undefined - const modelRoutingNote = - actualModelStr && parentModelStr && actualModelStr !== parentModelStr - ? `\n⚠️ Model routing: parent used ${parentModelStr}, this subagent used ${actualModelStr} (via category: ${args.category ?? "unknown"})` - : actualModelStr - ? `\nModel: ${actualModelStr}${args.category ? ` (category: ${args.category})` : ""}` - : "" + let modelRoutingNote = "" + if (actualModelStr && parentModelStr && actualModelStr !== parentModelStr) { + modelRoutingNote = `\n⚠️ Model routing: parent used ${parentModelStr}, this subagent used ${actualModelStr} (via category: ${args.category ?? "unknown"})` + } else if (actualModelStr) { + modelRoutingNote = `\nModel: ${actualModelStr}${args.category ? ` (category: ${args.category})` : ""}` + } return `Task completed in ${duration}. diff --git a/src/tools/delegate-task/unstable-agent-task.ts b/src/tools/delegate-task/unstable-agent-task.ts index bc4011fbe..f81eb9971 100644 --- a/src/tools/delegate-task/unstable-agent-task.ts +++ b/src/tools/delegate-task/unstable-agent-task.ts @@ -87,6 +87,14 @@ export async function executeUnstableAgentTask( } await publishToolMetadata(ctx, bgTaskMeta) + const taskMetadataBlock = buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + backgroundTaskId: task.id, + agent: agentToUse, + category: args.category, + }) + const startTime = new Date() const timingCfg = getTimingConfig() const pollStart = Date.now() @@ -152,13 +160,7 @@ Model: ${actualModel} The task session may contain partial results. -${buildTaskMetadataBlock({ - sessionId: sessionID, - taskId: sessionID, - backgroundTaskId: task.id, - agent: agentToUse, - category: args.category, - })}` +${taskMetadataBlock}` } if (!completedDuringMonitoring) { @@ -176,13 +178,7 @@ Model: ${actualModel} The task session may still contain partial results. -${buildTaskMetadataBlock({ - sessionId: sessionID, - taskId: sessionID, - backgroundTaskId: task.id, - agent: agentToUse, - category: args.category, - })}` +${taskMetadataBlock}` } const messagesResult = await client.session.messages({ path: { id: sessionID } }) @@ -193,9 +189,8 @@ ${buildTaskMetadataBlock({ const assistantMessages = messages .filter((m) => m.info?.role === "assistant") .sort((a, b) => (b.info?.time?.created ?? 0) - (a.info?.time?.created ?? 0)) - const lastMessage = assistantMessages[0] - if (!lastMessage) { + if (assistantMessages.length === 0) { return `No assistant response found (task ran in background mode).\n\nSession ID: ${sessionID}` } @@ -230,13 +225,7 @@ RESULT: ${textContent || "(No text output)"} -${buildTaskMetadataBlock({ - sessionId: sessionID, - taskId: sessionID, - backgroundTaskId: task.id, - agent: agentToUse, - category: args.category, - })}` +${taskMetadataBlock}` } catch (error) { if (!cleanupReason) { cleanupReason = "exception" From 3f28e42483ab403cf7aa0c566218495bb02b0e76 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:20:45 +0900 Subject: [PATCH 128/146] refactor(delegate-task): remove AI slop from supporting files Tighten resolve-metadata-model runtime guards, tidy tool-argument-preparation subagent-type override logging, and trim a redundant literal in the metadata-model-unification test. Behavior preserved (328 tests pass). --- .../metadata-model-unification.test.ts | 4 ++-- src/tools/delegate-task/resolve-metadata-model.ts | 9 +++++++-- .../delegate-task/tool-argument-preparation.ts | 13 +++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/tools/delegate-task/metadata-model-unification.test.ts b/src/tools/delegate-task/metadata-model-unification.test.ts index 9cdfba190..5e913b5e7 100644 --- a/src/tools/delegate-task/metadata-model-unification.test.ts +++ b/src/tools/delegate-task/metadata-model-unification.test.ts @@ -1,4 +1,4 @@ -const { describe, test, expect, mock } = require("bun:test") +const { describe, test, expect } = require("bun:test") import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ParentContext } from "./executor-types" @@ -90,7 +90,7 @@ describe("metadata model unification", () => { id: "bg_unstable", description: "test", agent: "explore", status: "completed", sessionID: "ses_unstable", model: MODEL, } - const result = await executeUnstableAgentTask( + await executeUnstableAgentTask( args, ctx, { manager: { diff --git a/src/tools/delegate-task/resolve-metadata-model.ts b/src/tools/delegate-task/resolve-metadata-model.ts index 01bddbda6..d4fa128b2 100644 --- a/src/tools/delegate-task/resolve-metadata-model.ts +++ b/src/tools/delegate-task/resolve-metadata-model.ts @@ -18,11 +18,16 @@ function isModelLike(value: unknown): value is ModelLike { } function toMetadataModel(model: ModelLike): MetadataModel { - return { + const metadataModel: MetadataModel = { providerID: model.providerID, modelID: model.modelID, - ...("variant" in model && model.variant ? { variant: model.variant } : {}), } + + if ("variant" in model && model.variant) { + metadataModel.variant = model.variant + } + + return metadataModel } export function resolveMetadataModel( diff --git a/src/tools/delegate-task/tool-argument-preparation.ts b/src/tools/delegate-task/tool-argument-preparation.ts index 8f529230b..f39e7bbee 100644 --- a/src/tools/delegate-task/tool-argument-preparation.ts +++ b/src/tools/delegate-task/tool-argument-preparation.ts @@ -8,13 +8,14 @@ export async function prepareDelegateTaskArgs(args: Record, ctx const originalSubagentType = typeof args.subagent_type === "string" ? args.subagent_type : undefined let subagentType = originalSubagentType + if (category && subagentType && subagentType !== SISYPHUS_JUNIOR_AGENT) { + log("[task] category provided - overriding subagent_type to sisyphus-junior", { + category, + subagent_type: subagentType, + }) + } + if (category) { - if (subagentType && subagentType !== SISYPHUS_JUNIOR_AGENT) { - log("[task] category provided - overriding subagent_type to sisyphus-junior", { - category, - subagent_type: subagentType, - }) - } subagentType = SISYPHUS_JUNIOR_AGENT } From 54cc9b7ca4cb6446038a23d0a7fa1b9aa00fd598 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:29:32 +0900 Subject: [PATCH 129/146] test(delegate-task): lock Oracle-found gaps with TDD Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../delegate-task/oracle-gap-closure.test.ts | 245 ++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 src/tools/delegate-task/oracle-gap-closure.test.ts diff --git a/src/tools/delegate-task/oracle-gap-closure.test.ts b/src/tools/delegate-task/oracle-gap-closure.test.ts new file mode 100644 index 000000000..eb8c3fe1c --- /dev/null +++ b/src/tools/delegate-task/oracle-gap-closure.test.ts @@ -0,0 +1,245 @@ +declare const require: NodeJS.Require + +const { describe, test, expect, beforeEach, afterEach, spyOn, mock } = require("bun:test") + +import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" +import type { ParentContext } from "./executor-types" +import * as executor from "./executor" + +const runtimeRequire = require as NodeJS.Require & { cache?: Record } +const MODEL = { providerID: "openai", modelID: "gpt-5.4" } + +function clearRequireCache(modulePath: string): void { + const resolvedPath = runtimeRequire.resolve(modulePath) + if (runtimeRequire.cache?.[resolvedPath]) { + delete runtimeRequire.cache[resolvedPath] + } +} + +function makeMockCtx(): ToolContextWithMetadata & { + captured: Array<{ title?: string; metadata?: Record }> +} { + const captured: Array<{ title?: string; metadata?: Record }> = [] + + return { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + abort: new AbortController().signal, + callID: "call_001", + metadata: async (input) => { + captured.push(input) + }, + captured, + } +} + +const parentContext: ParentContext = { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + model: MODEL, +} + +describe("delegate-task Oracle gap closure", () => { + beforeEach(() => { + mock.restore() + clearRequireCache("./tools") + }) + + afterEach(() => { + mock.restore() + clearRequireCache("./tools") + }) + + test("#given sync continuation message info has sibling variant #when metadata publishes #then model keeps variant", async () => { + //#given + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", + prompt: "keep going", + load_skills: [], + run_in_background: false, + task_id: "ses_cont_variant", + } + + //#when + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ data: [{ info: { agent: "explore", model: MODEL, variant: "max" } }] }), + promptAsync: async () => ({}), + }, + }, + }, parentContext, { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + }) + + //#then + const published = ctx.captured.find((item) => item.metadata?.sessionId === "ses_cont_variant") + expect(published?.metadata?.model).toEqual({ ...MODEL, variant: "max" }) + }) + + test("#given sync continuation category arg #when result returns task metadata block #then block includes category", async () => { + //#given + const { executeSyncContinuation } = require("./sync-continuation") + const args: DelegateTaskArgs = { + description: "continue", + prompt: "keep going", + category: "quick", + load_skills: [], + run_in_background: false, + task_id: "ses_cont_category", + } + + //#when + const result = await executeSyncContinuation(args, makeMockCtx(), { + client: { + session: { + messages: async () => ({ data: [{ info: { agent: "explore", model: MODEL } }] }), + promptAsync: async () => ({}), + }, + }, + }, parentContext, { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + }) + + //#then + expect(result).toContain("") + expect(result).toContain("category: quick") + }) + + test("#given background continuation task category #when result returns task metadata block #then block includes category", async () => { + //#given + const { executeBackgroundContinuation } = require("./background-continuation") + const args: DelegateTaskArgs = { + description: "continue", + prompt: "keep going", + load_skills: [], + run_in_background: true, + task_id: "ses_bg_category", + } + + //#when + const result = await executeBackgroundContinuation(args, makeMockCtx(), { + manager: { + resume: async () => ({ + id: "bg_category", + description: "existing", + agent: "explore", + status: "running", + sessionID: "ses_bg_category", + category: "deep", + model: MODEL, + }), + }, + }, parentContext) + + //#then + expect(result).toContain("") + expect(result).toContain("category: deep") + }) + + test("#given background continuation description changed #when metadata publishes #then title uses args description", async () => { + //#given + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "new desc", + prompt: "keep going", + load_skills: [], + run_in_background: true, + task_id: "ses_bg_title", + } + + //#when + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_title", + description: "old desc", + agent: "explore", + status: "running", + sessionID: "ses_bg_title", + model: MODEL, + }), + }, + }, parentContext) + + //#then + const published = ctx.captured.find((item) => item.metadata?.sessionId === "ses_bg_title") + expect(published?.title).toBe("Continue: new desc") + }) + + test("#given sync continuation receives system content #when prompt is sent #then system content reaches prompt body", async () => { + //#given + const promptCalls: Array<{ body?: { system?: string } }> = [] + const { executeSyncContinuation } = require("./sync-continuation") + + //#when + await executeSyncContinuation({ + description: "continue", + prompt: "keep going", + load_skills: ["playwright"], + run_in_background: false, + task_id: "ses_sync_skills", + }, makeMockCtx(), { + client: { + session: { + messages: async () => ({ data: [{ info: { agent: "explore", model: MODEL } }] }), + promptAsync: async (input: { body?: { system?: string } }) => { + promptCalls.push(input) + return {} + }, + }, + }, + }, parentContext, { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + }, "skill instructions") + + //#then + expect(promptCalls[0]?.body?.system).toBe("skill instructions") + }) + + test("#given background continuation loads skills through tool entry #when task resumes #then skill content is threaded into resumed prompt", async () => { + //#given + const resumeCalls: Array<{ prompt?: string }> = [] + spyOn(executor, "resolveSkillContent").mockResolvedValue({ content: "skill instructions", contents: undefined, error: null }) + spyOn(executor, "resolveParentContext").mockResolvedValue(parentContext) + const { createDelegateTask } = require("./tools") + const delegateTask = createDelegateTask({ + directory: "/tmp", + manager: { + resume: async (input: { prompt?: string }) => { + resumeCalls.push(input) + return { + id: "bg_skills", + description: "existing", + agent: "explore", + status: "running", + sessionID: "ses_bg_skills", + model: MODEL, + } + }, + }, + client: {}, + }) + + //#when + await delegateTask.execute({ + description: "continue", + prompt: "keep going", + load_skills: ["playwright"], + run_in_background: true, + task_id: "ses_bg_skills", + }, makeMockCtx()) + + //#then + expect(resumeCalls[0]?.prompt).toContain("skill instructions") + expect(resumeCalls[0]?.prompt).toContain("keep going") + }) +}) From b5bc4cd404d85fe8a0d44cead93ac94852f2717e Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:32:16 +0900 Subject: [PATCH 130/146] fix(delegate-task): preserve variant in sync-continuation metadata model Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/sync-continuation.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index ce29c7048..0f3665b73 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -74,6 +74,10 @@ export async function executeSyncContinuation( } const syncContMeta = { + const resumeModelForMetadata = resumeModel && resumeVariant !== undefined + ? { ...resumeModel, variant: resumeVariant } + : resumeModel + title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, @@ -87,7 +91,7 @@ export async function executeSyncContinuation( sessionId: continuationID, sync: true, command: args.command, - model: resolveMetadataModel(resumeModel, parentContext.model), + model: resolveMetadataModel(resumeModelForMetadata, parentContext.model), }, } await publishToolMetadata(ctx, syncContMeta) From 83c8ffbe0163a8155f1a40ddc20785a24c2cb02c Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:33:05 +0900 Subject: [PATCH 131/146] fix(delegate-task): include category in continuation task_metadata blocks Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/background-continuation.ts | 1 + src/tools/delegate-task/sync-continuation.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 098367fc3..a425a4db4 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -75,6 +75,7 @@ ${buildTaskMetadataBlock({ return formatDetailedError(error, { operation: "Continue background task", args, + category: task.category, sessionID: taskID, }) } diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index 0f3665b73..fdd05cddf 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -156,6 +156,7 @@ ${buildTaskMetadataBlock({ agent: resumeAgent, })}` } finally { + category: args.category, if (toastManager) { toastManager.removeTask(taskId) } From d0a3cb3936f949e0e9aeef7ccee343a7c372a197 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:33:45 +0900 Subject: [PATCH 132/146] fix(delegate-task): align background-continuation title with args.description Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/background-continuation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index a425a4db4..0af49757e 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -35,7 +35,7 @@ export async function executeBackgroundContinuation( const resolvedModel = resolveMetadataModel(task.model, parentContext.model) const bgContMeta = { - title: `Continue: ${task.description}`, + title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, agent: task.agent, From 4810d0f1bd9feea863c786ad6450b987d82ee322 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:35:45 +0900 Subject: [PATCH 133/146] fix(delegate-task): apply load_skills content to continuation prompts Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/background-continuation.ts | 11 ++++++++--- src/tools/delegate-task/sync-continuation.ts | 8 +++++--- src/tools/delegate-task/tools.ts | 11 +++++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 0af49757e..1d0aa94f6 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -11,7 +11,8 @@ export async function executeBackgroundContinuation( args: DelegateTaskArgs, ctx: ToolContextWithMetadata, executorCtx: ExecutorContext, - parentContext: ParentContext + parentContext: ParentContext, + systemContent?: string ): Promise { const { manager } = executorCtx const taskID = getTaskID(args) @@ -21,9 +22,13 @@ export async function executeBackgroundContinuation( throw new Error("task_id is required to continue a background task") } + const effectivePrompt = systemContent + ? `${systemContent}\n\n${args.prompt}` + : args.prompt + const task = await manager.resume({ sessionId: taskID, - prompt: args.prompt, + prompt: effectivePrompt, parentSessionID: parentContext.sessionID, parentMessageID: parentContext.messageID, parentModel: parentContext.model, @@ -70,12 +75,12 @@ ${buildTaskMetadataBlock({ taskId: sessionId, backgroundTaskId, agent: task.agent, + category: task.category, })}` } catch (error) { return formatDetailedError(error, { operation: "Continue background task", args, - category: task.category, sessionID: taskID, }) } diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index fdd05cddf..17edcb058 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -20,7 +20,8 @@ export async function executeSyncContinuation( ctx: ToolContextWithMetadata, executorCtx: ExecutorContext, parentContext: ParentContext, - deps: SyncContinuationDeps = syncContinuationDeps + deps: SyncContinuationDeps = syncContinuationDeps, + systemContent?: string ): Promise { const { client, syncPollTimeoutMs, sisyphusAgentConfig } = executorCtx const toastManager = getTaskToastManager() @@ -73,11 +74,11 @@ export async function executeSyncContinuation( resumeVariant = resumeMessageModel?.variant } - const syncContMeta = { const resumeModelForMetadata = resumeModel && resumeVariant !== undefined ? { ...resumeModel, variant: resumeVariant } : resumeModel + const syncContMeta = { title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, @@ -113,6 +114,7 @@ export async function executeSyncContinuation( ...(resumeAgent !== undefined ? { agent: resumeAgent } : {}), ...(resumeModel !== undefined ? { model: resumeModel } : {}), ...(resumeVariant !== undefined ? { variant: resumeVariant } : {}), + system: systemContent, tools, parts: [{ type: "text", text: effectivePrompt }], }, @@ -154,9 +156,9 @@ ${buildTaskMetadataBlock({ sessionId: continuationID, taskId: continuationID, agent: resumeAgent, + category: args.category, })}` } finally { - category: args.category, if (toastManager) { toastManager.removeTask(taskId) } diff --git a/src/tools/delegate-task/tools.ts b/src/tools/delegate-task/tools.ts index b0820f73b..268c455ca 100644 --- a/src/tools/delegate-task/tools.ts +++ b/src/tools/delegate-task/tools.ts @@ -53,13 +53,20 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini return skillError } + const continuationSystemContent = buildSystemContent({ + skillContent, + skillContents, + availableCategories, + availableSkills, + }) + const parentContext = await resolveParentContext(ctx, options.client) if (delegateTaskArgs.task_id) { if (runInBackground) { - return executeBackgroundContinuation(delegateTaskArgs, ctx, options, parentContext) + return executeBackgroundContinuation(delegateTaskArgs, ctx, options, parentContext, continuationSystemContent) } - return executeSyncContinuation(delegateTaskArgs, ctx, options, parentContext) + return executeSyncContinuation(delegateTaskArgs, ctx, options, parentContext, undefined, continuationSystemContent) } if (!delegateTaskArgs.category && !delegateTaskArgs.subagent_type) { From 2585031f54f0b096432ecf61b92550b9524e5268 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:48:58 +0900 Subject: [PATCH 134/146] refactor(delegate-task): extract sync continuation resume context Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/sync-continuation.ts | 80 +++++++++++++------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index 17edcb058..5a4b7f792 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -15,6 +15,53 @@ import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task- import { getTaskID } from "./task-id" import { resolveMetadataModel } from "./resolve-metadata-model" +type ResumeModel = { providerID: string; modelID: string } + +type ResumeContext = { + resumeAgent?: string + resumeModel?: ResumeModel + resumeVariant?: string + anchorMessageCount?: number +} + +async function resolveResumeContext( + client: ExecutorContext["client"], + continuationID: string +): Promise { + try { + const messagesResp = await client.session.messages({ path: { id: continuationID } }) + const messages = normalizeSDKResponse(messagesResp, [] as SessionMessage[]) + + for (let index = messages.length - 1; index >= 0; index--) { + const info = messages[index].info + if (info?.agent || info?.model || (info?.modelID && info?.providerID)) { + return { + resumeAgent: info.agent, + resumeModel: info.model ?? (info.providerID && info.modelID + ? { providerID: info.providerID, modelID: info.modelID } + : undefined), + resumeVariant: info.variant, + anchorMessageCount: messages.length, + } + } + } + + return { anchorMessageCount: messages.length } + } catch { + const resumeMessageDir = getMessageDir(continuationID) + const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null + const resumeMessageModel = resumeMessage?.model + + return { + resumeAgent: resumeMessage?.agent, + resumeModel: resumeMessageModel?.providerID && resumeMessageModel.modelID + ? { providerID: resumeMessageModel.providerID, modelID: resumeMessageModel.modelID } + : undefined, + resumeVariant: resumeMessageModel?.variant, + } + } +} + export async function executeSyncContinuation( args: DelegateTaskArgs, ctx: ToolContextWithMetadata, @@ -42,37 +89,16 @@ export async function executeSyncContinuation( } let resumeAgent: string | undefined - let resumeModel: { providerID: string; modelID: string } | undefined + let resumeModel: ResumeModel | undefined let resumeVariant: string | undefined let anchorMessageCount: number | undefined try { - try { - const messagesResp = await client.session.messages({ path: { id: continuationID } }) - const messages = normalizeSDKResponse(messagesResp, [] as SessionMessage[]) - anchorMessageCount = messages.length - for (let i = messages.length - 1; i >= 0; i--) { - const info = messages[i].info - if (info?.agent || info?.model || (info?.modelID && info?.providerID)) { - const fallbackResumeModel = info.providerID && info.modelID - ? { providerID: info.providerID, modelID: info.modelID } - : undefined - resumeAgent = info.agent - resumeModel = info.model ?? fallbackResumeModel - resumeVariant = info.variant - break - } - } - } catch { - const resumeMessageDir = getMessageDir(continuationID) - const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null - const resumeMessageModel = resumeMessage?.model - resumeAgent = resumeMessage?.agent - resumeModel = resumeMessageModel?.providerID && resumeMessageModel.modelID - ? { providerID: resumeMessageModel.providerID, modelID: resumeMessageModel.modelID } - : undefined - resumeVariant = resumeMessageModel?.variant - } + const resumeContext = await resolveResumeContext(client, continuationID) + resumeAgent = resumeContext.resumeAgent + resumeModel = resumeContext.resumeModel + resumeVariant = resumeContext.resumeVariant + anchorMessageCount = resumeContext.anchorMessageCount const resumeModelForMetadata = resumeModel && resumeVariant !== undefined ? { ...resumeModel, variant: resumeVariant } From 54e48de7f8eb16bcae8bf19475e171c609d69f5d Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:50:28 +0900 Subject: [PATCH 135/146] refactor(delegate-task): extract background session registration helpers Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/background-task.ts | 95 ++++++++++++++++------ 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 54bfd1351..e4ec2db38 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -12,6 +12,18 @@ import { stripAgentListSortPrefix } from "../../shared/agent-display-names" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" import { resolveMetadataModel } from "./resolve-metadata-model" +function registerBackgroundSessionContext(args: { + sessionId: string + fallbackChain?: FallbackEntry[] + category?: string + modelFallbackControllerAccessor?: ExecutorContext["modelFallbackControllerAccessor"] +}): void { + args.modelFallbackControllerAccessor?.setSessionFallbackChain(args.sessionId, args.fallbackChain) + if (args.category) { + SessionCategoryRegistry.register(args.sessionId, args.category) + } +} + function continueSessionSetup(args: { taskID: string manager: ExecutorContext["manager"] @@ -41,15 +53,50 @@ function continueSessionSetup(args: { continue } - args.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, args.fallbackChain) - if (args.category) { - SessionCategoryRegistry.register(sessionId, args.category) - } + registerBackgroundSessionContext({ + sessionId, + fallbackChain: args.fallbackChain, + category: args.category, + modelFallbackControllerAccessor: args.modelFallbackControllerAccessor, + }) return } })() } +async function waitForBackgroundSessionStart(args: { + taskId: string + initialSessionId?: string + manager: ExecutorContext["manager"] + timing: ReturnType + abortSignal?: AbortSignal + onAbort: () => void +}): Promise { + const waitStart = Date.now() + let sessionId = args.initialSessionId + + while (!sessionId && Date.now() - waitStart < args.timing.WAIT_FOR_SESSION_TIMEOUT_MS) { + const updated = args.manager.getTask(args.taskId) + if (updated?.status === "error" || updated?.status === "cancelled" || updated?.status === "interrupt") { + return undefined + } + + sessionId = updated?.sessionID + if (sessionId) { + return sessionId + } + + if (args.abortSignal?.aborted) { + args.onAbort() + return undefined + } + + await new Promise(resolve => setTimeout(resolve, args.timing.WAIT_FOR_SESSION_INTERVAL_MS)) + } + + return sessionId +} + export async function executeBackgroundTask( args: DelegateTaskArgs, ctx: ToolContextWithMetadata, @@ -88,18 +135,13 @@ export async function executeBackgroundTask( // BackgroundManager.launch() returns immediately (pending) before the session exists, // so we must wait briefly for the session to be created to set metadata correctly. const timing = getTimingConfig() - const waitStart = Date.now() - let sessionId = task.sessionID - while (!sessionId && Date.now() - waitStart < timing.WAIT_FOR_SESSION_TIMEOUT_MS) { - const updated = manager.getTask(task.id) - if (updated?.status === "error" || updated?.status === "cancelled" || updated?.status === "interrupt") { - return `Task failed to start (status: ${updated.status}).\n\nTask ID: ${task.id}` - } - sessionId = updated?.sessionID - if (sessionId) { - break - } - if (ctx.abort?.aborted) { + let sessionId = await waitForBackgroundSessionStart({ + taskId: task.id, + initialSessionId: task.sessionID, + manager, + timing, + abortSignal: ctx.abort, + onAbort: () => { continueSessionSetup({ taskID: task.id, manager, @@ -108,16 +150,23 @@ export async function executeBackgroundTask( category: args.category, modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor, }) - break - } - await new Promise(resolve => setTimeout(resolve, timing.WAIT_FOR_SESSION_INTERVAL_MS)) + }, + }) + + const updatedTask = typeof manager.getTask === "function" + ? manager.getTask(task.id) + : undefined + if (!sessionId && (updatedTask?.status === "error" || updatedTask?.status === "cancelled" || updatedTask?.status === "interrupt")) { + return `Task failed to start (status: ${updatedTask.status}).\n\nTask ID: ${task.id}` } if (sessionId) { - executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, fallbackChain) - if (args.category) { - SessionCategoryRegistry.register(sessionId, args.category) - } + registerBackgroundSessionContext({ + sessionId, + fallbackChain, + category: args.category, + modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor, + }) } const resolvedModel = resolveMetadataModel(categoryModel, parentContext.model) From a17ba1673e0fa519b4ec0858fa961e4e0bc498e5 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:51:19 +0900 Subject: [PATCH 136/146] chore(delegate-task): remove unused metadata model export Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/resolve-metadata-model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/delegate-task/resolve-metadata-model.ts b/src/tools/delegate-task/resolve-metadata-model.ts index d4fa128b2..c35580142 100644 --- a/src/tools/delegate-task/resolve-metadata-model.ts +++ b/src/tools/delegate-task/resolve-metadata-model.ts @@ -1,6 +1,6 @@ import type { DelegatedModelConfig } from "./types" -export interface MetadataModel { +interface MetadataModel { providerID: string modelID: string variant?: string From 064dcc844e9cb1e2984b1c89a272552fe47b7841 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 20 Apr 2026 15:56:05 +0900 Subject: [PATCH 137/146] fix(delegate-task): remove deprecated sync continuation fallback Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/sync-continuation.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index 5a4b7f792..add3afd0d 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -6,7 +6,7 @@ import { getTaskToastManager } from "../../features/task-toast-manager" import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions" import { getMessageDir, normalizeSDKResponse } from "../../shared" import { promptWithModelSuggestionRetry } from "../../shared/model-suggestion-retry" -import { findNearestMessageWithFields } from "../../features/hook-message-injector" +import { resolveMessageContext } from "../../features/hook-message-injector" import { formatDuration } from "./time-formatter" import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continuation-deps" import { setSessionTools } from "../../shared/session-tools-store" @@ -49,11 +49,11 @@ async function resolveResumeContext( return { anchorMessageCount: messages.length } } catch { const resumeMessageDir = getMessageDir(continuationID) - const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null - const resumeMessageModel = resumeMessage?.model + const { prevMessage } = await resolveMessageContext(continuationID, client, resumeMessageDir) + const resumeMessageModel = prevMessage?.model return { - resumeAgent: resumeMessage?.agent, + resumeAgent: prevMessage?.agent, resumeModel: resumeMessageModel?.providerID && resumeMessageModel.modelID ? { providerID: resumeMessageModel.providerID, modelID: resumeMessageModel.modelID } : undefined, From 680dd161b40352c8f38f4ae2f1235f4d6389efe3 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 13:29:49 +0900 Subject: [PATCH 138/146] fix(model-capabilities): bundle gpt-5.4-mini-fast caps Keep the supplemental OpenAI model available when the bundled snapshot omits it.\nMerge its capabilities at runtime so downstream model resolution can use it. Co-authored-by: Sisyphus --- .../model-capabilities/bundled-snapshot.ts | 11 +++++++++- .../supplemental-entries.ts | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/shared/model-capabilities/supplemental-entries.ts diff --git a/src/shared/model-capabilities/bundled-snapshot.ts b/src/shared/model-capabilities/bundled-snapshot.ts index 65644a8cf..18ffec737 100644 --- a/src/shared/model-capabilities/bundled-snapshot.ts +++ b/src/shared/model-capabilities/bundled-snapshot.ts @@ -1,5 +1,6 @@ import bundledModelCapabilitiesSnapshotJson from "../../generated/model-capabilities.generated.json" +import { SUPPLEMENTAL_MODEL_CAPABILITIES } from "./supplemental-entries" import type { ModelCapabilitiesSnapshot } from "./types" function normalizeSnapshot( @@ -8,7 +9,15 @@ function normalizeSnapshot( return snapshot as ModelCapabilitiesSnapshot } -const bundledModelCapabilitiesSnapshot = normalizeSnapshot(bundledModelCapabilitiesSnapshotJson) +const normalizedBundledSnapshot = normalizeSnapshot(bundledModelCapabilitiesSnapshotJson) + +const bundledModelCapabilitiesSnapshot: ModelCapabilitiesSnapshot = { + ...normalizedBundledSnapshot, + models: { + ...normalizedBundledSnapshot.models, + ...SUPPLEMENTAL_MODEL_CAPABILITIES, + }, +} export function getBundledModelCapabilitiesSnapshot(): ModelCapabilitiesSnapshot { return bundledModelCapabilitiesSnapshot diff --git a/src/shared/model-capabilities/supplemental-entries.ts b/src/shared/model-capabilities/supplemental-entries.ts new file mode 100644 index 000000000..197d88001 --- /dev/null +++ b/src/shared/model-capabilities/supplemental-entries.ts @@ -0,0 +1,20 @@ +import type { ModelCapabilitiesSnapshotEntry } from "./types" + +export const SUPPLEMENTAL_MODEL_CAPABILITIES: Record = { + "gpt-5.4-mini-fast": { + id: "gpt-5.4-mini-fast", + family: "gpt-mini", + reasoning: true, + temperature: false, + toolCall: true, + modalities: { + input: ["text", "image", "pdf"], + output: ["text"], + }, + limit: { + context: 400000, + input: 272000, + output: 128000, + }, + }, +} From d2e5ddd73de06674134a90fec19e898bf7b4d13d Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 13:29:55 +0900 Subject: [PATCH 139/146] fix(model-requirements): route primary agents to mini-fast Use gpt-5.4-mini-fast as the primary runtime model for librarian and explore.\nKeep the fallback chain intact so older providers still resolve. Co-authored-by: Sisyphus --- src/shared/model-requirements.test.ts | 36 +++++++++++++++------------ src/shared/model-requirements.ts | 11 ++++---- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/shared/model-requirements.test.ts b/src/shared/model-requirements.test.ts index 3692677f7..258beb1a3 100644 --- a/src/shared/model-requirements.test.ts +++ b/src/shared/model-requirements.test.ts @@ -64,33 +64,38 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(last.model).toBe("big-pickle") }) - test("librarian has valid fallbackChain with opencode-go/minimax-m2.7 as primary", () => { + test("librarian has valid fallbackChain with openai/gpt-5.4-mini-fast as primary", () => { // given - librarian agent requirement const librarian = AGENT_MODEL_REQUIREMENTS["librarian"] // when - accessing librarian requirement - // then - fallbackChain exists with opencode-go/minimax-m2.7 as first entry + // then - fallbackChain exists with openai/gpt-5.4-mini-fast as first entry expect(librarian).toBeDefined() expect(librarian.fallbackChain).toBeArray() - expect(librarian.fallbackChain.length).toBeGreaterThan(0) + expect(librarian.fallbackChain).toHaveLength(5) const primary = librarian.fallbackChain[0] - expect(primary.providers[0]).toBe("opencode-go") - expect(primary.model).toBe("minimax-m2.7") + expect(primary.providers).toEqual(["openai"]) + expect(primary.model).toBe("gpt-5.4-mini-fast") const second = librarian.fallbackChain[1] - expect(second.providers[0]).toBe("opencode") + expect(second.providers[0]).toBe("opencode-go") expect(second.model).toBe("minimax-m2.7-highspeed") const tertiary = librarian.fallbackChain[2] - expect(tertiary.providers).toContain("anthropic") - expect(tertiary.model).toBe("claude-haiku-4-5") + expect(tertiary.providers[0]).toBe("opencode-go") + expect(tertiary.model).toBe("minimax-m2.7") const quaternary = librarian.fallbackChain[3] - expect(quaternary.model).toBe("gpt-5-nano") + expect(quaternary.providers).toContain("anthropic") + expect(quaternary.model).toBe("claude-haiku-4-5") + + const fifth = librarian.fallbackChain[4] + expect(fifth.providers).toContain("openai") + expect(fifth.model).toBe("gpt-5.4-nano") }) - test("explore has valid fallbackChain with grok-code-fast-1 as primary", () => { + test("explore has valid fallbackChain with openai/gpt-5.4-mini-fast as primary", () => { // given - explore agent requirement const explore = AGENT_MODEL_REQUIREMENTS["explore"] @@ -100,16 +105,15 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(explore.fallbackChain).toHaveLength(5) const primary = explore.fallbackChain[0] - expect(primary.providers).toContain("github-copilot") - expect(primary.providers).toContain("xai") - expect(primary.model).toBe("grok-code-fast-1") + expect(primary.providers).toEqual(["openai"]) + expect(primary.model).toBe("gpt-5.4-mini-fast") const secondary = explore.fallbackChain[1] expect(secondary.providers).toContain("opencode-go") expect(secondary.model).toBe("minimax-m2.7-highspeed") const tertiary = explore.fallbackChain[2] - expect(tertiary.providers).toContain("opencode") + expect(tertiary.providers).toContain("opencode-go") expect(tertiary.model).toBe("minimax-m2.7") const quaternary = explore.fallbackChain[3] @@ -117,8 +121,8 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(quaternary.model).toBe("claude-haiku-4-5") const fifth = explore.fallbackChain[4] - expect(fifth.providers).toContain("opencode") - expect(fifth.model).toBe("gpt-5-nano") + expect(fifth.providers).toContain("openai") + expect(fifth.model).toBe("gpt-5.4-nano") }) test("multimodal-looker has valid fallbackChain with gpt-5.4 as primary", () => { diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index 16f64cd6a..36771b4bc 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -77,19 +77,20 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, librarian: { fallbackChain: [ + { providers: ["openai"], model: "gpt-5.4-mini-fast" }, + { providers: ["opencode-go", "vercel"], model: "minimax-m2.7-highspeed" }, { providers: ["opencode-go", "vercel"], model: "minimax-m2.7" }, - { providers: ["opencode", "vercel"], model: "minimax-m2.7-highspeed" }, { providers: ["anthropic", "opencode", "vercel"], model: "claude-haiku-4-5" }, - { providers: ["opencode", "vercel"], model: "gpt-5-nano" }, + { providers: ["openai", "opencode", "vercel"], model: "gpt-5.4-nano" }, ], }, explore: { fallbackChain: [ - { providers: ["github-copilot", "xai", "vercel"], model: "grok-code-fast-1" }, + { providers: ["openai"], model: "gpt-5.4-mini-fast" }, { providers: ["opencode-go", "vercel"], model: "minimax-m2.7-highspeed" }, - { providers: ["opencode", "vercel"], model: "minimax-m2.7" }, + { providers: ["opencode-go", "vercel"], model: "minimax-m2.7" }, { providers: ["anthropic", "opencode", "vercel"], model: "claude-haiku-4-5" }, - { providers: ["opencode", "vercel"], model: "gpt-5-nano" }, + { providers: ["openai", "opencode", "vercel"], model: "gpt-5.4-nano" }, ], }, "multimodal-looker": { From ceadf4bdbc5f1acf0d13ea7c152ef9fbc1c7ebfc Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 13:30:02 +0900 Subject: [PATCH 140/146] fix(cli): prefer mini-fast for install fallback Default the install-time fallback chain to gpt-5.4-mini-fast for librarian and explore when OpenAI is available.\nKeep the snapshot and catalog tests aligned with the new resolution path. Co-authored-by: Sisyphus --- .../__snapshots__/model-fallback.test.ts.snap | 150 ++++++++++-------- src/cli/model-fallback.test.ts | 24 +-- src/cli/model-fallback.ts | 8 +- src/cli/openai-only-model-catalog.test.ts | 6 +- 4 files changed, 103 insertions(+), 85 deletions(-) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index dc2bac7a6..ce9ea35df 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -519,12 +519,31 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "model": "anthropic/claude-haiku-4-5", + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -718,12 +737,31 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "model": "anthropic/claude-haiku-4-5", + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -917,10 +955,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "explore": { "fallback_models": [ { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -1142,10 +1177,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "explore": { "fallback_models": [ { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -1369,11 +1401,6 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "model": "github-copilot/claude-sonnet-4.6", }, "explore": { - "fallback_models": [ - { - "model": "github-copilot/grok-code-fast-1", - }, - ], "model": "github-copilot/gpt-5-mini", }, "hephaestus": { @@ -1555,11 +1582,6 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "model": "github-copilot/claude-sonnet-4.6", }, "explore": { - "fallback_models": [ - { - "model": "github-copilot/grok-code-fast-1", - }, - ], "model": "github-copilot/gpt-5-mini", }, "hephaestus": { @@ -1869,14 +1891,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen }, "explore": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7", - }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "anthropic/claude-haiku-4-5", @@ -2153,10 +2172,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", + "model": "openai/gpt-5.4-nano", }, ], - "model": "github-copilot/gpt-5-mini", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -2168,6 +2187,14 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -2622,13 +2649,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -2645,14 +2666,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, "librarian": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7-highspeed", - }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "zai-coding-plan/glm-4.7", @@ -3020,19 +3038,19 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -3050,9 +3068,6 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe }, "librarian": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7-highspeed", - }, { "model": "anthropic/claude-haiku-4-5", }, @@ -3060,10 +3075,13 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "zai-coding-plan/glm-4.7", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "fallback_models": [ @@ -3571,19 +3589,19 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -3601,9 +3619,6 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is }, "librarian": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7-highspeed", - }, { "model": "anthropic/claude-haiku-4-5", }, @@ -3611,10 +3626,13 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "zai-coding-plan/glm-4.7", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "fallback_models": [ @@ -4120,9 +4138,6 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, "explore": { "fallback_models": [ - { - "model": "vercel/xai/grok-code-fast-1", - }, { "model": "vercel/minimax/minimax-m2.7", }, @@ -4130,7 +4145,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7-highspeed", @@ -4148,7 +4163,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7", @@ -4413,9 +4428,6 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, "explore": { "fallback_models": [ - { - "model": "vercel/xai/grok-code-fast-1", - }, { "model": "vercel/minimax/minimax-m2.7", }, @@ -4423,7 +4435,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7-highspeed", @@ -4441,7 +4453,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7", diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index 67fa83fd7..5d6d2915a 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -553,15 +553,15 @@ describe("generateModelConfig", () => { }) describe("special-case agents include fallback_models", () => { - test("explore includes fallback_models when Copilot and Claude are both available", () => { - // #given both Copilot and Claude are available - const config = createConfig({ hasCopilot: true, hasClaude: true }) + test("explore includes fallback_models when OpenAI and Claude are both available", () => { + // #given both OpenAI and Claude are available + const config = createConfig({ hasOpenAI: true, hasClaude: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then explore should have fallback_models from the remaining chain entries - expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5") + expect(result.agents?.explore?.model).toBe("openai/gpt-5.4-mini-fast") expect(result.agents?.explore?.fallback_models).toBeDefined() expect(result.agents?.explore?.fallback_models?.length).toBeGreaterThan(0) }) @@ -578,28 +578,28 @@ describe("generateModelConfig", () => { expect(result.agents?.explore?.fallback_models).toBeUndefined() }) - test("librarian includes fallback_models when opencode-go and Claude are both available", () => { - // #given opencode-go and Claude are available - const config = createConfig({ hasOpencodeGo: true, hasClaude: true }) + test("librarian includes fallback_models when OpenAI and opencode-go are both available", () => { + // #given OpenAI and opencode-go are available + const config = createConfig({ hasOpenAI: true, hasOpencodeGo: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then librarian should have fallback_models - expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") + expect(result.agents?.librarian?.model).toBe("openai/gpt-5.4-mini-fast") expect(result.agents?.librarian?.fallback_models).toBeDefined() expect(result.agents?.librarian?.fallback_models?.length).toBeGreaterThan(0) }) - test("librarian omits fallback_models when only one provider matches", () => { - // #given only opencode-go is available - const config = createConfig({ hasOpencodeGo: true }) + test("librarian omits fallback_models when only ZAI is available", () => { + // #given only ZAI is available + const config = createConfig({ hasZaiCodingPlan: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then librarian should not have fallback_models - expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") + expect(result.agents?.librarian?.model).toBe("zai-coding-plan/glm-4.7") expect(result.agents?.librarian?.fallback_models).toBeUndefined() }) }) diff --git a/src/cli/model-fallback.ts b/src/cli/model-fallback.ts index 088c4515e..6378482c6 100644 --- a/src/cli/model-fallback.ts +++ b/src/cli/model-fallback.ts @@ -127,7 +127,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) { if (role === "librarian") { let agentConfig: AgentConfig | undefined - if (avail.opencodeGo) { + if (avail.native.openai) { + agentConfig = { model: "openai/gpt-5.4-mini-fast" } + } else if (avail.opencodeGo) { agentConfig = { model: "opencode-go/minimax-m2.7" } } else if (avail.zai) { agentConfig = { model: ZAI_MODEL } @@ -142,7 +144,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { if (role === "explore") { let agentConfig: AgentConfig - if (avail.native.claude) { + if (avail.native.openai) { + agentConfig = { model: "openai/gpt-5.4-mini-fast" } + } else if (avail.native.claude) { agentConfig = { model: "anthropic/claude-haiku-4-5" } } else if (avail.opencodeZen) { agentConfig = { model: "opencode/claude-haiku-4-5" } diff --git a/src/cli/openai-only-model-catalog.test.ts b/src/cli/openai-only-model-catalog.test.ts index da544156c..91e910f60 100644 --- a/src/cli/openai-only-model-catalog.test.ts +++ b/src/cli/openai-only-model-catalog.test.ts @@ -54,8 +54,10 @@ describe("generateModelConfig OpenAI-only model catalog", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.explore).toMatchObject({ model: "opencode-go/minimax-m2.7" }) - expect(result.agents?.librarian).toMatchObject({ model: "opencode-go/minimax-m2.7" }) + expect(result.agents?.explore).toMatchObject({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.librarian).toMatchObject({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.explore).not.toMatchObject({ variant: "medium" }) + expect(result.agents?.librarian).not.toMatchObject({ variant: "medium" }) expect(result.categories?.quick).toMatchObject({ model: "openai/gpt-5.4-mini" }) }) }) From 02e4de865eb1add67855c9abba697e2d6b2f14bd Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 13:30:11 +0900 Subject: [PATCH 141/146] docs(model): sync explorer and librarian guidance Document the new primary chain and install-time fallback behavior for explorer and librarian.\nKeep the user-facing guidance aligned with the runtime and CLI model selection. Co-authored-by: Sisyphus --- docs/guide/agent-model-matching.md | 10 +++++----- docs/guide/orchestration.md | 4 ++-- docs/reference/configuration.md | 4 ++-- docs/reference/features.md | 4 ++-- src/agents/AGENTS.md | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/guide/agent-model-matching.md b/docs/guide/agent-model-matching.md index 8c750a9b2..c2115039b 100644 --- a/docs/guide/agent-model-matching.md +++ b/docs/guide/agent-model-matching.md @@ -92,8 +92,8 @@ These agents do grep, search, and retrieval. They intentionally use the fastest, | Agent | Role | Fallback Chain | Notes | | --------------------- | ------------------ | ---------------------------------------------- | ----------------------------------------------------- | -| **Explore** | Fast codebase grep | github-copilot\|xai\|vercel/grok-code-fast-1 → opencode-go\|vercel/minimax-m2.7-highspeed → opencode\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Librarian** | Docs/code search | opencode-go\|vercel/minimax-m2.7 → opencode\|vercel/minimax-m2.7-highspeed → anthropic\|opencode\|vercel/claude-haiku-4-5 → opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Explore** | Fast codebase grep | openai/gpt-5.4-mini-fast → opencode-go\|vercel/minimax-m2.7-highspeed → opencode-go\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → openai\|opencode\|vercel/gpt-5.4-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Librarian** | Docs/code search | openai/gpt-5.4-mini-fast → opencode-go\|vercel/minimax-m2.7-highspeed → opencode-go\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → openai\|opencode\|vercel/gpt-5.4-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Multimodal Looker** | Vision/screenshots | openai\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/kimi-k2.5 → zai-coding-plan\|vercel/glm-4.6v → openai\|github-copilot\|opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Sisyphus-Junior** | Category executor | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | @@ -130,7 +130,7 @@ Principle-driven, explicit reasoning, deep technical capability. Best for agents | -------------------- | ------------------------------------------------------------------------------------------------------------ | | **Gemini 3.1 Pro** | Excels at visual/frontend tasks. Different reasoning style. Default for `visual-engineering` and `artistry`. | | **Gemini 3 Flash** | Fast. Good for doc search and light tasks. | -| **Grok Code Fast 1** | Blazing fast code grep. Default for Explore agent. | +| **GPT-5.4 Mini Fast** | Default for Explore and Librarian agents. Blazing-fast reasoning-capable mini model. | | **MiniMax M2.7** | Fast and smart. Used in OpenCode Go and OpenCode Zen utility fallback chains. | | **MiniMax M2.7 Highspeed** | High-speed OpenCode catalog entry used in utility fallback chains that prefer the fastest available MiniMax path. | @@ -144,8 +144,8 @@ A premium subscription tier ($10/month) that provides reliable access to Chinese | ------------------------ | --------------------------------------------------------------------- | | **opencode-go/kimi-k2.5** | Vision-capable, Claude-like reasoning. Used by Sisyphus, Atlas, Sisyphus-Junior, Multimodal Looker. | | **opencode-go/glm-5** | Text-only orchestration model. Used by Oracle, Prometheus, Metis, Momus. | -| **opencode-go/minimax-m2.7** | Ultra-cheap, fast responses. Used by Librarian, Atlas, and Sisyphus-Junior for utility work. | -| **opencode-go/minimax-m2.7-highspeed** | Even faster OpenCode Go MiniMax entry used by Explore when the high-speed catalog entry is available. | +| **opencode-go/minimax-m2.7** | Ultra-cheap, fast responses. Used by Atlas, Sisyphus-Junior, Explore and Librarian fallbacks for utility work. | +| **opencode-go/minimax-m2.7-highspeed** | Even faster OpenCode Go MiniMax entry used as a secondary fallback for Explore and Librarian when GPT-5.4 Mini Fast is unavailable. | **When It Gets Used:** diff --git a/docs/guide/orchestration.md b/docs/guide/orchestration.md index 0e21ce50a..0513be3f1 100644 --- a/docs/guide/orchestration.md +++ b/docs/guide/orchestration.md @@ -47,8 +47,8 @@ flowchart TB subgraph Workers["Worker Layer (Specialized Agents)"] Junior[" Sisyphus-Junior
(Task Executor)
claude-sonnet-4-6 / kimi-k2.5 / gpt-5.4 / minimax-m2.7"] Oracle[" Oracle
(Architecture)
gpt-5.4 / gemini-3.1-pro / claude-opus-4-7 / glm-5"] - Explore[" Explore
(Codebase Grep)
grok-code-fast-1 / minimax-m2.7-highspeed / claude-haiku-4-5"] - Librarian[" Librarian
(Docs/OSS)
minimax-m2.7 / minimax-m2.7-highspeed / claude-haiku-4-5"] +Explore[" Explore
(Codebase Grep)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] +Librarian[" Librarian
(Docs/OSS)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] Frontend[" visual-engineering
(category + frontend-ui-ux)
gemini-3.1-pro / glm-5 / claude-opus-4-7"] end diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 04f510b6d..c6513bfe8 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -358,8 +358,8 @@ Capability data comes from provider runtime metadata first. OmO also ships bundl | **Sisyphus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle` | | **Hephaestus** | `gpt-5.4` | `gpt-5.4 (medium)` | | **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` | -| **librarian** | `minimax-m2.7` | `opencode-go/minimax-m2.7` → `opencode/minimax-m2.7-highspeed` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano` | -| **explore** | `grok-code-fast-1` | `github-copilot\|xai/grok-code-fast-1` → `opencode-go/minimax-m2.7-highspeed` → `opencode/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano` | +| **librarian** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano` | +| **explore** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano` | | **multimodal-looker** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (medium)` → `opencode-go/kimi-k2.5` → `zai-coding-plan/glm-4.6v` → `openai\|github-copilot\|opencode/gpt-5-nano` | | **Prometheus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro` | | **Metis** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | diff --git a/docs/reference/features.md b/docs/reference/features.md index 366554b6c..ab5f3925c 100644 --- a/docs/reference/features.md +++ b/docs/reference/features.md @@ -13,8 +13,8 @@ Core-agent tab cycling is deterministic via injected runtime order field. The fi | **Sisyphus** | `claude-opus-4-7` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle`. | | **Hephaestus** | `gpt-5.4` | The Legitimate Craftsman. Autonomous deep worker inspired by AmpCode's deep mode. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end without premature stopping. Named after the Greek god of forge and craftsmanship. Requires a GPT-capable provider. | | **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5`. | -| **Librarian** | `minimax-m2.7` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode/minimax-m2.7-highspeed` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano`. | -| **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed` → `opencode/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano`. | +| **Librarian** | `gpt-5.4-mini-fast` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano`. | +| **Explore** | `gpt-5.4-mini-fast` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano`. | | **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `opencode-go/kimi-k2.5` → `zai-coding-plan/glm-4.6v` → `openai\|github-copilot\|opencode/gpt-5-nano`. | ### Planning Agents diff --git a/src/agents/AGENTS.md b/src/agents/AGENTS.md index f92c44406..c69c0608a 100644 --- a/src/agents/AGENTS.md +++ b/src/agents/AGENTS.md @@ -13,8 +13,8 @@ Agent factories following `createXXXAgent(model) → AgentConfig` pattern. Each | **Sisyphus** | claude-opus-4-7 max | 0.1 | all | k2p5 -> kimi-k2.5 -> gpt-5.4 medium -> glm-5 -> big-pickle | Main orchestrator, plans + delegates | | **Hephaestus** | gpt-5.4 medium | 0.1 | all | — | Autonomous deep worker | | **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high -> claude-opus-4-7 max | Read-only consultation | -| **Librarian** | minimax-m2.7 | 0.1 | subagent | minimax-m2.7-highspeed -> claude-haiku-4-5 -> gpt-5-nano | External docs/code search | -| **Explore** | grok-code-fast-1 | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5-nano | Contextual grep | +| **Librarian** | gpt-5.4-mini-fast | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5.4-nano | External docs/code search | +| **Explore** | gpt-5.4-mini-fast | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5.4-nano | Contextual grep | | **Multimodal-Looker** | gpt-5.3-codex medium | 0.1 | subagent | k2p5 -> gemini-3-flash -> glm-4.6v -> gpt-5-nano | PDF/image analysis | | **Metis** | claude-opus-4-7 max | **0.3** | subagent | gpt-5.4 high -> gemini-3.1-pro high | Pre-planning consultant | | **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-7 max -> gemini-3.1-pro high | Plan reviewer | From fe44363bf826535a708a86a6991f25b6f16e701f Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 13:38:23 +0900 Subject: [PATCH 142/146] fix(model-capabilities): drop pdf modality from gpt-5.4-mini-fast OpenAI's mini-fast variant only accepts text and image input; advertising pdf risks unsupported requests hitting runtime errors. --- src/shared/model-capabilities/supplemental-entries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/model-capabilities/supplemental-entries.ts b/src/shared/model-capabilities/supplemental-entries.ts index 197d88001..87a35f71c 100644 --- a/src/shared/model-capabilities/supplemental-entries.ts +++ b/src/shared/model-capabilities/supplemental-entries.ts @@ -8,7 +8,7 @@ export const SUPPLEMENTAL_MODEL_CAPABILITIES: Record Date: Tue, 21 Apr 2026 13:38:23 +0900 Subject: [PATCH 143/146] docs(configuration): restore vercel aliases in explore/librarian rows Align documented fallback provider lists with the runtime chain in model-requirements.ts so operators see the same providers that resolve at runtime. --- docs/reference/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index c6513bfe8..3f59a7f7c 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -358,8 +358,8 @@ Capability data comes from provider runtime metadata first. OmO also ships bundl | **Sisyphus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle` | | **Hephaestus** | `gpt-5.4` | `gpt-5.4 (medium)` | | **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` | -| **librarian** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano` | -| **explore** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano` | +| **librarian** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go\|vercel/minimax-m2.7-highspeed` → `opencode-go\|vercel/minimax-m2.7` → `anthropic\|opencode\|vercel/claude-haiku-4-5` → `openai\|opencode\|vercel/gpt-5.4-nano` | +| **explore** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go\|vercel/minimax-m2.7-highspeed` → `opencode-go\|vercel/minimax-m2.7` → `anthropic\|opencode\|vercel/claude-haiku-4-5` → `openai\|opencode\|vercel/gpt-5.4-nano` | | **multimodal-looker** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (medium)` → `opencode-go/kimi-k2.5` → `zai-coding-plan/glm-4.6v` → `openai\|github-copilot\|opencode/gpt-5-nano` | | **Prometheus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro` | | **Metis** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | From 3a6bd932525c0d6fa54bfddcb4736a3c4242bfd7 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 14:23:39 +0900 Subject: [PATCH 144/146] fix(cli): keep mini-fast primary in openai-only install catalog OPENAI_ONLY_AGENT_OVERRIDES was rewriting explore and librarian back to gpt-5.4 medium for OpenAI-only installs. Match the runtime primary so the install default stays on gpt-5.4-mini-fast. --- src/cli/__snapshots__/model-fallback.test.ts.snap | 12 ++++-------- src/cli/model-fallback.test.ts | 6 +++--- src/cli/openai-only-model-catalog.test.ts | 4 ++-- src/cli/openai-only-model-catalog.ts | 4 ++-- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index ce9ea35df..ddc9a60a0 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -206,16 +206,14 @@ exports[`generateModelConfig single native provider uses OpenAI models when only "variant": "medium", }, "explore": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "model": "openai/gpt-5.4", @@ -296,16 +294,14 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa "variant": "medium", }, "explore": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "model": "openai/gpt-5.4", diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index 5d6d2915a..ec27d40c6 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -355,9 +355,9 @@ describe("generateModelConfig", () => { // #when generateModelConfig is called const result = generateModelConfig(config) - // #then explore should use native OpenAI model - expect(result.agents?.explore?.model).toBe("openai/gpt-5.4") - expect(result.agents?.explore?.variant).toBe("medium") + // #then explore should use native OpenAI mini-fast (primary model) + expect(result.agents?.explore?.model).toBe("openai/gpt-5.4-mini-fast") + expect(result.agents?.explore?.variant).toBeUndefined() }) test("explore uses gpt-5-mini when only Copilot available", () => { diff --git a/src/cli/openai-only-model-catalog.test.ts b/src/cli/openai-only-model-catalog.test.ts index 91e910f60..7c94aa850 100644 --- a/src/cli/openai-only-model-catalog.test.ts +++ b/src/cli/openai-only-model-catalog.test.ts @@ -28,8 +28,8 @@ describe("generateModelConfig OpenAI-only model catalog", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.explore).toEqual({ model: "openai/gpt-5.4", variant: "medium" }) - expect(result.agents?.librarian).toEqual({ model: "openai/gpt-5.4", variant: "medium" }) + expect(result.agents?.explore).toEqual({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.librarian).toEqual({ model: "openai/gpt-5.4-mini-fast" }) }) test("fills remaining OpenAI-only category gaps with OpenAI models", () => { diff --git a/src/cli/openai-only-model-catalog.ts b/src/cli/openai-only-model-catalog.ts index 186b600b2..36d6ca802 100644 --- a/src/cli/openai-only-model-catalog.ts +++ b/src/cli/openai-only-model-catalog.ts @@ -1,8 +1,8 @@ import type { AgentConfig, CategoryConfig, GeneratedOmoConfig, ProviderAvailability } from "./model-fallback-types" const OPENAI_ONLY_AGENT_OVERRIDES: Record = { - explore: { model: "openai/gpt-5.4", variant: "medium" }, - librarian: { model: "openai/gpt-5.4", variant: "medium" }, + explore: { model: "openai/gpt-5.4-mini-fast" }, + librarian: { model: "openai/gpt-5.4-mini-fast" }, } const OPENAI_ONLY_CATEGORY_OVERRIDES: Record = { From 993fe20a1218074e7f92a756831fb7aa3ed60f2b Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 21 Apr 2026 14:23:39 +0900 Subject: [PATCH 145/146] docs(orchestration): reindent explore/librarian mermaid nodes Align with sibling Junior/Oracle/Frontend nodes in the Worker Layer subgraph. --- docs/guide/orchestration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/orchestration.md b/docs/guide/orchestration.md index 0513be3f1..b25a93bbb 100644 --- a/docs/guide/orchestration.md +++ b/docs/guide/orchestration.md @@ -47,8 +47,8 @@ flowchart TB subgraph Workers["Worker Layer (Specialized Agents)"] Junior[" Sisyphus-Junior
(Task Executor)
claude-sonnet-4-6 / kimi-k2.5 / gpt-5.4 / minimax-m2.7"] Oracle[" Oracle
(Architecture)
gpt-5.4 / gemini-3.1-pro / claude-opus-4-7 / glm-5"] -Explore[" Explore
(Codebase Grep)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] -Librarian[" Librarian
(Docs/OSS)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] + Explore[" Explore
(Codebase Grep)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] + Librarian[" Librarian
(Docs/OSS)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] Frontend[" visual-engineering
(category + frontend-ui-ux)
gemini-3.1-pro / glm-5 / claude-opus-4-7"] end From e0bcf3e2f91ac7a5345807e96f50d3c529222d69 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 10:06:24 +0000 Subject: [PATCH 146/146] @aschina has signed the CLA in code-yeongyu/oh-my-openagent#3560 --- signatures/cla.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/signatures/cla.json b/signatures/cla.json index d6c62243a..dddea1ad0 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2887,6 +2887,14 @@ "created_at": "2026-04-19T03:28:19Z", "repoId": 1108837393, "pullRequestNo": 3518 + }, + { + "name": "aschina", + "id": 31149103, + "comment_id": 4287617163, + "created_at": "2026-04-21T10:00:13Z", + "repoId": 1108837393, + "pullRequestNo": 3560 } ] } \ No newline at end of file