Compare commits

..

1 Commits

Author SHA1 Message Date
Aiden Cline 131ea15aa3 fix(provider): centralize Azure request options 2026-08-03 22:11:50 +00:00
56 changed files with 222 additions and 481 deletions
+28 -28
View File
@@ -29,7 +29,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@corvu/drawer": "catalog:",
"@dnd-kit/abstract": "0.5.0",
@@ -96,7 +96,7 @@
},
"packages/cli": {
"name": "@opencode-ai/cli",
"version": "1.18.12",
"version": "1.18.11",
"bin": {
"lildax": "./bin/lildax.cjs",
},
@@ -144,7 +144,7 @@
},
"packages/codemode": {
"name": "@opencode-ai/codemode",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"acorn": "8.15.0",
"effect": "catalog:",
@@ -158,7 +158,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -194,7 +194,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -221,7 +221,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/openai": "3.0.48",
@@ -243,7 +243,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -267,7 +267,7 @@
},
"packages/console/support": {
"name": "@opencode-ai/console-support",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@opencode-ai/console-core": "workspace:*",
@@ -287,7 +287,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.18.12",
"version": "1.18.11",
"bin": {
"opencode": "./bin/opencode",
},
@@ -381,7 +381,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"drizzle-orm": "catalog:",
@@ -435,7 +435,7 @@
},
"packages/effect-drizzle-sqlite": {
"name": "@opencode-ai/effect-drizzle-sqlite",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@@ -449,7 +449,7 @@
},
"packages/effect-sqlite-node": {
"name": "@opencode-ai/effect-sqlite-node",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"effect": "catalog:",
},
@@ -461,7 +461,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -493,7 +493,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -509,7 +509,7 @@
},
"packages/http-recorder": {
"name": "@opencode-ai/http-recorder",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@effect/platform-node": "4.0.0-beta.83",
"@effect/platform-node-shared": "4.0.0-beta.83",
@@ -540,7 +540,7 @@
},
"packages/llm": {
"name": "@opencode-ai/llm",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/schema": "workspace:*",
"@smithy/eventstream-codec": "4.2.14",
@@ -559,7 +559,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.18.12",
"version": "1.18.11",
"bin": {
"opencode": "./bin/opencode",
},
@@ -690,7 +690,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@ai-sdk/provider": "3.0.8",
"@opencode-ai/sdk": "workspace:*",
@@ -766,7 +766,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"cross-spawn": "catalog:",
},
@@ -781,7 +781,7 @@
},
"packages/server": {
"name": "@opencode-ai/server",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/protocol": "workspace:*",
@@ -796,7 +796,7 @@
},
"packages/session-ui": {
"name": "@opencode-ai/session-ui",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz",
@@ -840,7 +840,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -853,7 +853,7 @@
},
"packages/stats/app": {
"name": "@opencode-ai/stats-app",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
@@ -887,7 +887,7 @@
},
"packages/stats/core": {
"name": "@opencode-ai/stats-core",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@aws-sdk/client-athena": "3.933.0",
"@planetscale/database": "1.19.0",
@@ -906,7 +906,7 @@
},
"packages/stats/server": {
"name": "@opencode-ai/stats-server",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@aws-sdk/client-firehose": "3.933.0",
"@effect/platform-node": "catalog:",
@@ -948,7 +948,7 @@
},
"packages/tui": {
"name": "@opencode-ai/tui",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/plugin": "workspace:*",
@@ -975,7 +975,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@kobalte/core": "catalog:",
"@pierre/diffs": "catalog:",
@@ -1027,7 +1027,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.18.12",
"version": "1.18.11",
"description": "",
"type": "module",
"exports": {
@@ -88,7 +88,7 @@ export const DialogSelectModelUnpaidV2: Component<{ model?: ModelState }> = (pro
class="w-full"
placement="right-start"
gutter={6}
delay="intent"
openDelay={0}
contentStyle={{ "font-family": "var(--v2-font-family-sans)" }}
value={
<ModelTooltip
@@ -460,7 +460,7 @@ function ModelSelectorPopoverV2View(props: {
class="w-full"
placement="right-start"
gutter={6}
delay="intent"
openDelay={0}
value={
<ModelTooltip
model={item}
@@ -47,7 +47,7 @@ export const PromptContextItems: Component<ContextItemsProps> = (props) => {
</span>
}
placement="top"
{...(!props.newLayoutDesigns ? { openDelay: 800 } : {})}
openDelay={800}
>
<div
classList={{
@@ -52,7 +52,12 @@ export const PromptImageAttachments: Component<PromptImageAttachmentsProps> = (p
<For each={props.comments ?? []}>
{(item) => (
<div class="relative group shrink-0">
<TooltipV2 value={item.comment} placement="top" contentClass="max-w-[300px] break-words">
<TooltipV2
value={item.comment}
placement="top"
openDelay={800}
contentClass="max-w-[300px] break-words"
>
<CommentCardV2
comment={item.comment ?? ""}
path={item.path}
-16
View File
@@ -338,22 +338,6 @@ export function Titlebar(props: { update?: TitlebarUpdate; debugTools?: { visibl
keybind: "mod+shift+t",
onSelect: () => tabsStoreActions.reopenClosedTab(),
},
{
id: `tab.prev`,
category: "tab",
title: "",
keybind: `mod+option+ArrowLeft,ctrl+shift+tab`,
hidden: true,
onSelect: tabs.previous,
},
{
id: `tab.next`,
category: "tab",
title: "",
keybind: `mod+option+ArrowRight,ctrl+tab`,
hidden: true,
onSelect: tabs.next,
},
].filter((v) => v !== undefined)
})
@@ -1,43 +0,0 @@
import { describe, expect, test } from "bun:test"
import { nextTab, previousTab, rememberTab, type TabHistory } from "./tab-history"
function history(): TabHistory {
return { stack: [], index: -1 }
}
describe("tab history", () => {
test("moves backward and forward through selected tabs", () => {
const selected = ["a", "b", "c"].reduce(rememberTab, history())
const available = new Set(selected.stack)
const previous = previousTab(selected, available)
expect(previous?.key).toBe("b")
const first = previousTab(previous!.state, available)
expect(first?.key).toBe("a")
const next = nextTab(first!.state, available)
expect(next?.key).toBe("b")
})
test("replaces forward history after a new selection", () => {
const selected = ["a", "b", "c"].reduce(rememberTab, history())
const previous = previousTab(selected, new Set(selected.stack))
const next = rememberTab(previous!.state, "d")
expect(next).toEqual({ stack: ["a", "b", "d"], index: 2 })
expect(nextTab(next, new Set(next.stack))).toBeUndefined()
})
test("skips tabs that are no longer open", () => {
const selected = ["a", "b", "c"].reduce(rememberTab, history())
expect(previousTab(selected, new Set(["a", "c"]))?.key).toBe("a")
})
test("skips a repeated current tab after closing the previous selection", () => {
const selected = ["a", "b", "c", "b"].reduce(rememberTab, history())
expect(previousTab(selected, new Set(["a", "b"]))?.key).toBe("a")
})
})
-28
View File
@@ -1,28 +0,0 @@
const MAX_TAB_HISTORY = 100
export type TabHistory = {
stack: string[]
index: number
}
export function rememberTab(state: TabHistory, key: string): TabHistory {
if (state.stack[state.index] === key) return state
const stack = state.stack.slice(0, state.index + 1).concat(key).slice(-MAX_TAB_HISTORY)
return { stack, index: stack.length - 1 }
}
export function previousTab(state: TabHistory, available: Set<string>) {
return move(state, -1, available)
}
export function nextTab(state: TabHistory, available: Set<string>) {
return move(state, 1, available)
}
function move(state: TabHistory, offset: -1 | 1, available: Set<string>) {
const current = state.stack[state.index]
for (let index = state.index + offset; index >= 0 && index < state.stack.length; index += offset) {
const key = state.stack[index]
if (key && key !== current && available.has(key)) return { state: { ...state, index }, key }
}
}
-16
View File
@@ -13,7 +13,6 @@ import { createTabMemory } from "./tab-memory"
import { nextTabAfterClose, pushClosedTab, removeClosedTabs, takeClosedTab, type ClosedTab } from "./closed-tabs"
import { createDraftPromptSession, type PromptModel } from "./prompt-state"
import { migrateTabs } from "./tab-migration"
import { nextTab, previousTab, rememberTab, type TabHistory } from "./tab-history"
export type SessionTab = {
type: "session"
@@ -75,7 +74,6 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
const memory = createTabMemory(getOwner())
const closing = new Set<string>()
let history: TabHistory = { stack: [], index: -1 }
let recentWrite = 0
let recentValue: string | undefined
@@ -150,21 +148,10 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
const navigateTab = (tab: Tab) => {
const href = tabHref(tab)
history = rememberTab(history, tabKey(tab))
setRecentKey(tabKey(tab))
navigate(href)
}
const moveHistory = (direction: "previous" | "next") => {
const available = new Set(store.map(tabKey))
const result = direction === "previous" ? previousTab(history, available) : nextTab(history, available)
if (!result) return
const tab = store.find((item) => tabKey(item) === result.key)
if (!tab) return
history = result.state
navigateTab(tab)
}
const removeTab = (index: number) => {
const tab = store[index]
if (!tab) return
@@ -370,11 +357,8 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
select: navigateTab,
remember(tab: Tab) {
const key = tabKey(tab)
history = rememberTab(history, key)
if (recentKey() !== key) setRecentKey(key)
},
previous: () => moveHistory("previous"),
next: () => moveHistory("next"),
toggleHome(input: { home: boolean; current?: Tab }) {
if (input.home) {
const tab = store.find((tab) => tabKey(tab) === recentKey())
-11
View File
@@ -2,17 +2,6 @@ import { describe, expect, test } from "bun:test"
import { DESKTOP_MENU } from "./desktop-menu"
describe("desktop menu", () => {
test("navigates between tabs", () => {
const items = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).filter(
(item) => item.type === "item" && (item.label === "Previous Tab" || item.label === "Next Tab"),
)
expect(items).toEqual([
{ type: "item", label: "Previous Tab", command: "tab.prev", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "Next Tab", command: "tab.next", accelerator: { macos: "Option+Down" } },
])
})
test("exports logs through the desktop command registry", () => {
const items = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).filter(
(item) => item.type === "item" && item.label === "Export Logs...",
+2 -2
View File
@@ -168,8 +168,8 @@ export const DESKTOP_MENU: DesktopMenu[] = [
{ type: "item", label: "Back", command: "common.goBack", accelerator: { macos: "Cmd+[" } },
{ type: "item", label: "Forward", command: "common.goForward", accelerator: { macos: "Cmd+]" } },
{ type: "separator" },
{ type: "item", label: "Previous Tab", command: "tab.prev", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "Next Tab", command: "tab.next", accelerator: { macos: "Option+Down" } },
{ type: "item", label: "Previous Session", command: "session.previous", accelerator: { macos: "Option+Up" } },
{ type: "item", label: "Next Session", command: "session.next", accelerator: { macos: "Option+Down" } },
{ type: "separator" },
{
type: "item",
@@ -143,7 +143,7 @@ function ProviderTip() {
<TooltipV2
class="hover-reveal absolute left-full top-0 flex h-6 w-7 items-center justify-end delay-0 duration-0 group-hover/provider-tip:delay-[250ms] group-hover/provider-tip:duration-150 group-hover/provider-tip:opacity-100 focus-within:delay-0 focus-within:duration-0 focus-within:opacity-100"
placement="top"
delay="intent"
openDelay={1000}
value={language.t("common.dismiss")}
>
<button
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/cli",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"bin": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/codemode",
"version": "1.18.12",
"version": "1.18.11",
"description": "Effect-native confined code execution over schema-described tools",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+13 -35
View File
@@ -59,30 +59,7 @@ export namespace Referral {
const accountID = Actor.account()
const code = await ensureCode(workspaceID)
const rows = await Database.use(async (tx) => {
const [rewards, invites, inviteeReferral, inviteeRewards] = await Promise.all([
tx
.select({
referralID: ReferralRewardTable.referralID,
workspaceID: ReferralRewardTable.workspaceID,
referralWorkspaceID: ReferralTable.workspaceID,
inviteeEmail: AuthTable.subject,
amount: ReferralRewardTable.amount,
timeCreated: ReferralRewardTable.timeCreated,
timeApplied: ReferralRewardTable.timeApplied,
})
.from(ReferralRewardTable)
.innerJoin(ReferralTable, eq(ReferralTable.id, ReferralRewardTable.referralID))
.innerJoin(
AuthTable,
and(eq(AuthTable.accountID, ReferralTable.inviteeAccountID), eq(AuthTable.provider, "email")),
)
.where(
and(
eq(ReferralRewardTable.workspaceID, workspaceID),
isNull(ReferralRewardTable.timeDeleted),
isNull(ReferralTable.timeDeleted),
),
),
const [invites, inviteeReferral] = await Promise.all([
tx
.select({ id: ReferralTable.id, inviteeEmail: AuthTable.subject, timeCreated: ReferralTable.timeCreated })
.from(ReferralTable)
@@ -106,19 +83,20 @@ export namespace Referral {
.where(and(eq(ReferralTable.inviteeAccountID, accountID), isNull(ReferralTable.timeDeleted)))
.orderBy(asc(UserTable.timeCreated))
.then((rows) => rows.find((row) => row.inviterEmail) ?? rows[0]),
tx
.select({ referralID: ReferralRewardTable.referralID })
.from(ReferralRewardTable)
.innerJoin(ReferralTable, eq(ReferralTable.id, ReferralRewardTable.referralID))
.where(
and(
eq(ReferralTable.inviteeAccountID, accountID),
isNull(ReferralRewardTable.timeDeleted),
isNull(ReferralTable.timeDeleted),
),
),
])
// Hide reward history until the referral_id index can be deployed and this lookup restored.
const rewards: {
referralID: string
workspaceID: string
referralWorkspaceID: string
inviteeEmail: string
amount: number
timeCreated: Date
timeApplied: Date | null
}[] = []
// Hide pending invitee rewards until the referral_id index can be deployed and this lookup restored.
const inviteeRewards = inviteeReferral ? [{ referralID: inviteeReferral.id }] : []
return { inviteeReferral, inviteeRewards, invites, rewards }
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.18.12",
"version": "1.18.11",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-support",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/effect-drizzle-sqlite",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/effect-sqlite-node",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.18.12",
"version": "1.18.11",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/http-recorder",
"description": "Record and replay Effect HTTP client traffic with deterministic cassettes",
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/llm",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "opencode",
"type": "module",
"license": "MIT",
+26 -11
View File
@@ -1270,17 +1270,6 @@ export function options(input: {
result["gateway"] = { caching: "auto" }
}
// Any gpt version above 5.4 in combination with azure does not support reasoningEffort
// so we should return early here.
const [, gptMajorVersion, gptMinorVersion] = input.model.api.id.match(/gpt-(\d+)\.(\d+)/) ?? []
const isGpt55OrNewer = Number(gptMajorVersion) > 5 || (Number(gptMajorVersion) === 5 && Number(gptMinorVersion) >= 5)
if (input.model.api.npm === "@ai-sdk/azure" && input.providerOptions?.useCompletionUrls) {
if (!isGpt55OrNewer) {
result["reasoningEffort"] = "medium"
}
return result
}
if (input.model.api.id.includes("gpt-5") && !input.model.api.id.includes("gpt-5-chat")) {
if (!input.model.api.id.includes("gpt-5-pro")) {
result["reasoningEffort"] = "medium"
@@ -1318,6 +1307,32 @@ export function options(input: {
return result
}
export function requestOptions(input: {
model: Provider.Model
providerOptions: Record<string, any>
options: Record<string, any>
}) {
if (
input.model.api.npm !== "@ai-sdk/azure" ||
!(input.model.options.useCompletionUrls ?? input.providerOptions.useCompletionUrls)
)
return input.options
const result = { ...input.options }
delete result.reasoningSummary
delete result.include
if (isGpt55OrNewer(input.model.api.id)) delete result.reasoningEffort
return result
}
function isGpt55OrNewer(modelID: string) {
const match = /gpt-(\d)(?:[.-](\d+))?(?:[.-]|$)/i.exec(modelID)
if (!match) return false
const major = Number(match[1])
const minor = Number(match[2] ?? 0)
return major > 5 || (major === 5 && minor >= 5)
}
export function smallOptions(model: Provider.Model) {
const small = Object.values(model.variants ?? {})[0] ?? {}
if (
+5 -8
View File
@@ -88,14 +88,11 @@ export const prepare = Effect.fn("LLMRequestPrep.prepare")(function* (input: Pre
sessionID: input.sessionID,
providerOptions: input.provider.options,
})
const options = mergeOptions(mergeOptions(mergeOptions(base, input.model.options), input.agent.options), variant)
if (
input.model.api.npm === "@ai-sdk/azure" &&
(input.provider.options.useCompletionUrls || input.model.options.useCompletionUrls || options.useCompletionUrls)
) {
delete options.reasoningSummary
delete options.include
}
const options = ProviderTransform.requestOptions({
model: input.model,
providerOptions: input.provider.options,
options: mergeOptions(mergeOptions(mergeOptions(base, input.model.options), input.agent.options), variant),
})
if (isOpenaiOauth) options.instructions = system.join("\n")
const messages =
@@ -252,7 +252,7 @@ describe("ProviderTransform.options - setCacheKey", () => {
expect(result.promptCacheKey).toBeUndefined()
})
test("should keep the Azure cache key for gpt-5.5 early return", () => {
test("should keep the Azure cache key for gpt-5.5 Responses defaults", () => {
const result = ProviderTransform.options({
model: {
...mockModel,
@@ -264,6 +264,7 @@ describe("ProviderTransform.options - setCacheKey", () => {
})
expect(result.store).toBe(false)
expect(result.reasoningSummary).toBe("auto")
expect(result.reasoningEffort).toBe("medium")
expect(result.promptCacheKey).toBe(sessionID)
})
@@ -525,13 +526,13 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
expect(result.include).toBeUndefined()
})
test("azure chat completions omit Responses-only reasoning options after variants merge", async () => {
test("azure gpt-5.5 chat completions omit unsupported reasoning options after variants merge", async () => {
const model = {
...createGpt5Model("gpt-5.4"),
id: "azure/gpt-5.4",
...createGpt5Model("gpt-5.5"),
id: "azure/gpt-5.5",
providerID: "azure",
api: {
id: "gpt-5.4",
id: "gpt-5.5",
url: "https://azure.com",
npm: "@ai-sdk/azure",
},
@@ -551,7 +552,7 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
role: "user",
time: { created: Date.now() },
agent: "test",
model: { providerID: "azure", modelID: "gpt-5.4", variant: "high" },
model: { providerID: "azure", modelID: "gpt-5.5", variant: "high" },
} as any,
sessionID,
model,
@@ -580,7 +581,7 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
isWorkflow: false,
}),
)
expect(result.params.options.reasoningEffort).toBe("high")
expect(result.params.options.reasoningEffort).toBeUndefined()
expect(result.params.options.reasoningSummary).toBeUndefined()
expect(result.params.options.include).toBeUndefined()
expect(result.tools.lookup.strict).toBe(false)
@@ -681,34 +682,52 @@ describe("ProviderTransform.options - gpt-5 reasoningEffort", () => {
expect(result.reasoningEffort).toBeUndefined()
})
test("gpt-5.5 should NOT set reasoningEffort for the completions API", () => {
test("gpt-5.5 should set Responses reasoning options", () => {
const result = ProviderTransform.options({
model: createModel("gpt-5.5"),
sessionID,
providerOptions: { useCompletionUrls: true },
})
expect(result.reasoningEffort).toBeUndefined()
})
test("gpt-5.6 should NOT set reasoningEffort for the completions API", () => {
const result = ProviderTransform.options({
model: createModel("gpt-5.6"),
sessionID,
providerOptions: { useCompletionUrls: true },
})
expect(result.reasoningEffort).toBeUndefined()
})
test("gpt-5.6 should set reasoningEffort for the responses API", () => {
const result = ProviderTransform.options({
model: createModel("gpt-5.6"),
sessionID,
providerOptions: {},
})
expect(result.reasoningEffort).toBe("medium")
expect(result.reasoningSummary).toBe("auto")
})
})
describe("ProviderTransform.requestOptions - Azure endpoints", () => {
const options = {
reasoningEffort: "high",
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
}
test.each([
["preserves Responses reasoning options", "gpt-5.5", {}, {}, options],
[
"preserves reasoning effort for gpt-5.4 Chat Completions",
"gpt-5.4",
{ useCompletionUrls: true },
{},
{ reasoningEffort: "high" },
],
["uses the model endpoint override", "gpt-5.5", { useCompletionUrls: true }, { useCompletionUrls: false }, options],
["omits reasoning effort for gpt-5.5 Chat Completions", "gpt-5.5", { useCompletionUrls: true }, {}, {}],
["omits reasoning effort for gpt-5.6 Chat Completions", "gpt-5.6", { useCompletionUrls: true }, {}, {}],
["omits reasoning effort for gpt-6 Chat Completions", "gpt-6", { useCompletionUrls: true }, {}, {}],
[
"does not treat gpt-50 as a versioned GPT model",
"gpt-50",
{ useCompletionUrls: true },
{},
{ reasoningEffort: "high" },
],
])("%s", (_name, apiID, providerOptions, modelOptions, expected) => {
expect(
ProviderTransform.requestOptions({
model: { api: { id: apiID, npm: "@ai-sdk/azure" }, options: modelOptions } as any,
providerOptions,
options,
}),
).toEqual(expected)
})
})
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/server",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/session-ui",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+5 -32
View File
@@ -255,16 +255,8 @@ function useFileViewer(config: ViewerConfig) {
if (!dragMoved) {
pendingSelectionEnd = false
const selected = config.buildClickSelection()
const next =
selected &&
lastSelection?.start === selected.start &&
lastSelection.end === selected.end &&
lastSelection.side === selected.side &&
(lastSelection.endSide ?? lastSelection.side) === (selected.endSide ?? selected.side)
? null
: selected
if (next !== undefined) config.setSelectedLines(next)
config.onLineSelectionEnd(next === undefined ? lastSelection : next)
if (selected) config.setSelectedLines(selected)
config.onLineSelectionEnd(lastSelection)
dragStart = undefined
dragEnd = undefined
dragMoved = false
@@ -299,29 +291,10 @@ function useFileViewer(config: ViewerConfig) {
createEffect(() => {
rendered()
const ranges = config.commentedLines()
const root = getRoot()
if (!root) return
if (ranges.length === 0) {
requestAnimationFrame(() => {
const root = getRoot()
if (!root) return
config.markCommented(root, ranges)
return
}
let frame: number | undefined
const mark = () => {
if (frame !== undefined) cancelAnimationFrame(frame)
frame = requestAnimationFrame(() => {
frame = undefined
config.markCommented(root, ranges)
})
}
const observer = new MutationObserver(mark)
observer.observe(root, { childList: true, subtree: true })
mark()
onCleanup(() => {
observer.disconnect()
if (frame !== undefined) cancelAnimationFrame(frame)
})
})
+29 -61
View File
@@ -26,19 +26,30 @@ const unsafeCSS = `
color-mix(in lab, var(--diffs-bg) 33.333%, var(--diffs-deletion-base)),
color-mix(in lab, var(--diffs-bg) 60%, var(--diffs-deletion-base))
);
--diffs-bg-deletion-number-override: var(--diffs-bg-deletion-override);
--diffs-bg-addition-override: light-dark(
color-mix(in lab, var(--diffs-bg) 33.333%, var(--diffs-addition-base)),
color-mix(in lab, var(--diffs-bg) 60%, var(--diffs-addition-base))
);
--diffs-bg-addition-number-override: var(--diffs-bg-addition-override);
--diffs-selection-base: var(--v2-background-bg-accent);
--diffs-selection-number-fg: var(--v2-text-text-accent);
--diffs-comment-bg: rgb(from var(--v2-background-bg-accent) r g b / 0.06);
--diffs-selection-base: var(--surface-warning-strong);
--diffs-selection-border: var(--border-warning-base);
--diffs-selection-number-fg: #1c1917;
/* Use explicit alpha instead of color-mix(..., transparent) to avoid Safari's non-premultiplied interpolation bugs. */
--diffs-bg-selection: var(--diffs-bg-selection-override, rgb(from var(--diffs-selection-base) r g b / 0.2));
--diffs-bg-selection-number: var(--diffs-bg-selection-number-override, var(--diffs-bg-selection));
--diffs-bg-selection-text: rgb(from var(--diffs-selection-base) r g b / 0.2);
--diffs-bg-selection: var(--diffs-bg-selection-override, rgb(from var(--surface-warning-base) r g b / 0.65));
--diffs-bg-selection-number: var(
--diffs-bg-selection-number-override,
rgb(from var(--surface-warning-base) r g b / 0.85)
);
--diffs-bg-selection-text: rgb(from var(--surface-warning-strong) r g b / 0.2);
}
:host([data-color-scheme='dark']) [data-diff],
:host([data-color-scheme='dark']) [data-file] {
--diffs-selection-number-fg: #fdfbfb;
--diffs-bg-selection: var(--diffs-bg-selection-override, rgb(from var(--solaris-dark-6) r g b / 0.65));
--diffs-bg-selection-number: var(
--diffs-bg-selection-number-override,
rgb(from var(--solaris-dark-6) r g b / 0.85)
);
}
[data-diff] ::selection,
@@ -46,34 +57,6 @@ const unsafeCSS = `
background-color: var(--diffs-bg-selection-text);
}
[data-indicators='bars'] [data-column-number][data-line-type='change-addition']::before,
[data-indicators='bars'] [data-column-number][data-line-type='change-deletion']::before {
width: 2px;
}
[data-indicators='bars'] [data-column-number][data-line-type='change-deletion']::before {
background-image: none;
background-color: var(--diffs-deletion-base);
}
[data-background] [data-column-number] {
--mix-light: 88%;
--mix-dark: 80%;
}
[data-diff-type='split'] [data-additions],
[data-diff-type='split'] [data-additions] [data-gutter],
[data-diff-type='split'] [data-deletions],
[data-diff-type='split'] [data-deletions] [data-content] {
border-left: 0;
border-right: 0;
}
[data-content-buffer] {
background-image: none;
background-color: var(--diffs-bg-context-gutter);
}
::highlight(opencode-find) {
background-color: rgb(from var(--surface-warning-base) r g b / 0.35);
}
@@ -100,24 +83,22 @@ const unsafeCSS = `
color: var(--diffs-selection-number-fg);
}
[data-diff] [data-line-annotation],
[data-diff] [data-gutter-buffer='annotation'],
[data-file] [data-line-annotation],
[data-file] [data-gutter-buffer='annotation'] {
--diffs-annotation-bg: var(--diffs-comment-bg);
--diffs-computed-decoration-bg: var(--diffs-comment-bg);
--diffs-computed-diff-line-bg: var(--diffs-comment-bg);
--diffs-computed-selected-line-bg: var(--diffs-comment-bg);
--diffs-line-bg: var(--diffs-comment-bg);
background-color: var(--diffs-comment-bg);
[data-diff] [data-line-annotation][data-comment-selected]:not([data-selected-line]) [data-annotation-content] {
box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection);
}
[data-file] [data-line-annotation][data-comment-selected]:not([data-selected-line]) [data-annotation-content] {
box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection);
}
[data-diff] [data-line][data-selected-line] {
background-color: var(--diffs-bg-selection);
box-shadow: inset 2px 0 0 var(--diffs-selection-border);
}
[data-file] [data-line][data-selected-line] {
background-color: var(--diffs-bg-selection);
box-shadow: inset 2px 0 0 var(--diffs-selection-border);
}
[data-diff] [data-column-number][data-selected-line] {
@@ -137,19 +118,6 @@ const unsafeCSS = `
color: var(--diffs-selection-number-fg);
}
@media (pointer: fine) {
[data-gutter-utility-slot] {
opacity: 0;
pointer-events: none;
}
[data-column-number][data-hovered] [data-gutter-utility-slot],
[data-gutter-utility-slot]:focus-within {
opacity: 1;
pointer-events: auto;
}
}
/* The deletion word-diff emphasis is stronger than additions; soften it while selected so the selection highlight reads consistently. */
[data-diff] [data-line][data-line-type='change-deletion'][data-selected-line] {
--diffs-bg-deletion-emphasis: light-dark(
@@ -165,6 +133,7 @@ const unsafeCSS = `
height: 24px;
}
[data-column-number] {
background-color: var(--diffs-bg);
cursor: default !important;
}
@@ -213,6 +182,5 @@ export const styleVariables = {
"--diffs-font-features": "var(--font-family-mono--font-feature-settings)",
"--diffs-header-font-family": "var(--font-family-sans)",
"--diffs-gap-block": 0,
"--diffs-gap-style": 0,
"--diffs-min-number-column-width": "3ch",
"--diffs-min-number-column-width": "4ch",
}
@@ -32,6 +32,7 @@ export function CommentCardV2(props: {
return (
<TooltipV2
placement="top"
openDelay={1000}
value={props.title ?? props.comment}
disabled={!props.tooltip || !truncated()}
class={props.wide ? "w-full" : undefined}
@@ -151,10 +151,7 @@ export function createLineCommentControllerV2<T extends LineCommentShape>(props:
}
: undefined
},
onMouseEnter: () => {
if (note.commenting()) return
note.hoverComment(comment.selection)
},
onMouseEnter: () => note.hoverComment(comment.selection),
onClick: () => {
if (note.isEditing(comment.id)) return
note.toggleComment(comment.id, comment.selection)
@@ -167,14 +164,10 @@ export function createLineCommentControllerV2<T extends LineCommentShape>(props:
},
selection: formatSelectedLineLabel(range, i18n.t),
onInput: note.setDraft,
onCancel: () => {
note.cancelDraft()
note.select(null)
},
onCancel: note.cancelDraft,
onSubmit: (comment) => {
props.onSubmit({ comment, selection: cloneSelectedLineRange(range) })
note.cancelDraft()
note.select(null)
},
cancelLabel: i18n.t("ui.lineComment.cancel"),
submitLabel: i18n.t("ui.lineComment.submit"),
@@ -387,7 +387,12 @@ export function PromptInputV2Attachments(props: {
<For each={props.comments ?? []}>
{(comment) => (
<div class="relative group shrink-0">
<TooltipV2 value={comment.comment} placement="top" contentClass="max-w-[300px] break-words">
<TooltipV2
value={comment.comment}
placement="top"
openDelay={800}
contentClass="max-w-[300px] break-words"
>
<CommentCardV2
comment={comment.comment ?? ""}
path={comment.path}
@@ -216,6 +216,7 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
</Show>
<div class="flex items-center">
<TooltipV2
openDelay={2000}
inactive={!prev()}
value={
<>
@@ -235,6 +236,7 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
/>
</TooltipV2>
<TooltipV2
openDelay={2000}
inactive={!next()}
value={
<>
@@ -268,12 +270,12 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
class="session-review-v2-segmented-control session-review-v2-segmented-control--icon"
aria-label={i18n.t("ui.sessionReviewV2.expandMode")}
>
<TooltipV2 value={i18n.t("ui.sessionReviewV2.showAllLines")}>
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.showAllLines")}>
<SegmentedControlItemV2 value="expand" aria-label={i18n.t("ui.sessionReviewV2.showAllLines")}>
<Icon name="expand" />
</SegmentedControlItemV2>
</TooltipV2>
<TooltipV2 value={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
<SegmentedControlItemV2 value="collapse" aria-label={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
<Icon name="collapse" />
</SegmentedControlItemV2>
@@ -289,12 +291,12 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
class="session-review-v2-segmented-control session-review-v2-segmented-control--icon"
aria-label={i18n.t("ui.sessionReviewV2.diffView")}
>
<TooltipV2 value={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
<SegmentedControlItemV2 value="unified" aria-label={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
<Icon name="unified" />
</SegmentedControlItemV2>
</TooltipV2>
<TooltipV2 value={i18n.t("ui.sessionReviewV2.splitDiff")}>
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.splitDiff")}>
<SegmentedControlItemV2 value="split" aria-label={i18n.t("ui.sessionReviewV2.splitDiff")}>
<Icon name="split" />
</SegmentedControlItemV2>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-app",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-core",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-server",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/tui",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -5
View File
@@ -104,6 +104,7 @@ const appGlobalBindingCommands = [
] as const
const appBindingCommands = [
"command.palette.show",
"model.list",
"model.cycle_recent",
"model.cycle_recent_reverse",
@@ -962,11 +963,6 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
commands: appCommands(),
}))
useBindings(() => ({
enabled: () => dialog.stack.length === 0,
bindings: tuiConfig.keybinds.get(COMMAND_PALETTE_COMMAND),
}))
useBindings(() => ({
mode: OPENCODE_BASE_MODE,
bindings: tuiConfig.keybinds.gather("app", appBindingCommands),
+4 -34
View File
@@ -5,13 +5,7 @@ import { testRender, useRenderer } from "@opentui/solid"
import { expect, test } from "bun:test"
import { onCleanup } from "solid-js"
import { TuiKeybind } from "../src/config/keybind"
import {
COMMAND_PALETTE_COMMAND,
getOpencodeModeStack,
OPENCODE_BASE_MODE,
OpencodeKeymapProvider,
registerOpencodeKeymap,
} from "../src/keymap"
import { getOpencodeModeStack, OPENCODE_BASE_MODE, OpencodeKeymapProvider, registerOpencodeKeymap } from "../src/keymap"
function createResolvedKeymapConfig(input: TuiKeybind.KeybindOverrides = {}) {
const keybinds = TuiKeybind.parse(input)
@@ -79,14 +73,12 @@ test("mode-less bindings stay active when opencode mode changes", async () => {
const offKeymap = registerOpencodeKeymap(keymap, renderer, config)
const offGlobal = keymap.registerLayer({
commands: [
{ name: COMMAND_PALETTE_COMMAND, run() {} },
{ name: "session.list", run() {} },
{ name: "session.new", run() {} },
{ name: "session.page.up", run() {} },
{ name: "session.first", run() {} },
],
bindings: config.keybinds.gather("test.global", [
COMMAND_PALETTE_COMMAND,
"session.list",
"session.new",
"session.page.up",
@@ -103,14 +95,7 @@ test("mode-less bindings stay active when opencode mode changes", async () => {
Array.from(
keymap.getCommandBindings({
visibility: "active",
commands: [
COMMAND_PALETTE_COMMAND,
"session.list",
"session.new",
"session.page.up",
"session.first",
"model.list",
],
commands: ["session.list", "session.new", "session.page.up", "session.first", "model.list"],
}),
([command, bindings]) => [command, bindings.length],
),
@@ -140,24 +125,9 @@ test("mode-less bindings stay active when opencode mode changes", async () => {
const app = await testRender(() => <Harness />)
try {
expect(counts).toEqual({
base: {
[COMMAND_PALETTE_COMMAND]: 1,
"session.list": 1,
"session.new": 1,
"session.page.up": 2,
"session.first": 2,
"model.list": 1,
},
question: {
[COMMAND_PALETTE_COMMAND]: 1,
"session.list": 1,
"session.new": 1,
"session.page.up": 2,
"session.first": 2,
"model.list": 0,
},
base: { "session.list": 1, "session.new": 1, "session.page.up": 2, "session.first": 2, "model.list": 1 },
question: { "session.list": 1, "session.new": 1, "session.page.up": 2, "session.first": 2, "model.list": 0 },
autocomplete: {
[COMMAND_PALETTE_COMMAND]: 1,
"session.list": 1,
"session.new": 1,
"session.page.up": 2,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"repository": {
+2 -4
View File
@@ -41,8 +41,7 @@
"syntax-type": "var(--v2-purple-800)",
"syntax-constant": "#007b80",
"syntax-critical": "var(--v2-red-800)",
"syntax-diff-add": "var(--v2-state-fg-success)",
"syntax-diff-delete": "var(--v2-state-fg-danger)",
"syntax-diff-delete": "#ff8c00",
"syntax-diff-unknown": "#a753ae",
"surface-critical-base": "#FFF2F0"
},
@@ -276,8 +275,7 @@
"syntax-type": "var(--v2-purple-400)",
"syntax-constant": "#93e9f6",
"syntax-critical": "var(--v2-red-400)",
"syntax-diff-add": "var(--v2-state-fg-success)",
"syntax-diff-delete": "var(--v2-state-fg-danger)",
"syntax-diff-delete": "#fab283",
"syntax-diff-unknown": "#edb2f1",
"surface-critical-base": "#1F0603"
},
@@ -1,35 +0,0 @@
const OPEN_DELAY = 1_000
// Kobalte warms every tooltip globally. Keep intent previews isolated so opening
// a model picker never inherits warm state from an unrelated tooltip.
let warm = false
let reset: ReturnType<typeof setTimeout> | undefined
export function openTooltipIntent(open: () => void) {
clearTimeout(reset)
reset = undefined
if (warm) {
open()
return
}
const timer = setTimeout(() => {
warm = true
open()
}, OPEN_DELAY)
return () => clearTimeout(timer)
}
export function closeTooltipIntent() {
clearTimeout(reset)
// Adjacent triggers enter before the next task; leaving the group does not.
reset = setTimeout(() => {
warm = false
reset = undefined
})
}
export function resetTooltipIntent() {
clearTimeout(reset)
reset = undefined
warm = false
}
+6 -36
View File
@@ -2,22 +2,19 @@ import { Tooltip as KobalteTooltip } from "@kobalte/core/tooltip"
import { createEffect, Match, onCleanup, splitProps, Switch, type JSX } from "solid-js"
import type { ComponentProps } from "solid-js"
import { createStore } from "solid-js/store"
import { closeTooltipIntent, openTooltipIntent, resetTooltipIntent } from "./tooltip-intent"
import "./tooltip-v2.css"
export interface TooltipV2Props extends Omit<ComponentProps<typeof KobalteTooltip>, "openDelay"> {
export interface TooltipV2Props extends ComponentProps<typeof KobalteTooltip> {
value: JSX.Element
class?: string
contentClass?: string
contentStyle?: JSX.CSSProperties
inactive?: boolean
delay?: "standard" | "intent"
forceOpen?: boolean
}
export function TooltipV2(props: TooltipV2Props) {
let ref: HTMLDivElement | undefined
let cancelIntent: (() => void) | undefined
const [state, setState] = createStore({
open: false,
block: false,
@@ -29,37 +26,19 @@ export function TooltipV2(props: TooltipV2Props) {
"contentClass",
"contentStyle",
"inactive",
"delay",
"forceOpen",
"ignoreSafeArea",
"value",
])
const close = () => setState("open", false)
const inside = () => {
const active = document.activeElement
if (!ref || !active) return false
return ref.contains(active)
}
const close = () => {
cancelIntent?.()
cancelIntent = undefined
if (local.delay === "intent") closeTooltipIntent()
setState("open", false)
}
const show = () => {
if (local.delay !== "intent" || inside()) {
setState("open", true)
return
}
if (cancelIntent) return
cancelIntent = openTooltipIntent(() => {
cancelIntent = undefined
setState("open", true)
})
}
const drop = (expand = state.expand) => {
if (expand) return
if (ref?.matches(":hover")) return
@@ -101,11 +80,6 @@ export function TooltipV2(props: TooltipV2Props) {
onCleanup(() => obs.disconnect())
})
onCleanup(() => {
cancelIntent?.()
if (local.delay === "intent") resetTooltipIntent()
})
let justClickedTrigger = false
return (
@@ -114,8 +88,8 @@ export function TooltipV2(props: TooltipV2Props) {
<Match when={true}>
<KobalteTooltip
gutter={4}
openDelay={local.delay === "intent" ? 0 : 400}
skipDelayDuration={local.delay === "intent" ? 0 : 300}
openDelay={400}
skipDelayDuration={300}
{...others}
closeDelay={0}
ignoreSafeArea={local.ignoreSafeArea ?? true}
@@ -127,11 +101,7 @@ export function TooltipV2(props: TooltipV2Props) {
justClickedTrigger = false
return
}
if (open) {
show()
return
}
close()
setState("open", open)
}}
>
<KobalteTooltip.Trigger
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.18.12",
"version": "1.18.11",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.18.12",
"version": "1.18.11",
"publisher": "sst-dev",
"repository": {
"type": "git",