refactor: create normalizeSDKResponse helper and replace scattered patterns across 37 files
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user