refactor(sdk): narrow response fallbacks

Replace unsafe unknown-array assertions with generic fallback types and explicit todo status narrowing.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-05-15 16:31:13 +09:00
parent 4785767a0c
commit d92e78c956
3 changed files with 19 additions and 15 deletions
+16 -12
View File
@@ -2,7 +2,7 @@ import pc from "picocolors"
import type { RunContext } from "./types"
import type { EventState } from "./events"
import { checkCompletionConditions } from "./completion"
import { normalizeSDKResponse } from "../../shared"
import { isRecord, normalizeSDKResponse } from "../../shared"
const DEFAULT_POLL_INTERVAL_MS = 500
const DEFAULT_REQUIRED_CONSECUTIVE = 1
@@ -11,6 +11,17 @@ const MIN_STABILIZATION_MS = 1_000
const DEFAULT_EVENT_WATCHDOG_MS = 30_000 // 30 seconds
const DEFAULT_SECONDARY_MEANINGFUL_WORK_TIMEOUT_MS = 60_000 // 60 seconds
type SessionStatusMap = Record<string, { type?: string }>
function isIncompleteTodo(value: unknown): boolean {
if (!isRecord(value)) {
return true
}
const status = value.status
return status !== "completed" && status !== "cancelled"
}
export interface PollOptions {
pollIntervalMs?: number
requiredConsecutive?: number
@@ -123,22 +134,18 @@ export async function pollForCompletion(
path: { id: ctx.sessionID },
query: { directory: ctx.directory },
})
const children = normalizeSDKResponse(childrenRes, [] as unknown[])
const children = normalizeSDKResponse<unknown[]>(childrenRes, [])
const todosRes = await ctx.client.session.todo({
path: { id: ctx.sessionID },
query: { directory: ctx.directory },
})
const todos = normalizeSDKResponse(todosRes, [] as unknown[])
const todos = normalizeSDKResponse<unknown[]>(todosRes, [])
const hasActiveChildren =
Array.isArray(children) && children.length > 0
const hasActiveTodos =
Array.isArray(todos) &&
todos.some(
(t: unknown) =>
(t as { status?: string })?.status !== "completed" &&
(t as { status?: string })?.status !== "cancelled"
)
todos.some(isIncompleteTodo)
const hasActiveWork = hasActiveChildren || hasActiveTodos
if (hasActiveWork) {
@@ -189,10 +196,7 @@ async function getMainSessionStatus(
const statusesRes = await ctx.client.session.status({
query: { directory: ctx.directory },
})
const statuses = normalizeSDKResponse(
statusesRes,
{} as Record<string, { type?: string }>
)
const statuses = normalizeSDKResponse<SessionStatusMap>(statusesRes, {})
if (!(ctx.sessionID in statuses)) {
return "idle"
}
+2 -2
View File
@@ -189,8 +189,8 @@ export function createReadImageResizerHook(_ctx: PluginInput) {
}
}
if (attachmentsToRemove.length > 0) {
const rawAttachments = outputRecord.attachments as unknown[]
if (attachmentsToRemove.length > 0 && Array.isArray(outputRecord.attachments)) {
const rawAttachments = outputRecord.attachments
for (const toRemove of attachmentsToRemove) {
const removeIndex = rawAttachments.indexOf(toRemove)
if (removeIndex !== -1) {
@@ -62,7 +62,7 @@ export async function readMessagesFromSDK(
): Promise<StoredMessageMeta[]> {
try {
const response = await client.session.messages({ path: { id: sessionID } })
const data = normalizeSDKResponse(response, [] as unknown[], {
const data = normalizeSDKResponse<unknown[]>(response, [], {
preferResponseOnMissingData: true,
})
if (!Array.isArray(data)) return []