mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-12 10:02:45 +00:00
fix(core): disable effort updates for ChatGPT token sharing (#54085)
This commit is contained in:
parent
ee0e614221
commit
903ec2bb35
2 changed files with 82 additions and 1 deletions
|
|
@ -306,6 +306,7 @@ export const ChatGPTPlugin = define({
|
|||
for (const model of models.list(providerID)) {
|
||||
models.update(model.providerID, model.id, (draft) => {
|
||||
if (!chatgpt) return
|
||||
draft.compatibility = { ...draft.compatibility, supportsEffortUpdates: false }
|
||||
// Token sharing does not support native /responses/compact.
|
||||
draft.settings = { ...draft.settings, compaction: { type: "summary" } }
|
||||
if (Schema.is(Schema.Struct({ mode: Schema.Literal("pro") }))(draft.body?.reasoning)) {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ import { Money } from "@opencode/schema/money"
|
|||
import { Agent } from "@opencode/schema/agent"
|
||||
import { Session } from "@opencode/core/session"
|
||||
import { OpenAIResponses } from "@opencode/ai/protocols/openai-responses"
|
||||
import { AIError, HttpContext, RateLimitError } from "@opencode/ai"
|
||||
import { AIError, HttpContext, LLM, Message, RateLimitError } from "@opencode/ai"
|
||||
import { classifyProviderFailure } from "@opencode/ai/provider-error"
|
||||
import { compileRequest } from "@opencode/ai/route/client"
|
||||
import { describe, expect } from "bun:test"
|
||||
// import { DateTime, Deferred, Effect, Schedule } from "effect"
|
||||
import { DateTime, Effect, Schedule } from "effect"
|
||||
|
|
@ -1054,6 +1055,85 @@ describe("ChatGPTPlugin", () => {
|
|||
)
|
||||
}
|
||||
|
||||
for (const connection of ["chatgpt", "key"] as const) {
|
||||
it.effect(`${connection} sends mid-session reasoning effort switches in a form its backend accepts`, () =>
|
||||
Effect.gen(function* () {
|
||||
const catalog = yield* Provider.Service
|
||||
const models = yield* Model.Service
|
||||
const credentials = yield* Credential.Service
|
||||
const modelID = Model.ID.make("gpt-6.1-sol")
|
||||
yield* catalog.transform((editor) => {
|
||||
editor.update(Provider.ID.openai, (provider) => {
|
||||
provider.package = "@opencode/ai/providers/openai"
|
||||
})
|
||||
editor.models.update(Provider.ID.openai, modelID, (model) => {
|
||||
model.variants = ["high", "max"].map((effort) => ({
|
||||
id: Model.VariantID.make(effort),
|
||||
settings: { reasoningEffort: effort },
|
||||
}))
|
||||
})
|
||||
})
|
||||
yield* credentials.create({
|
||||
integrationID: Integration.ID.make("openai"),
|
||||
value:
|
||||
connection === "chatgpt"
|
||||
? Credential.OAuth.make({
|
||||
type: "oauth",
|
||||
methodID: Integration.MethodID.make("chatgpt-token-sharing"),
|
||||
access: "chatgpt-token",
|
||||
refresh: "refresh",
|
||||
expires: Date.now() + 60_000,
|
||||
metadata: { clientID: "oaiapp_issued" },
|
||||
})
|
||||
: Credential.Key.make({ type: "key", key: "sk-test" }),
|
||||
})
|
||||
yield* addPlugin()
|
||||
yield* addLegacyPlugin()
|
||||
const resolver = yield* ModelResolver.Service
|
||||
const model = required(yield* models.get(Provider.ID.openai, modelID))
|
||||
const body = (variant: string, messages: ReadonlyArray<Message>) =>
|
||||
resolver.resolveModel(model, Model.VariantID.make(variant)).pipe(
|
||||
Effect.flatMap((resolved) => compileRequest(LLM.request({ model: resolved.model, messages }))),
|
||||
Effect.map((compiled) => compiled.body),
|
||||
)
|
||||
const switched = [
|
||||
Message.user("a"),
|
||||
Message.assistant("b"),
|
||||
Message.effort({ effort: "max", previous: "high" }),
|
||||
Message.user("c"),
|
||||
]
|
||||
const switchedBack = [
|
||||
...switched,
|
||||
Message.assistant("d"),
|
||||
Message.effort({ effort: "high", previous: "max" }),
|
||||
Message.user("e"),
|
||||
]
|
||||
const user = (text: string) => ({ role: "user", content: [{ type: "input_text", text }] })
|
||||
const assistant = (text: string) => ({ role: "assistant", content: [{ type: "output_text", text }] })
|
||||
const update = (effort: string) => ({ type: "configuration_update", reasoning: { effort } })
|
||||
|
||||
expect([yield* body("max", switched), yield* body("high", switchedBack)]).toMatchObject(
|
||||
{
|
||||
chatgpt: [
|
||||
{ reasoning: { effort: "max" }, input: [user("a"), assistant("b"), user("c")] },
|
||||
{
|
||||
reasoning: { effort: "high" },
|
||||
input: [user("a"), assistant("b"), user("c"), assistant("d"), user("e")],
|
||||
},
|
||||
],
|
||||
key: [
|
||||
{ reasoning: { effort: "high" }, input: [user("a"), assistant("b"), update("max"), user("c")] },
|
||||
{
|
||||
reasoning: { effort: "high" },
|
||||
input: [user("a"), assistant("b"), update("max"), user("c"), assistant("d"), update("high"), user("e")],
|
||||
},
|
||||
],
|
||||
}[connection],
|
||||
)
|
||||
}).pipe(Effect.provide(ModelResolver.layer)),
|
||||
)
|
||||
}
|
||||
|
||||
it.effect("selects WebSocket only from explicit policy", () =>
|
||||
Effect.gen(function* () {
|
||||
const credentials = yield* Credential.Service
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue