fix(runtime-fallback): handle object-shaped event models
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -18,6 +18,27 @@ function resolveEventModel(props: Record<string, unknown> | undefined): string |
|
||||
return model
|
||||
}
|
||||
|
||||
if (model && typeof model === "object") {
|
||||
const modelRecord = model as Record<string, unknown>
|
||||
const provider = modelRecord.provider
|
||||
const providerID = modelRecord.providerID
|
||||
const modelName = modelRecord.model
|
||||
const modelID = modelRecord.modelID
|
||||
const id = modelRecord.id
|
||||
|
||||
if (typeof provider === "string" && typeof modelName === "string") {
|
||||
return `${provider}/${modelName}`
|
||||
}
|
||||
|
||||
if (typeof providerID === "string" && typeof modelID === "string") {
|
||||
return `${providerID}/${modelID}`
|
||||
}
|
||||
|
||||
if (typeof id === "string") {
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
const providerID = props?.providerID
|
||||
const modelID = props?.modelID
|
||||
if (typeof providerID === "string" && typeof modelID === "string") {
|
||||
@@ -45,9 +66,9 @@ 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 sessionInfo = props?.info as Record<string, unknown> | undefined
|
||||
const sessionID = resolveSessionEventID(props)
|
||||
const model = sessionInfo?.model
|
||||
const model = resolveEventModel(sessionInfo)
|
||||
|
||||
if (sessionID && model) {
|
||||
log(`[${HOOK_NAME}] Session created with model`, { sessionID, model })
|
||||
@@ -209,7 +230,7 @@ export function createEventHandler(deps: HookDeps, helpers: AutoRetryHelpers) {
|
||||
const initialModel = resolveFallbackBootstrapModel({
|
||||
sessionID,
|
||||
source: "session.error",
|
||||
eventModel: props?.model as string | undefined,
|
||||
eventModel: resolveEventModel(props),
|
||||
resolvedAgent,
|
||||
pluginConfig,
|
||||
})
|
||||
|
||||
@@ -50,6 +50,8 @@ function parseCanonicalModel(model: string): { providerID: string; modelID: stri
|
||||
}
|
||||
|
||||
function isEquivalentModel(candidate: string, current: string): boolean {
|
||||
if (typeof current !== "string") return false
|
||||
|
||||
const parsedCandidate = parseCanonicalModel(candidate)
|
||||
const parsedCurrent = parseCanonicalModel(current)
|
||||
|
||||
|
||||
@@ -1024,6 +1024,50 @@ describe("runtime-fallback", () => {
|
||||
expect(createLog?.data).toMatchObject({ sessionID, model })
|
||||
})
|
||||
|
||||
test("#given session.created carries an object-shaped model #when fallback is prepared #then it does not crash", async () => {
|
||||
//#given
|
||||
const promptCalls: unknown[] = []
|
||||
const sessionID = "test-session-object-model"
|
||||
const hook = createRuntimeFallbackHook(
|
||||
createMockPluginInput({
|
||||
session: {
|
||||
messages: async () => ({
|
||||
data: [{ info: { role: "user" }, parts: [{ type: "text", text: "continue" }] }],
|
||||
}),
|
||||
promptAsync: async (args: unknown) => {
|
||||
promptCalls.push(args)
|
||||
return {}
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
config: createMockConfig({ notify_on_fallback: false }),
|
||||
pluginConfig: createMockPluginConfigWithCategoryFallback(["openai/gpt-5.4"]),
|
||||
},
|
||||
)
|
||||
SessionCategoryRegistry.register(sessionID, "test")
|
||||
|
||||
await hook.event({
|
||||
event: {
|
||||
type: "session.created",
|
||||
properties: { info: { id: sessionID, model: { provider: "openai", model: "gpt-5.5-fast" } } },
|
||||
},
|
||||
})
|
||||
|
||||
//#when
|
||||
await hook.event({
|
||||
event: {
|
||||
type: "session.error",
|
||||
properties: { sessionID, error: { statusCode: 429, message: "Rate limit" } },
|
||||
},
|
||||
})
|
||||
|
||||
//#then
|
||||
expect(promptCalls).toHaveLength(1)
|
||||
const createLog = logCalls.find((c) => c.msg.includes("Session created with model"))
|
||||
expect(createLog?.data).toMatchObject({ sessionID, model: "openai/gpt-5.5-fast" })
|
||||
})
|
||||
|
||||
test("should cleanup state on session.deleted", async () => {
|
||||
const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig() })
|
||||
const sessionID = "test-session-delete"
|
||||
|
||||
Reference in New Issue
Block a user