fix(#2852): forward model overrides from categories/agent config to subagents
- fix(switcher): use lastIndexOf for multi-slash model IDs (e.g. aws/anthropic/claude-sonnet-4) - fix(model-resolution): same lastIndexOf fix in doctor parseProviderModel - fix(call-omo-agent): resolve model from agent config and forward to both background and sync executors via DelegatedModelConfig - fix(subagent-resolver): inherit category model/variant when agent uses category reference without explicit model override - test: add model override forwarding tests for call-omo-agent - test: add multi-slash model ID test for switcher
This commit is contained in:
@@ -451,7 +451,9 @@ describe("preemptive-compaction", () => {
|
||||
|
||||
expect(ctx.client.session.summarize).toHaveBeenCalledTimes(1)
|
||||
|
||||
// when - new message with high tokens (context grew after compaction)
|
||||
// when - advance past the 60s cooldown window, then new message with high tokens
|
||||
const originalNow = Date.now
|
||||
Date.now = () => originalNow() + 61_000
|
||||
await hook.event({
|
||||
event: {
|
||||
type: "message.updated",
|
||||
@@ -480,6 +482,7 @@ describe("preemptive-compaction", () => {
|
||||
|
||||
// then - summarize should fire again
|
||||
expect(ctx.client.session.summarize).toHaveBeenCalledTimes(2)
|
||||
Date.now = originalNow
|
||||
})
|
||||
|
||||
// #given modelContextLimitsCache has model-specific limit (256k)
|
||||
|
||||
@@ -10,6 +10,7 @@ import { createPostCompactionDegradationMonitor } from "./preemptive-compaction-
|
||||
|
||||
const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 120_000
|
||||
const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78
|
||||
const PREEMPTIVE_COMPACTION_COOLDOWN_MS = 60_000
|
||||
|
||||
declare function setTimeout(handler: () => void, timeout?: number): unknown
|
||||
declare function clearTimeout(timeoutID: unknown): void
|
||||
@@ -68,6 +69,7 @@ export function createPreemptiveCompactionHook(
|
||||
) {
|
||||
const compactionInProgress = new Set<string>()
|
||||
const compactedSessions = new Set<string>()
|
||||
const lastCompactionTime = new Map<string, number>()
|
||||
const tokenCache = new Map<string, CachedCompactionState>()
|
||||
|
||||
const postCompactionMonitor = createPostCompactionDegradationMonitor({
|
||||
@@ -85,6 +87,9 @@ export function createPreemptiveCompactionHook(
|
||||
const { sessionID } = input
|
||||
if (compactedSessions.has(sessionID) || compactionInProgress.has(sessionID)) return
|
||||
|
||||
const lastTime = lastCompactionTime.get(sessionID)
|
||||
if (lastTime && Date.now() - lastTime < PREEMPTIVE_COMPACTION_COOLDOWN_MS) return
|
||||
|
||||
const cached = tokenCache.get(sessionID)
|
||||
if (!cached) return
|
||||
|
||||
@@ -127,6 +132,7 @@ export function createPreemptiveCompactionHook(
|
||||
)
|
||||
|
||||
compactedSessions.add(sessionID)
|
||||
lastCompactionTime.set(sessionID, Date.now())
|
||||
} catch (error) {
|
||||
log("[preemptive-compaction] Compaction failed", { sessionID, error: String(error) })
|
||||
} finally {
|
||||
@@ -142,6 +148,7 @@ export function createPreemptiveCompactionHook(
|
||||
if (sessionID) {
|
||||
compactionInProgress.delete(sessionID)
|
||||
compactedSessions.delete(sessionID)
|
||||
lastCompactionTime.delete(sessionID)
|
||||
tokenCache.delete(sessionID)
|
||||
postCompactionMonitor.clear(sessionID)
|
||||
}
|
||||
|
||||
@@ -146,6 +146,19 @@ describe("think-mode switcher", () => {
|
||||
expect(getHighVariant("custom-llm/gemini-3.1-pro")).toBe("custom-llm/gemini-3-1-pro-high")
|
||||
})
|
||||
|
||||
it("should handle multi-slash model IDs (#2852)", () => {
|
||||
// given model IDs with multiple slashes (e.g. aws/anthropic/claude-sonnet-4)
|
||||
const variant = getHighVariant("aws/anthropic/claude-sonnet-4-6")
|
||||
|
||||
// then should split at last slash, preserving full provider prefix
|
||||
expect(variant).toBe("aws/anthropic/claude-sonnet-4-6-high")
|
||||
})
|
||||
|
||||
it("should return null for multi-slash unknown models", () => {
|
||||
// given multi-slash model ID without high variant mapping
|
||||
expect(getHighVariant("aws/anthropic/unknown-model")).toBeNull()
|
||||
})
|
||||
|
||||
it("should return null for prefixed models without high variant mapping", () => {
|
||||
// given prefixed model IDs without high variant mapping
|
||||
expect(getHighVariant("vertex_ai/unknown-model")).toBeNull()
|
||||
|
||||
@@ -26,9 +26,10 @@ import { normalizeModelID } from "../../shared"
|
||||
* extractModelPrefix("vertex_ai/claude-sonnet-4-6") // { prefix: "vertex_ai/", base: "claude-sonnet-4-6" }
|
||||
* extractModelPrefix("claude-sonnet-4-6") // { prefix: "", base: "claude-sonnet-4-6" }
|
||||
* extractModelPrefix("openai/gpt-5.4") // { prefix: "openai/", base: "gpt-5.4" }
|
||||
* extractModelPrefix("aws/anthropic/claude-sonnet-4") // { prefix: "aws/anthropic/", base: "claude-sonnet-4" }
|
||||
*/
|
||||
function extractModelPrefix(modelID: string): { prefix: string; base: string } {
|
||||
const slashIndex = modelID.indexOf("/")
|
||||
const slashIndex = modelID.lastIndexOf("/")
|
||||
if (slashIndex === -1) {
|
||||
return { prefix: "", base: modelID }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user