Migrate UI to v2 SDK client

Use v2 OpencodeClient with normalized request handling and rehydrate pending permissions via GET /permission on instance hydration.
This commit is contained in:
Shantur Rathore
2026-01-04 22:01:49 +00:00
parent fcb5998474
commit 1377bc6b91
15 changed files with 186 additions and 117 deletions

View File

@@ -18,6 +18,7 @@ import type { MessageRecord } from "../../stores/message-v2/types"
import { messageStoreBus } from "../../stores/message-v2/bus"
import { cleanupBlankSessions } from "../../stores/session-state"
import { getLogger } from "../logger"
import { requestData } from "../opencode-api"
import { emitSessionSidebarRequest } from "../session-sidebar-events"
const log = getLogger("actions")
@@ -241,13 +242,14 @@ export function useCommands(options: UseCommandsOptions) {
try {
setSessionCompactionState(instance.id, sessionId, true)
await instance.client.session.summarize({
path: { id: sessionId },
body: {
await requestData(
instance.client.session.summarize({
sessionID: sessionId,
providerID: session.model.providerId,
modelID: session.model.modelId,
},
})
}),
"session.summarize",
)
} catch (error) {
setSessionCompactionState(instance.id, sessionId, false)
log.error("Failed to compact session", error)
@@ -332,10 +334,13 @@ export function useCommands(options: UseCommandsOptions) {
}
try {
await instance.client.session.revert({
path: { id: sessionId },
body: { messageID },
})
await requestData(
instance.client.session.revert({
sessionID: sessionId,
messageID,
}),
"session.revert",
)
if (!restoredText) {
const fallbackRecord = store.getMessage(messageID)

View File

@@ -0,0 +1,37 @@
import type { OpencodeClient } from "@opencode-ai/sdk/v2/client"
export class OpencodeApiError extends Error {
constructor(message: string, options?: { cause?: unknown }) {
super(message)
this.name = "OpencodeApiError"
if (options && "cause" in options) {
;(this as any).cause = options.cause
}
}
}
type RequestResultLike<T> =
| {
data: T
error?: undefined
}
| {
data?: undefined
error: unknown
}
export async function requestData<T>(
promise: Promise<RequestResultLike<T> | undefined>,
label: string,
): Promise<T> {
const result = await promise
if (!result) {
throw new OpencodeApiError(`${label} returned no result`)
}
if ((result as any).error) {
throw new OpencodeApiError(`${label} failed`, { cause: (result as any).error })
}
return (result as any).data as T
}
export type { OpencodeClient }

View File

@@ -1,18 +1,20 @@
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/client"
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2/client"
import { CODENOMAD_API_BASE } from "./api-client"
class SDKManager {
private clients = new Map<string, OpencodeClient>()
createClient(instanceId: string, proxyPath: string): OpencodeClient {
if (this.clients.has(instanceId)) {
return this.clients.get(instanceId)!
const existing = this.clients.get(instanceId)
if (existing) {
return existing
}
const baseUrl = buildInstanceBaseUrl(proxyPath)
const client = createOpencodeClient({ baseUrl })
this.clients.set(instanceId, client)
return client
}
@@ -29,6 +31,8 @@ class SDKManager {
}
}
export type { OpencodeClient }
function buildInstanceBaseUrl(proxyPath: string): string {
const normalized = normalizeProxyPath(proxyPath)
const base = stripTrailingSlashes(CODENOMAD_API_BASE)