refactor: create normalizeSDKResponse helper and replace scattered patterns across 37 files

This commit is contained in:
YeonGyu-Kim
2026-02-16 18:20:19 +09:00
parent 6d732fd1f6
commit 1a6810535c
41 changed files with 250 additions and 77 deletions
+3 -2
View File
@@ -2,6 +2,7 @@ import { addModelsFromModelsJsonCache } from "./models-json-cache-reader"
import { getModelListFunction, getProviderListFunction } from "./open-code-client-accessors"
import { addModelsFromProviderModelsCache } from "./provider-models-cache-model-reader"
import { log } from "./logger"
import { normalizeSDKResponse } from "./normalize-sdk-response"
export async function getConnectedProviders(client: unknown): Promise<string[]> {
const providerList = getProviderListFunction(client)
@@ -53,7 +54,7 @@ export async function fetchAvailableModels(
const modelSet = new Set<string>()
try {
const modelsResult = await modelList()
const models = modelsResult.data ?? []
const models = normalizeSDKResponse(modelsResult, [] as Array<{ provider?: string; id?: string }>)
for (const model of models) {
if (model.provider && model.id) {
modelSet.add(`${model.provider}/${model.id}`)
@@ -92,7 +93,7 @@ export async function fetchAvailableModels(
if (modelList) {
try {
const modelsResult = await modelList()
const models = modelsResult.data ?? []
const models = normalizeSDKResponse(modelsResult, [] as Array<{ provider?: string; id?: string }>)
for (const model of models) {
if (!model.provider || !model.id) continue
+2 -1
View File
@@ -1,4 +1,5 @@
import type { PluginInput } from "@opencode-ai/plugin";
import { normalizeSDKResponse } from "./normalize-sdk-response"
const ANTHROPIC_ACTUAL_LIMIT =
process.env.ANTHROPIC_1M_CONTEXT === "true" ||
@@ -119,7 +120,7 @@ export async function getContextWindowUsage(
path: { id: sessionID },
});
const messages = (response.data ?? response) as MessageWrapper[];
const messages = normalizeSDKResponse(response, [] as MessageWrapper[], { preferResponseOnMissingData: true })
const assistantMessages = messages
.filter((m) => m.info.role === "assistant")
+1
View File
@@ -53,3 +53,4 @@ export * from "./safe-create-hook"
export * from "./truncate-description"
export * from "./opencode-storage-paths"
export * from "./opencode-message-dir"
export * from "./normalize-sdk-response"
+3 -2
View File
@@ -3,6 +3,7 @@ import { join } from "path"
import { log } from "./logger"
import { getOpenCodeCacheDir } from "./data-path"
import * as connectedProvidersCache from "./connected-providers-cache"
import { normalizeSDKResponse } from "./normalize-sdk-response"
/**
* Fuzzy match a target model name against available models
@@ -159,7 +160,7 @@ export async function fetchAvailableModels(
const modelSet = new Set<string>()
try {
const modelsResult = await client.model.list()
const models = modelsResult.data ?? []
const models = normalizeSDKResponse(modelsResult, [] as Array<{ provider?: string; id?: string }>)
for (const model of models) {
if (model?.provider && model?.id) {
modelSet.add(`${model.provider}/${model.id}`)
@@ -261,7 +262,7 @@ export async function fetchAvailableModels(
if (client?.model?.list) {
try {
const modelsResult = await client.model.list()
const models = modelsResult.data ?? []
const models = normalizeSDKResponse(modelsResult, [] as Array<{ provider?: string; id?: string }>)
for (const model of models) {
if (!model?.provider || !model?.id) continue
+72
View File
@@ -0,0 +1,72 @@
import { describe, expect, it } from "bun:test"
import { normalizeSDKResponse } from "./normalize-sdk-response"
describe("normalizeSDKResponse", () => {
it("returns data array when response includes data", () => {
//#given
const response = { data: [{ id: "1" }] }
//#when
const result = normalizeSDKResponse(response, [] as Array<{ id: string }>)
//#then
expect(result).toEqual([{ id: "1" }])
})
it("returns fallback array when data is missing", () => {
//#given
const response = {}
const fallback = [{ id: "fallback" }]
//#when
const result = normalizeSDKResponse(response, fallback)
//#then
expect(result).toEqual(fallback)
})
it("returns response array directly when SDK returns plain array", () => {
//#given
const response = [{ id: "2" }]
//#when
const result = normalizeSDKResponse(response, [] as Array<{ id: string }>)
//#then
expect(result).toEqual([{ id: "2" }])
})
it("returns response when data missing and preferResponseOnMissingData is true", () => {
//#given
const response = { value: "legacy" }
//#when
const result = normalizeSDKResponse(response, { value: "fallback" }, { preferResponseOnMissingData: true })
//#then
expect(result).toEqual({ value: "legacy" })
})
it("returns fallback for null response", () => {
//#given
const response = null
//#when
const result = normalizeSDKResponse(response, [] as string[])
//#then
expect(result).toEqual([])
})
it("returns object fallback for direct data nullish pattern", () => {
//#given
const response = { data: undefined as { connected: string[] } | undefined }
const fallback = { connected: [] }
//#when
const result = normalizeSDKResponse(response, fallback)
//#then
expect(result).toEqual(fallback)
})
})
+36
View File
@@ -0,0 +1,36 @@
export interface NormalizeSDKResponseOptions {
preferResponseOnMissingData?: boolean
}
export function normalizeSDKResponse<TData>(
response: unknown,
fallback: TData,
options?: NormalizeSDKResponseOptions,
): TData {
if (response === null || response === undefined) {
return fallback
}
if (Array.isArray(response)) {
return response as TData
}
if (typeof response === "object" && "data" in response) {
const data = (response as { data?: unknown }).data
if (data !== null && data !== undefined) {
return data as TData
}
if (options?.preferResponseOnMissingData === true) {
return response as TData
}
return fallback
}
if (options?.preferResponseOnMissingData === true) {
return response as TData
}
return fallback
}