Compare commits

...

6 Commits

Author SHA1 Message Date
Aiden Cline 9e7b5f1701 feat(opencode): cache-friendly compaction via primary loop request path
Default compaction no longer uses a dedicated compaction agent. It inherits
the session's active agent and delegates request assembly to the primary
loop's shared envelope (same system prompt, instructions, skills, MCP
context, and tool definitions), replaying the typed message head and
appending the summary instruction as the final user message. This keeps the
compaction request prefix-identical to the preceding turn so provider
prompt/KV caches are reused instead of fully re-prefilled.

An explicitly configured agent.compaction preserves the legacy behavior
exactly: dedicated hidden agent, optional model override, and the
serialized-transcript summary request.
2026-08-13 23:10:07 -05:00
Jack d0c2b41adf docs(go): use responses API for Grok 4.5 (#42373) 2026-08-14 01:28:55 +08:00
Frank c7af47f9ed update grok endpoint 2026-08-13 13:27:41 -04:00
Kit Langton 6c035e1fd7 fix(core): preserve unicode in grep previews (#42356) 2026-08-13 16:51:43 +00:00
opencode-agent[bot] ab7cbc808f chore: generate 2026-08-13 16:30:12 +00:00
Aditya Sethi 62387f39d4 fix(skills): Update global config path in documentation (#42337) 2026-08-13 18:27:29 +02:00
28 changed files with 332 additions and 126 deletions
@@ -40,7 +40,7 @@ already-loaded config until then.
| Scope | Path |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Project config | `./opencode.json`, `./opencode.jsonc`, or `.opencode/opencode.json` (opencode walks up from the cwd to the worktree root) |
| Global config | `~/.config/opencode/opencode.json` (NOT `~/.opencode/`) |
| Global config | `~/.config/opencode/opencode.json` or `~/.config/opencode/opencode.jsonc` (NOT `~/.opencode/`) |
| Project agents | `.opencode/agent/<name>.md` or `.opencode/agents/<name>.md` |
| Global agents | `~/.config/opencode/agent(s)/<name>.md` |
| Project commands | `.opencode/command/<name>.md` or `.opencode/commands/<name>.md` |
+4 -1
View File
@@ -264,7 +264,10 @@ const layer = Layer.effect(
}),
line: match.line_number,
offset: match.absolute_offset,
text: match.lines.text.length > 2_000 ? match.lines.text.slice(0, 2_000) + "..." : match.lines.text,
text:
match.lines.text.length > 2_000
? match.lines.text.slice(0, 2_000).replace(/[\uD800-\uDBFF]$/, "") + "..."
: match.lines.text,
submatches: match.submatches.map((submatch) => ({
text: submatch.match.text,
start: submatch.start,
+12
View File
@@ -173,6 +173,18 @@ export const buildPrompt = (input: { readonly previousSummary?: string; readonly
].join("\n\n")
}
export const buildReplayPrompt = (previousSummary?: string) => {
const instruction =
"Create a new anchored summary from the conversation messages above so another coding agent can continue the work."
if (!previousSummary) return [instruction, SUMMARY_TEMPLATE].join("\n\n")
return [
instruction,
`Here is the summary of the conversation before the messages above:\n\n<prior-summary>\n${previousSummary}\n</prior-summary>`,
SUMMARY_UPDATE_INSTRUCTIONS,
SUMMARY_TEMPLATE,
].join("\n\n")
}
export const make = (dependencies: Dependencies) => {
const config = settings(dependencies.config)
const compactAfterOverflow = Effect.fn("SessionCompaction.compactAfterOverflow")(function* (input: Input) {
+20
View File
@@ -62,4 +62,24 @@ describe("Ripgrep", () => {
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
),
)
it.live("does not split surrogate pairs in oversized line previews", () =>
Effect.acquireUseRelease(
Effect.promise(() => tmpdir()),
(tmp) =>
Effect.gen(function* () {
yield* Effect.promise(() =>
fs.writeFile(path.join(tmp.path, "unicode.txt"), `needle${"x".repeat(1_993)}😀\n`),
)
const matches = yield* (yield* Ripgrep.Service).grep({
cwd: tmp.path,
pattern: "needle",
limit: 10,
})
expect(matches[0]?.text).toBe(`needle${"x".repeat(1_993)}...`)
}),
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
),
)
})
+20 -15
View File
@@ -216,21 +216,6 @@ const layer = Layer.effect(
mode: "subagent",
native: true,
},
compaction: {
name: "compaction",
mode: "primary",
native: true,
hidden: true,
prompt: PROMPT_COMPACTION,
permission: Permission.merge(
defaults,
Permission.fromConfig({
"*": "deny",
}),
user,
),
options: {},
},
title: {
name: "title",
mode: "primary",
@@ -270,6 +255,26 @@ const layer = Layer.effect(
continue
}
let item = agents[key]
// The compaction agent is not registered by default: compaction inherits
// the session's active agent so its request stays prefix-identical for
// prompt caching. An explicit `agent.compaction` config opts into the
// legacy dedicated agent, seeded here so overrides merge as before.
if (!item && key === "compaction")
item = agents[key] = {
name: "compaction",
mode: "primary",
native: true,
hidden: true,
prompt: PROMPT_COMPACTION,
permission: Permission.merge(
defaults,
Permission.fromConfig({
"*": "deny",
}),
user,
),
options: {},
}
if (!item)
item = agents[key] = {
name: key,
+61 -37
View File
@@ -20,7 +20,7 @@ import { RuntimeFlags } from "@/effect/runtime-flags"
import { EventV2Bridge } from "@/event-v2-bridge"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { ModelV2 } from "@opencode-ai/core/model"
import { buildPrompt } from "@opencode-ai/core/session/compaction"
import { buildPrompt, buildReplayPrompt } from "@opencode-ai/core/session/compaction"
import { SessionCompactionEvent } from "@opencode-ai/schema/session-compaction-event"
export const Event = SessionCompactionEvent
@@ -162,6 +162,15 @@ function splitTurn(input: {
})
}
export type Run = (input: {
user: SessionV1.User
agent: Agent.Info
model: Provider.Model
processor: SessionProcessor.Handle
messages: SessionV1.WithParts[]
prompt: string
}) => Effect.Effect<SessionProcessor.Result>
export interface Interface {
readonly isOverflow: (input: {
tokens: SessionV1.Assistant["tokens"]
@@ -174,6 +183,7 @@ export interface Interface {
sessionID: SessionID
auto: boolean
overflow?: boolean
run?: Run
}) => Effect.Effect<"continue" | "stop">
readonly create: (input: {
sessionID: SessionID
@@ -322,6 +332,7 @@ const layer = Layer.effect(
sessionID: SessionID
auto: boolean
overflow?: boolean
run?: Run
}) {
const parent = input.messages.findLast((m) => m.info.id === input.parentID)
if (!parent || parent.info.role !== "user") {
@@ -355,11 +366,13 @@ const layer = Layer.effect(
}
}
const agent = yield* agents.get("compaction")
const model = agent.model
? yield* provider.getModel(agent.model.providerID, agent.model.modelID).pipe(Effect.orDie)
: yield* provider.getModel(userMessage.model.providerID, userMessage.model.modelID).pipe(Effect.orDie)
const cfg = yield* config.get()
const configured = cfg.agent?.compaction !== undefined
const agent = yield* agents.get(configured ? "compaction" : userMessage.agent)
const model =
configured && agent.model
? yield* provider.getModel(agent.model.providerID, agent.model.modelID).pipe(Effect.orDie)
: yield* provider.getModel(userMessage.model.providerID, userMessage.model.modelID).pipe(Effect.orDie)
const history = compactionPart && messages.at(-1)?.info.id === input.parentID ? messages.slice(0, -1) : messages
const prior = completedCompactions(history)
const hidden = new Set(prior.flatMap((item) => [item.userIndex, item.assistantIndex]))
@@ -377,18 +390,16 @@ const layer = Layer.effect(
)
const msgs = structuredClone(selected.head)
yield* plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs })
const conversation = msgs.map(serialize).filter(Boolean).join("\n\n")
const nextPrompt =
// A configured compaction agent keeps the legacy serialized-transcript path.
const run = configured ? undefined : input.run
const conversation = run ? "" : msgs.map(serialize).filter(Boolean).join("\n\n")
const nextPrompt = [
compacting.prompt ??
[
buildPrompt({
previousSummary,
context: [conversation],
}),
...compacting.context,
]
.filter(Boolean)
.join("\n\n")
(run ? buildReplayPrompt(previousSummary) : buildPrompt({ previousSummary, context: [conversation] })),
...compacting.context,
]
.filter(Boolean)
.join("\n\n")
const ctx = yield* InstanceState.context
const msg: SessionV1.Assistant = {
id: MessageID.ascending(),
@@ -422,30 +433,43 @@ const layer = Layer.effect(
sessionID: input.sessionID,
model,
})
const result = yield* processor.process({
user: userMessage,
agent,
sessionID: input.sessionID,
tools: {},
system: [],
messages: [
{
role: "user",
content: [
// The synthetic compaction marker carries no per-turn system/tools settings.
const active = msgs.findLast(
(message) => message.info.role === "user" && !message.parts.some((part) => part.type === "compaction"),
)
const result = run
? yield* run({
user: active?.info.role === "user" ? active.info : userMessage,
agent,
model,
processor,
messages: msgs,
prompt: nextPrompt,
})
: yield* processor.process({
user: userMessage,
agent,
sessionID: input.sessionID,
tools: {},
system: [],
messages: [
{
type: "text",
text: [
nextPrompt,
...(compacting.prompt ? ["The following is the conversation history:", conversation] : []),
]
.filter(Boolean)
.join("\n\n"),
role: "user",
content: [
{
type: "text",
text: [
nextPrompt,
...(compacting.prompt ? ["The following is the conversation history:", conversation] : []),
]
.filter(Boolean)
.join("\n\n"),
},
],
},
],
},
],
model,
})
model,
})
if (result === "compact") {
processor.message.error = new SessionV1.ContextOverflowError({
+67 -47
View File
@@ -149,6 +149,45 @@ const layer = Layer.effect(
} satisfies TaskPromptOps
})
// One assembly path keeps compaction requests prefix-identical to normal turns for prompt caching.
const prepare = Effect.fn("SessionPrompt.prepare")(function* (input: {
session: Session.Info
agent: Agent.Info
model: Provider.Model
processor: SessionProcessor.Handle
messages: SessionV1.WithParts[]
}) {
const lastUserMsg = input.messages.findLast((message) => message.info.role === "user")
const tools = yield* SessionTools.resolve({
agent: input.agent,
session: input.session,
model: input.model,
processor: input.processor,
bypassAgentCheck: lastUserMsg?.parts.some((part) => part.type === "agent") ?? false,
messages: input.messages,
promptOps: yield* ops(),
}).pipe(
Effect.provideService(Plugin.Service, plugin),
Effect.provideService(Permission.Service, permission),
Effect.provideService(ToolRegistry.Service, registry),
Effect.provideService(MCP.Service, mcp),
Effect.provideService(Truncate.Service, truncate),
Effect.provideService(RuntimeFlags.Service, flags),
)
const [skills, env, instructions, mcpInstructions, modelMessages] = yield* Effect.all([
sys.skills(input.agent),
sys.environment(input.model),
instruction.system().pipe(Effect.orDie),
sys.mcp(input.agent, input.session.permission),
MessageV2.toModelMessagesEffect(input.messages, input.model),
])
return {
tools,
modelMessages,
system: [...env, ...instructions, ...(mcpInstructions ? [mcpInstructions] : []), ...(skills ? [skills] : [])],
}
})
const cancel = Effect.fn("SessionPrompt.cancel")(function* (sessionID: SessionID) {
yield* Effect.logInfo("cancel", { "session.id": sessionID })
yield* state.cancel(sessionID)
@@ -1153,6 +1192,21 @@ const layer = Layer.effect(
sessionID,
auto: task.auto,
overflow: task.overflow,
run: ({ user, agent, model, processor, messages, prompt }) =>
Effect.gen(function* () {
const prepared = yield* prepare({ session, agent, model, processor, messages })
return yield* processor.process({
user,
agent,
permission: session.permission,
sessionID,
parentSessionID: session.parentID,
system: prepared.system,
messages: [...prepared.modelMessages, { role: "user", content: prompt }],
tools: prepared.tools,
model,
})
}),
})
if (result === "stop") break
continue
@@ -1219,68 +1273,34 @@ const layer = Layer.effect(
.pipe(Effect.onInterrupt(() => finalizeInterruptedAssistant))
const outcome: "break" | "continue" = yield* Effect.gen(function* () {
const lastUserMsg = msgs.findLast((m) => m.info.role === "user")
const bypassAgentCheck = lastUserMsg?.parts.some((p) => p.type === "agent") ?? false
const promptOps = yield* ops()
const tools = yield* SessionTools.resolve({
agent,
session,
model,
processor: handle,
bypassAgentCheck,
messages: msgs,
promptOps,
}).pipe(
Effect.provideService(Plugin.Service, plugin),
Effect.provideService(Permission.Service, permission),
Effect.provideService(ToolRegistry.Service, registry),
Effect.provideService(MCP.Service, mcp),
Effect.provideService(Truncate.Service, truncate),
Effect.provideService(RuntimeFlags.Service, flags),
)
if (lastUser.format?.type === "json_schema") {
tools["StructuredOutput"] = createStructuredOutputTool({
schema: lastUser.format.schema,
onSuccess(output) {
structured = output
},
})
}
if (step === 1)
yield* summary.summarize({ sessionID, messageID: lastUser.id }).pipe(Effect.ignore, Effect.forkIn(scope))
yield* plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs })
const [skills, env, instructions, mcpInstructions, modelMsgs] = yield* Effect.all([
sys.skills(agent),
sys.environment(model),
instruction.system().pipe(Effect.orDie),
sys.mcp(agent, session.permission),
MessageV2.toModelMessagesEffect(msgs, model),
])
const system = [
...env,
...instructions,
...(mcpInstructions ? [mcpInstructions] : []),
...(skills ? [skills] : []),
]
const prepared = yield* prepare({ session, agent, model, processor: handle, messages: msgs })
const format = lastUser.format ?? { type: "text" as const }
if (format.type === "json_schema") system.push(STRUCTURED_OUTPUT_SYSTEM_PROMPT)
if (format.type === "json_schema") {
prepared.system.push(STRUCTURED_OUTPUT_SYSTEM_PROMPT)
prepared.tools["StructuredOutput"] = createStructuredOutputTool({
schema: format.schema,
onSuccess(output) {
structured = output
},
})
}
const result = yield* handle.process({
user: lastUser,
agent,
permission: session.permission,
sessionID,
parentSessionID: session.parentID,
system,
system: prepared.system,
messages: [
...modelMsgs,
...prepared.modelMessages,
...(isLastStep ? [{ role: "assistant" as const, content: MAX_STEPS_PROMPT }] : []),
],
tools,
tools: prepared.tools,
model,
toolChoice: format.type === "json_schema" ? "required" : undefined,
})
+27 -7
View File
@@ -52,7 +52,7 @@ it.instance("returns default native agents when no config", () =>
expect(names).toContain("plan")
expect(names).toContain("general")
expect(names).toContain("explore")
expect(names).toContain("compaction")
expect(names).not.toContain("compaction")
expect(names).toContain("title")
expect(names).toContain("summary")
}),
@@ -170,17 +170,34 @@ it.instance("general agent denies todo tools", () =>
}),
)
it.instance("compaction agent denies all permissions", () =>
it.instance("compaction agent is absent without configuration", () =>
Effect.gen(function* () {
const compaction = yield* load((svc) => svc.get("compaction"))
expect(compaction).toBeDefined()
expect(compaction?.hidden).toBe(true)
expect(evalPerm(compaction, "bash")).toBe("deny")
expect(evalPerm(compaction, "edit")).toBe("deny")
expect(evalPerm(compaction, "read")).toBe("deny")
expect(compaction).toBeUndefined()
}),
)
it.instance(
"configured compaction agent keeps native defaults",
() =>
Effect.gen(function* () {
const compaction = yield* load((svc) => svc.get("compaction"))
expect(compaction).toBeDefined()
expect(compaction?.native).toBe(true)
expect(compaction?.hidden).toBe(true)
expect(evalPerm(compaction, "bash")).toBe("deny")
expect(evalPerm(compaction, "edit")).toBe("deny")
expect(evalPerm(compaction, "read")).toBe("deny")
}),
{
config: {
agent: {
compaction: {},
},
},
},
)
it.instance(
"custom agent from config creates new agent",
() =>
@@ -710,6 +727,9 @@ it.instance(
{
config: {
default_agent: "compaction",
agent: {
compaction: {},
},
},
},
)
@@ -222,6 +222,11 @@ function cfg(compaction?: ConfigV1.Info["compaction"]) {
return Layer.succeed(Config.Service, TestConfig.make({ get: () => Effect.succeed({ ...base, compaction }) }))
}
function cfgAgent(agent: NonNullable<ConfigV1.Info["agent"]>) {
const config = Schema.decodeUnknownSync(ConfigV1.Info)({ agent }) as ConfigV1.Info
return Layer.succeed(Config.Service, TestConfig.make({ get: () => Effect.succeed(config) }))
}
const defaultProvider = wide()
const compactionTestNode = LayerNode.group([
SessionCompaction.node,
@@ -812,6 +817,75 @@ describe("session.compaction.prune", () => {
})
describe("session.compaction.process", () => {
itCompaction.instance(
"inherits the last agent when compaction is not configured",
() => {
const stub = llm()
let captured: LLM.StreamInput | undefined
stub.push(reply("summary", (input) => (captured = input)))
return Effect.gen(function* () {
const ssn = yield* SessionNs.Service
const session = yield* ssn.create({})
const msg = yield* createUserMessage(session.id, "hello")
const msgs = yield* ssn.messages({ sessionID: session.id })
yield* SessionCompaction.use.process({
parentID: msg.id,
messages: msgs,
sessionID: session.id,
auto: false,
})
expect(captured?.agent.name).toBe("build")
expect(captured?.agent.prompt).toBe("custom build prompt")
expect(captured?.agent.temperature).toBe(0.37)
expect(String(captured?.model.providerID)).toBe("test")
expect(String(captured?.model.id)).toBe("test-model")
}).pipe(
withCompaction({
llm: stub.llmLayer,
config: cfgAgent({
build: { prompt: "custom build prompt", temperature: 0.37, model: "missing/missing" },
}),
}),
)
},
{ git: true },
)
itCompaction.instance(
"preserves an explicitly configured compaction agent",
() => {
const stub = llm()
let captured: LLM.StreamInput | undefined
stub.push(reply("summary", (input) => (captured = input)))
return Effect.gen(function* () {
const ssn = yield* SessionNs.Service
const session = yield* ssn.create({})
const msg = yield* createUserMessage(session.id, "hello")
const msgs = yield* ssn.messages({ sessionID: session.id })
yield* SessionCompaction.use.process({
parentID: msg.id,
messages: msgs,
sessionID: session.id,
auto: false,
})
expect(captured?.agent.name).toBe("compaction")
expect(captured?.agent.prompt).toBe("custom compaction prompt")
expect(captured?.agent.temperature).toBe(0.81)
expect(captured?.agent.hidden).toBe(true)
}).pipe(
withCompaction({
llm: stub.llmLayer,
config: cfgAgent({ compaction: { prompt: "custom compaction prompt", temperature: 0.81 } }),
}),
)
},
{ git: true },
)
it.instance(
"throws when parent is not a user message",
Effect.gen(function* () {
@@ -444,6 +444,34 @@ const boot = Effect.fn("test.boot")(function* (input?: { title?: string }) {
// Loop semantics
it.instance("default compaction reuses the normal system and tools", () =>
Effect.gen(function* () {
const { llm } = yield* useServerConfig(providerCfg)
const { prompt, chat } = yield* boot()
const compact = yield* SessionCompaction.Service
yield* user(chat.id, "cache prefix message")
yield* llm.text("normal response")
yield* prompt.loop({ sessionID: chat.id })
yield* compact.create({ sessionID: chat.id, agent: "build", model: ref, auto: false })
yield* llm.text("compacted summary")
yield* prompt.loop({ sessionID: chat.id })
const inputs = yield* llm.inputs
expect(inputs).toHaveLength(2)
expect(inputs[1]?.tools).toEqual(inputs[0]?.tools)
const normalMessages = Array.isArray(inputs[0]?.messages) ? inputs[0].messages : []
const compactMessages = Array.isArray(inputs[1]?.messages) ? inputs[1].messages : []
const system = (message: unknown) =>
typeof message === "object" && message !== null && "role" in message && message.role === "system"
expect(compactMessages.find(system)).toEqual(normalMessages.find(system))
expect(JSON.stringify(compactMessages)).toContain("cache prefix message")
expect(JSON.stringify(compactMessages)).toContain("normal response")
expect(JSON.stringify(compactMessages)).toContain("Create a new anchored summary")
expect(JSON.stringify(compactMessages)).not.toContain("[User]: cache prefix message")
}),
)
noLLMServer.instance(
"loop exits immediately when last assistant has stop finish",
() =>
+1 -1
View File
@@ -185,7 +185,7 @@ OpenCode Go هو اشتراك منخفض التكلفة — **$5 للشهر ال
| Model | Model ID | Endpoint | AI SDK Package |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -197,7 +197,7 @@ Također možete pristupiti Go modelima putem sljedećih API endpointa.
| Model | Model ID | Endpoint | AI SDK Paket |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -197,7 +197,7 @@ Du kan også få adgang til Go-modeller gennem følgende API-endpoints.
| Model | Model ID | Endpoint | AI SDK Package |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -187,7 +187,7 @@ Du kannst auf die Go-Modelle auch über die folgenden API-Endpunkte zugreifen.
| Modell | Modell-ID | Endpunkt | AI SDK Package |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -197,7 +197,7 @@ También puedes acceder a los modelos de Go a través de los siguientes endpoint
| Modelo | ID del modelo | Endpoint | Paquete de AI SDK |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -185,7 +185,7 @@ Vous pouvez également accéder aux modèles Go via les points de terminaison d'
| Modèle | ID de modèle | Point de terminaison | Package AI SDK |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -197,7 +197,7 @@ You can also access Go models through the following API endpoints.
| Model | Model ID | Endpoint | AI SDK Package |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -195,7 +195,7 @@ Puoi anche accedere ai modelli Go tramite i seguenti endpoint API.
| Modello | ID Modello | Endpoint | Pacchetto AI SDK |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -185,7 +185,7 @@ Goでは月額$10を支払い、その6倍の利用枠を提供することを
| Model | Model ID | Endpoint | AI SDK Package |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -185,7 +185,7 @@ Go에서는 월 $10를 지불하며, 저희는 그 6배의 사용량을 제공
| 모델 | 모델 ID | 엔드포인트 | AI SDK 패키지 |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -197,7 +197,7 @@ Du kan også få tilgang til Go-modeller gjennom følgende API-endepunkter.
| Modell | Modell-ID | Endepunkt | AI SDK Package |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -189,7 +189,7 @@ Możesz również uzyskać dostęp do modeli Go za pośrednictwem następującyc
| Model | ID modelu | Punkt końcowy | Pakiet AI SDK |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -197,7 +197,7 @@ Você também pode acessar os modelos do Go através dos seguintes endpoints de
| Modelo | ID do Modelo | Endpoint | Pacote do AI SDK |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -197,7 +197,7 @@ OpenCode Go включает следующие лимиты:
| Модель | ID модели | Эндпоинт | Пакет AI SDK |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -185,7 +185,7 @@ OpenCode Go มีขีดจำกัดดังต่อไปนี้:
| Model | Model ID | Endpoint | AI SDK Package |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -185,7 +185,7 @@ Go modellerine aşağıdaki API uç noktaları aracılığıyla da erişebilirsi
| Model | Model ID | Uç Nokta | AI SDK Paketi |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -185,7 +185,7 @@ OpenCode Go 包含以下限制:
| 模型 | 模型 ID | 端点 | AI SDK 包 |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
+1 -1
View File
@@ -185,7 +185,7 @@ OpenCode Go 包含以下限制:
| 模型 | 模型 ID | 端點 | AI SDK 套件 |
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| Grok 4.5 | grok-4.5 | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GPT 5.6 Luna | gpt-5.6-luna | `https://opencode.ai/zen/go/v1/responses` | `@ai-sdk/openai` |
| GLM-5.2 | glm-5.2 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |
| GLM-5.1 | glm-5.1 | `https://opencode.ai/zen/go/v1/chat/completions` | `@ai-sdk/openai-compatible` |