Merge branch 'dev' into fix/surface-subagent-quota-error

This commit is contained in:
Ivan Smetanin
2026-05-12 22:17:38 +01:00
committed by GitHub
225 changed files with 4552 additions and 2104 deletions
+7 -7
View File
@@ -10,6 +10,7 @@ import { isAbortError } from "../../shared/is-abort-error"
import { resolveFallbackBootstrapModel } from "./fallback-bootstrap-model"
import { dispatchFallbackRetry } from "./fallback-retry-dispatcher"
import { createSessionStatusHandler } from "./session-status-handler"
import { resolveMessageEventSessionID, resolveSessionEventID } from "../../shared/event-session-id"
export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
const { config, pluginConfig, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts, sessionStatusRetryKeys } = deps
@@ -30,7 +31,7 @@ export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
const handleSessionCreated = (props: Record<string, unknown> | undefined) => {
const sessionInfo = props?.info as { id?: string; model?: string } | undefined
const sessionID = sessionInfo?.id
const sessionID = resolveSessionEventID(props)
const model = sessionInfo?.model
if (sessionID && model) {
@@ -41,8 +42,7 @@ export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
}
const handleSessionDeleted = (props: Record<string, unknown> | undefined) => {
const sessionInfo = props?.info as { id?: string } | undefined
const sessionID = sessionInfo?.id
const sessionID = resolveSessionEventID(props)
if (sessionID) {
log(`[${HOOK_NAME}] Cleaning up session state`, { sessionID })
@@ -58,7 +58,7 @@ export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
}
const handleSessionStop = async (props: Record<string, unknown> | undefined) => {
const sessionID = props?.sessionID as string | undefined
const sessionID = resolveSessionEventID(props)
if (!sessionID) return
if (sessionRetryInFlight.has(sessionID) || sessionAwaitingFallbackResult.has(sessionID)) {
@@ -73,7 +73,7 @@ export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
const handleMessageUpdated = (props: Record<string, unknown> | undefined) => {
const info = props?.info as Record<string, unknown> | undefined
const sessionID = info?.sessionID as string | undefined
const sessionID = resolveMessageEventSessionID(props)
const role = info?.role as string | undefined
if (!sessionID || role !== "user") return
@@ -81,7 +81,7 @@ export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
}
const handleSessionIdle = (props: Record<string, unknown> | undefined) => {
const sessionID = props?.sessionID as string | undefined
const sessionID = resolveSessionEventID(props)
if (!sessionID) return
if (cancelledSessions.has(sessionID)) {
@@ -111,7 +111,7 @@ export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
}
const handleSessionError = async (props: Record<string, unknown> | undefined) => {
const sessionID = props?.sessionID as string | undefined
const sessionID = resolveSessionEventID(props)
const error = props?.error
const agent = props?.agent as string | undefined
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test"
import { getFallbackModelsForSession } from "./fallback-models"
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
describe("runtime-fallback fallback-models", () => {
afterEach(() => {
@@ -12,13 +13,13 @@ describe("runtime-fallback fallback-models", () => {
//#given
const sessionID = "ses_runtime_fallback_category"
SessionCategoryRegistry.register(sessionID, "quick")
const pluginConfig = {
const pluginConfig = unsafeTestValue({
categories: {
quick: {
fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"],
},
},
} as any
})
//#when
const result = getFallbackModelsForSession(sessionID, undefined, pluginConfig)
@@ -29,13 +30,13 @@ describe("runtime-fallback fallback-models", () => {
test("uses agent-specific fallback_models when agent is resolved", () => {
//#given
const pluginConfig = {
const pluginConfig = unsafeTestValue({
agents: {
oracle: {
fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"],
},
},
} as any
})
//#when
const result = getFallbackModelsForSession("ses_runtime_fallback_agent", "oracle", pluginConfig)
@@ -46,7 +47,7 @@ describe("runtime-fallback fallback-models", () => {
test("does not fall back to another agent chain when agent cannot be resolved", () => {
//#given
const pluginConfig = {
const pluginConfig = unsafeTestValue({
agents: {
sisyphus: {
fallback_models: ["quotio/gpt-5.2", "quotio/glm-5", "quotio/kimi-k2.5"],
@@ -55,7 +56,7 @@ describe("runtime-fallback fallback-models", () => {
fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"],
},
},
} as any
})
//#when
const result = getFallbackModelsForSession("ses_runtime_fallback_unknown", undefined, pluginConfig)
+3 -2
View File
@@ -2,6 +2,7 @@ import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test"
import type { RuntimeFallbackConfig, OhMyOpenCodeConfig } from "../../config"
import * as loggerModule from "../../shared/logger"
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
type RuntimeFallbackModule = typeof import("./hook")
@@ -41,7 +42,7 @@ describe("runtime-fallback", () => {
abort?: (args: unknown) => Promise<unknown>
}
}) {
return {
return unsafeTestValue({
client: {
tui: {
showToast: async (opts: { body: { title: string; message: string; variant: string; duration: number } }) => {
@@ -59,7 +60,7 @@ describe("runtime-fallback", () => {
},
},
directory: "/test/dir",
} as any
})
}
function createMockConfig(overrides?: Partial<RuntimeFallbackConfig>): RuntimeFallbackConfig {
@@ -9,6 +9,7 @@ import { resolveFallbackBootstrapModel } from "./fallback-bootstrap-model"
import { dispatchFallbackRetry } from "./fallback-retry-dispatcher"
import { hasVisibleAssistantResponse } from "./visible-assistant-response"
import { subagentSessions } from "../../features/claude-code-session-state"
import { resolveMessageEventSessionID } from "../../shared/event-session-id"
export { hasVisibleAssistantResponse } from "./visible-assistant-response"
@@ -18,7 +19,7 @@ export function createMessageUpdateHandler(deps: HookDeps, helpers: AutoRetryHel
return async (props: Record<string, unknown> | undefined) => {
const info = props?.info as Record<string, unknown> | undefined
const sessionID = info?.sessionID as string | undefined
const sessionID = resolveMessageEventSessionID(props)
const timeoutEnabled = config.timeout_seconds > 0
const eventParts = props?.parts as Array<{ type?: string; text?: string }> | undefined
const infoParts = info?.parts as Array<{ type?: string; text?: string }> | undefined
@@ -8,6 +8,7 @@ import { getFallbackModelsForSession } from "./fallback-models"
import { normalizeRetryStatusMessage, extractRetryAttempt } from "../../shared/retry-status-utils"
import { resolveFallbackBootstrapModel } from "./fallback-bootstrap-model"
import { dispatchFallbackRetry } from "./fallback-retry-dispatcher"
import { resolveSessionEventID } from "../../shared/event-session-id"
export function createSessionStatusHandler(
deps: HookDeps,
@@ -22,7 +23,7 @@ export function createSessionStatusHandler(
} = deps
return async (props: Record<string, unknown> | undefined) => {
const sessionID = props?.sessionID as string | undefined
const sessionID = resolveSessionEventID(props)
const status = props?.status as { type?: string; message?: string; attempt?: number } | undefined
const agent = props?.agent as string | undefined
const model = props?.model as string | undefined