fix: address cubic review — SDK compatibility and race condition fixes
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
import type { OhMyOpenCodeConfig } from "../config"
|
import type { OhMyOpenCodeConfig } from "../config"
|
||||||
import { log } from "../shared/logger"
|
import { log } from "../shared/logger"
|
||||||
import { isStepOnlyNoTextParts, resolveNoTextTailFromSession } from "./preemptive-compaction-no-text-tail"
|
import { resolveNoTextTailFromSession } from "./preemptive-compaction-no-text-tail"
|
||||||
import { resolveCompactionModel } from "./shared/compaction-model-resolver"
|
import { resolveCompactionModel } from "./shared/compaction-model-resolver"
|
||||||
|
|
||||||
const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 120_000
|
const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 120_000
|
||||||
const POST_COMPACTION_MONITOR_COUNT = 5
|
const POST_COMPACTION_MONITOR_COUNT = 5
|
||||||
const POST_COMPACTION_NO_TEXT_THRESHOLD = 3
|
const POST_COMPACTION_NO_TEXT_THRESHOLD = 3
|
||||||
|
|
||||||
|
declare function setTimeout(handler: () => void, timeout?: number): unknown
|
||||||
|
declare function clearTimeout(timeoutID: unknown): void
|
||||||
|
|
||||||
interface CompactionTargetState {
|
interface CompactionTargetState {
|
||||||
providerID: string
|
providerID: string
|
||||||
modelID: string
|
modelID: string
|
||||||
@@ -16,12 +19,12 @@ interface ClientLike {
|
|||||||
session: {
|
session: {
|
||||||
summarize: (input: {
|
summarize: (input: {
|
||||||
path: { id: string }
|
path: { id: string }
|
||||||
body: { providerID: string; modelID: string; auto: true }
|
body: { providerID: string; modelID: string }
|
||||||
query: { directory: string }
|
query: { directory: string }
|
||||||
}) => Promise<unknown>
|
}) => Promise<unknown>
|
||||||
messages: (input: {
|
messages: (input: {
|
||||||
path: { id: string }
|
sessionID: string
|
||||||
query: { directory: string }
|
directory: string
|
||||||
}) => Promise<unknown>
|
}) => Promise<unknown>
|
||||||
}
|
}
|
||||||
tui: {
|
tui: {
|
||||||
@@ -39,7 +42,6 @@ interface ClientLike {
|
|||||||
export interface AssistantCompactionMessageInfo {
|
export interface AssistantCompactionMessageInfo {
|
||||||
sessionID: string
|
sessionID: string
|
||||||
id?: string
|
id?: string
|
||||||
parts?: unknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function withTimeout<TValue>(
|
async function withTimeout<TValue>(
|
||||||
@@ -47,7 +49,7 @@ async function withTimeout<TValue>(
|
|||||||
timeoutMs: number,
|
timeoutMs: number,
|
||||||
errorMessage: string,
|
errorMessage: string,
|
||||||
): Promise<TValue> {
|
): Promise<TValue> {
|
||||||
let timeoutID: ReturnType<typeof setTimeout> | undefined
|
let timeoutID: unknown
|
||||||
|
|
||||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||||
timeoutID = setTimeout(() => {
|
timeoutID = setTimeout(() => {
|
||||||
@@ -56,7 +58,7 @@ async function withTimeout<TValue>(
|
|||||||
})
|
})
|
||||||
|
|
||||||
return await Promise.race([promise, timeoutPromise]).finally(() => {
|
return await Promise.race([promise, timeoutPromise]).finally(() => {
|
||||||
if (timeoutID !== undefined) clearTimeout(timeoutID)
|
clearTimeout(timeoutID)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,14 +73,18 @@ export function createPostCompactionDegradationMonitor(args: {
|
|||||||
const postCompactionRemaining = new Map<string, number>()
|
const postCompactionRemaining = new Map<string, number>()
|
||||||
const postCompactionNoTextStreak = new Map<string, number>()
|
const postCompactionNoTextStreak = new Map<string, number>()
|
||||||
const postCompactionRecoveryTriggered = new Set<string>()
|
const postCompactionRecoveryTriggered = new Set<string>()
|
||||||
|
const postCompactionEpoch = new Map<string, number>()
|
||||||
|
|
||||||
const clear = (sessionID: string): void => {
|
const clear = (sessionID: string): void => {
|
||||||
postCompactionRemaining.delete(sessionID)
|
postCompactionRemaining.delete(sessionID)
|
||||||
postCompactionNoTextStreak.delete(sessionID)
|
postCompactionNoTextStreak.delete(sessionID)
|
||||||
postCompactionRecoveryTriggered.delete(sessionID)
|
postCompactionRecoveryTriggered.delete(sessionID)
|
||||||
|
postCompactionEpoch.delete(sessionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSessionCompacted = (sessionID: string): void => {
|
const onSessionCompacted = (sessionID: string): void => {
|
||||||
|
const nextEpoch = (postCompactionEpoch.get(sessionID) ?? 0) + 1
|
||||||
|
postCompactionEpoch.set(sessionID, nextEpoch)
|
||||||
postCompactionRemaining.set(sessionID, POST_COMPACTION_MONITOR_COUNT)
|
postCompactionRemaining.set(sessionID, POST_COMPACTION_MONITOR_COUNT)
|
||||||
postCompactionNoTextStreak.set(sessionID, 0)
|
postCompactionNoTextStreak.set(sessionID, 0)
|
||||||
postCompactionRecoveryTriggered.delete(sessionID)
|
postCompactionRecoveryTriggered.delete(sessionID)
|
||||||
@@ -95,6 +101,7 @@ export function createPostCompactionDegradationMonitor(args: {
|
|||||||
|
|
||||||
postCompactionRecoveryTriggered.add(sessionID)
|
postCompactionRecoveryTriggered.add(sessionID)
|
||||||
compactionInProgress.add(sessionID)
|
compactionInProgress.add(sessionID)
|
||||||
|
const recoveryEpoch = postCompactionEpoch.get(sessionID) ?? 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { providerID: targetProviderID, modelID: targetModelID } = resolveCompactionModel(
|
const { providerID: targetProviderID, modelID: targetModelID } = resolveCompactionModel(
|
||||||
@@ -118,7 +125,7 @@ export function createPostCompactionDegradationMonitor(args: {
|
|||||||
await withTimeout(
|
await withTimeout(
|
||||||
client.session.summarize({
|
client.session.summarize({
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: { providerID: targetProviderID, modelID: targetModelID, auto: true },
|
body: { providerID: targetProviderID, modelID: targetModelID },
|
||||||
query: { directory },
|
query: { directory },
|
||||||
}),
|
}),
|
||||||
PREEMPTIVE_COMPACTION_TIMEOUT_MS,
|
PREEMPTIVE_COMPACTION_TIMEOUT_MS,
|
||||||
@@ -133,7 +140,9 @@ export function createPostCompactionDegradationMonitor(args: {
|
|||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
compactionInProgress.delete(sessionID)
|
compactionInProgress.delete(sessionID)
|
||||||
clear(sessionID)
|
if ((postCompactionEpoch.get(sessionID) ?? 0) === recoveryEpoch) {
|
||||||
|
clear(sessionID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,13 +156,12 @@ export function createPostCompactionDegradationMonitor(args: {
|
|||||||
postCompactionRemaining.set(info.sessionID, remaining - 1)
|
postCompactionRemaining.set(info.sessionID, remaining - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isNoTextTail = isStepOnlyNoTextParts(info.parts)
|
const isNoTextTail = await resolveNoTextTailFromSession({
|
||||||
|| await resolveNoTextTailFromSession({
|
client,
|
||||||
client,
|
sessionID: info.sessionID,
|
||||||
sessionID: info.sessionID,
|
messageID: info.id,
|
||||||
messageID: info.id,
|
directory,
|
||||||
directory,
|
})
|
||||||
})
|
|
||||||
|
|
||||||
if (!isNoTextTail) {
|
if (!isNoTextTail) {
|
||||||
postCompactionNoTextStreak.set(info.sessionID, 0)
|
postCompactionNoTextStreak.set(info.sessionID, 0)
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ export async function resolveNoTextTailFromSession(args: {
|
|||||||
client: {
|
client: {
|
||||||
session: {
|
session: {
|
||||||
messages: (input: {
|
messages: (input: {
|
||||||
path: { id: string }
|
sessionID: string
|
||||||
query: { directory: string }
|
directory: string
|
||||||
}) => Promise<unknown>
|
}) => Promise<unknown>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,8 +51,8 @@ export async function resolveNoTextTailFromSession(args: {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await client.session.messages({
|
const response = await client.session.messages({
|
||||||
path: { id: sessionID },
|
sessionID,
|
||||||
query: { directory },
|
directory,
|
||||||
})
|
})
|
||||||
|
|
||||||
const messages = normalizeSDKResponse(response, [] as SessionMessage[], {
|
const messages = normalizeSDKResponse(response, [] as SessionMessage[], {
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import { createPostCompactionDegradationMonitor } from "./preemptive-compaction-
|
|||||||
const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 120_000
|
const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 120_000
|
||||||
const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78
|
const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78
|
||||||
|
|
||||||
|
declare function setTimeout(handler: () => void, timeout?: number): unknown
|
||||||
|
declare function clearTimeout(timeoutID: unknown): void
|
||||||
|
|
||||||
interface TokenInfo {
|
interface TokenInfo {
|
||||||
input: number
|
input: number
|
||||||
output: number
|
output: number
|
||||||
@@ -29,7 +32,7 @@ async function withTimeout<TValue>(
|
|||||||
timeoutMs: number,
|
timeoutMs: number,
|
||||||
errorMessage: string,
|
errorMessage: string,
|
||||||
): Promise<TValue> {
|
): Promise<TValue> {
|
||||||
let timeoutID: ReturnType<typeof setTimeout> | undefined
|
let timeoutID: unknown
|
||||||
|
|
||||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||||
timeoutID = setTimeout(() => {
|
timeoutID = setTimeout(() => {
|
||||||
@@ -38,9 +41,7 @@ async function withTimeout<TValue>(
|
|||||||
})
|
})
|
||||||
|
|
||||||
return await Promise.race([promise, timeoutPromise]).finally(() => {
|
return await Promise.race([promise, timeoutPromise]).finally(() => {
|
||||||
if (timeoutID !== undefined) {
|
clearTimeout(timeoutID)
|
||||||
clearTimeout(timeoutID)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +166,6 @@ export function createPreemptiveCompactionHook(
|
|||||||
modelID?: string
|
modelID?: string
|
||||||
finish?: boolean
|
finish?: boolean
|
||||||
tokens?: TokenInfo
|
tokens?: TokenInfo
|
||||||
parts?: unknown
|
|
||||||
} | undefined
|
} | undefined
|
||||||
|
|
||||||
if (!info || info.role !== "assistant" || !info.finish || !info.sessionID) return
|
if (!info || info.role !== "assistant" || !info.finish || !info.sessionID) return
|
||||||
@@ -182,7 +182,6 @@ export function createPreemptiveCompactionHook(
|
|||||||
await postCompactionMonitor.onAssistantMessageUpdated({
|
await postCompactionMonitor.onAssistantMessageUpdated({
|
||||||
sessionID: info.sessionID,
|
sessionID: info.sessionID,
|
||||||
id: info.id,
|
id: info.id,
|
||||||
parts: info.parts,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user