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
@@ -1,5 +1,6 @@
import type { PluginInput } from "@opencode-ai/plugin"
import { log } from "../../shared"
import { normalizeSDKResponse } from "../../shared"
export async function waitForCompletion(
sessionID: string,
@@ -33,7 +34,7 @@ export async function waitForCompletion(
// Check session status
const statusResult = await ctx.client.session.status()
const allStatuses = (statusResult.data ?? {}) as Record<string, { type: string }>
const allStatuses = normalizeSDKResponse(statusResult, {} as Record<string, { type: string }>)
const sessionStatus = allStatuses[sessionID]
// If session is actively running, reset stability counter
@@ -45,7 +46,9 @@ export async function waitForCompletion(
// Session is idle - check message stability
const messagesCheck = await ctx.client.session.messages({ path: { id: sessionID } })
const msgs = ((messagesCheck as { data?: unknown }).data ?? messagesCheck) as Array<unknown>
const msgs = normalizeSDKResponse(messagesCheck, [] as Array<unknown>, {
preferResponseOnMissingData: true,
})
const currentMsgCount = msgs.length
if (currentMsgCount > 0 && currentMsgCount === lastMsgCount) {
+4 -1
View File
@@ -4,6 +4,7 @@ import { isPlanFamily } from "./constants"
import { SISYPHUS_JUNIOR_AGENT } from "./sisyphus-junior-agent"
import { parseModelString } from "./model-string-parser"
import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements"
import { normalizeSDKResponse } from "../../shared"
import { getAvailableModelsForDelegateTask } from "./available-models"
import { resolveModelForDelegateTask } from "./model-selection"
@@ -47,7 +48,9 @@ Create the work plan directly - that's your job as the planning agent.`,
try {
const agentsResult = await client.app.agents()
type AgentInfo = { name: string; mode?: "subagent" | "primary" | "all"; model?: { providerID: string; modelID: string } }
const agents = (agentsResult as { data?: AgentInfo[] }).data ?? agentsResult as unknown as AgentInfo[]
const agents = normalizeSDKResponse(agentsResult, [] as AgentInfo[], {
preferResponseOnMissingData: true,
})
const callableAgents = agents.filter((a) => a.mode !== "primary")
+2 -1
View File
@@ -10,6 +10,7 @@ import { findNearestMessageWithFields } from "../../features/hook-message-inject
import { formatDuration } from "./time-formatter"
import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continuation-deps"
import { setSessionTools } from "../../shared/session-tools-store"
import { normalizeSDKResponse } from "../../shared"
export async function executeSyncContinuation(
args: DelegateTaskArgs,
@@ -56,7 +57,7 @@ export async function executeSyncContinuation(
try {
try {
const messagesResp = await client.session.messages({ path: { id: args.session_id! } })
const messages = (messagesResp.data ?? []) as SessionMessage[]
const messages = normalizeSDKResponse(messagesResp, [] as SessionMessage[])
anchorMessageCount = messages.length
for (let i = messages.length - 1; i >= 0; i--) {
const info = messages[i].info
@@ -1,5 +1,6 @@
import type { OpencodeClient } from "./types"
import type { SessionMessage } from "./executor-types"
import { normalizeSDKResponse } from "../../shared"
export async function fetchSyncResult(
client: OpencodeClient,
@@ -14,7 +15,9 @@ export async function fetchSyncResult(
return { ok: false, error: `Error fetching result: ${(messagesResult as { error: unknown }).error}\n\nSession ID: ${sessionID}` }
}
const messages = ((messagesResult as { data?: unknown }).data ?? messagesResult) as SessionMessage[]
const messages = normalizeSDKResponse(messagesResult, [] as SessionMessage[], {
preferResponseOnMissingData: true,
})
const messagesAfterAnchor = anchorMessageCount !== undefined ? messages.slice(anchorMessageCount) : messages
@@ -2,6 +2,7 @@ import type { ToolContextWithMetadata, OpencodeClient } from "./types"
import type { SessionMessage } from "./executor-types"
import { getTimingConfig } from "./timing"
import { log } from "../../shared/logger"
import { normalizeSDKResponse } from "../../shared"
const NON_TERMINAL_FINISH_REASONS = new Set(["tool-calls", "unknown"])
@@ -58,7 +59,7 @@ export async function pollSyncSession(
log("[task] Poll status fetch failed, retrying", { sessionID: input.sessionID, error: String(error) })
continue
}
const allStatuses = (statusResult.data ?? {}) as Record<string, { type: string }>
const allStatuses = normalizeSDKResponse(statusResult, {} as Record<string, { type: string }>)
const sessionStatus = allStatuses[input.sessionID]
if (pollCount % 10 === 0) {
@@ -5,6 +5,7 @@ import { storeToolMetadata } from "../../features/tool-metadata-store"
import { formatDuration } from "./time-formatter"
import { formatDetailedError } from "./error-formatting"
import { getSessionTools } from "../../shared/session-tools-store"
import { normalizeSDKResponse } from "../../shared"
export async function executeUnstableAgentTask(
args: DelegateTaskArgs,
@@ -93,7 +94,7 @@ export async function executeUnstableAgentTask(
}
const statusResult = await client.session.status()
const allStatuses = (statusResult.data ?? {}) as Record<string, { type: string }>
const allStatuses = normalizeSDKResponse(statusResult, {} as Record<string, { type: string }>)
const sessionStatus = allStatuses[sessionID]
if (sessionStatus && sessionStatus.type !== "idle") {
@@ -105,7 +106,9 @@ export async function executeUnstableAgentTask(
if (Date.now() - pollStart < timingCfg.MIN_STABILITY_TIME_MS) continue
const messagesCheck = await client.session.messages({ path: { id: sessionID } })
const msgs = ((messagesCheck as { data?: unknown }).data ?? messagesCheck) as Array<unknown>
const msgs = normalizeSDKResponse(messagesCheck, [] as Array<unknown>, {
preferResponseOnMissingData: true,
})
const currentMsgCount = msgs.length
if (currentMsgCount === lastMsgCount) {
@@ -136,7 +139,9 @@ session_id: ${sessionID}
}
const messagesResult = await client.session.messages({ path: { id: sessionID } })
const messages = ((messagesResult as { data?: unknown }).data ?? messagesResult) as SessionMessage[]
const messages = normalizeSDKResponse(messagesResult, [] as SessionMessage[], {
preferResponseOnMissingData: true,
})
const assistantMessages = messages
.filter((m) => m.info?.role === "assistant")
+8 -7
View File
@@ -6,6 +6,7 @@ import { MESSAGE_STORAGE, PART_STORAGE, SESSION_STORAGE, TODO_DIR, TRANSCRIPT_DI
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
import { getMessageDir } from "../../shared/opencode-message-dir"
import type { SessionMessage, SessionInfo, TodoItem, SessionMetadata } from "./types"
import { normalizeSDKResponse } from "../../shared"
export interface GetMainSessionsOptions {
directory?: string
@@ -27,7 +28,7 @@ export async function getMainSessions(options: GetMainSessionsOptions): Promise<
if (isSqliteBackend() && sdkClient) {
try {
const response = await sdkClient.session.list()
const sessions = (response.data || []) as SessionMetadata[]
const sessions = normalizeSDKResponse(response, [] as SessionMetadata[])
const mainSessions = sessions.filter((s) => !s.parentID)
if (options.directory) {
return mainSessions
@@ -82,7 +83,7 @@ export async function getAllSessions(): Promise<string[]> {
if (isSqliteBackend() && sdkClient) {
try {
const response = await sdkClient.session.list()
const sessions = (response.data || []) as SessionMetadata[]
const sessions = normalizeSDKResponse(response, [] as SessionMetadata[])
return sessions.map((s) => s.id)
} catch {
return []
@@ -122,7 +123,7 @@ export { getMessageDir } from "../../shared/opencode-message-dir"
export async function sessionExists(sessionID: string): Promise<boolean> {
if (isSqliteBackend() && sdkClient) {
const response = await sdkClient.session.list()
const sessions = (response.data || []) as Array<{ id?: string }>
const sessions = normalizeSDKResponse(response, [] as Array<{ id?: string }>)
return sessions.some((s) => s.id === sessionID)
}
return getMessageDir(sessionID) !== null
@@ -133,7 +134,7 @@ export async function readSessionMessages(sessionID: string): Promise<SessionMes
if (isSqliteBackend() && sdkClient) {
try {
const response = await sdkClient.session.messages({ path: { id: sessionID } })
const rawMessages = (response.data || []) as Array<{
const rawMessages = normalizeSDKResponse(response, [] as Array<{
info?: {
id?: string
role?: string
@@ -151,7 +152,7 @@ export async function readSessionMessages(sessionID: string): Promise<SessionMes
output?: string
error?: string
}>
}>
}>)
const messages: SessionMessage[] = rawMessages
.filter((m) => m.info?.id)
.map((m) => ({
@@ -254,12 +255,12 @@ export async function readSessionTodos(sessionID: string): Promise<TodoItem[]> {
if (isSqliteBackend() && sdkClient) {
try {
const response = await sdkClient.session.todo({ path: { id: sessionID } })
const data = (response.data || []) as Array<{
const data = normalizeSDKResponse(response, [] as Array<{
id?: string
content?: string
status?: string
priority?: string
}>
}>)
return data.map((item) => ({
id: item.id || "",
content: item.content || "",