fix: preserve unexpected provider finish reasons

This commit is contained in:
marius-kilocode
2026-07-24 12:20:43 +02:00
parent e6f4216088
commit 2fcb137ebc
34 changed files with 144 additions and 9 deletions
@@ -10,7 +10,7 @@ import * as Log from "@opencode-ai/core/util/log"
import { Cause, Effect, Exit } from "effect"
import { Flag } from "@opencode-ai/core/flag/flag"
import { EffectBridge } from "@/effect/bridge"
import type { LLMEvent, Usage } from "@opencode-ai/llm"
import type { LLMEvent, ProviderMetadata, Usage } from "@opencode-ai/llm"
import type { ProviderV2 } from "@opencode-ai/core/provider"
import { SessionRetry } from "@/session/retry"
import { computeMetrics as computeMetricsHelper, type TokenRates } from "@/kilocode/session/metrics"
@@ -137,6 +137,14 @@ export namespace KiloSessionProcessor {
/** Returned shape for downstream consumers that prefer the namespace. */
export type Metrics = TokenRates
export function generationID(meta: ProviderMetadata | undefined) {
const value = meta?.gateway?.generationId
if (typeof value !== "string") return
const id = value.trim()
if (!/^gen_[A-Za-z0-9_-]{1,200}$/.test(id)) return
return id
}
/**
* Effect-based offline handler for the retry schedule.
* Shows offline status, waits for network reconnection or user rejection.
@@ -869,6 +869,7 @@ export const layer = Layer.effect(
modelID: ctx.model.id,
selected: ctx.assistantMessage.modelID,
})
const generationID = KiloSessionProcessor.generationID(value.providerMetadata)
// kilocode_change end
// kilocode_change start - guard against finish-step without start-step:
// ctx.stepStart is 0 until `start-step` fires, which would feed a
@@ -922,6 +923,7 @@ export const layer = Layer.effect(
type: "step-finish",
time: { start: startDate, end: endDate, elapsed: elapsedMs }, // kilocode_change
...(model ? { model } : {}), // kilocode_change
...(generationID ? { generationID } : {}), // kilocode_change
...(metrics ? { metrics } : {}), // kilocode_change
tokens: usage.tokens,
cost: usage.cost,
@@ -0,0 +1,23 @@
import { describe, expect, test } from "bun:test"
import { KiloSessionProcessor } from "../../src/kilocode/session/processor"
describe("session generation id", () => {
test("extracts a bounded Gateway generation id", () => {
expect(
KiloSessionProcessor.generationID({
gateway: {
generationId: " gen_test-123 ",
routing: { finalProvider: "novita" },
marketCost: "0.1",
},
}),
).toBe("gen_test-123")
})
test("rejects arbitrary or oversized metadata values", () => {
expect(KiloSessionProcessor.generationID({ gateway: { generationId: "request-secret" } })).toBeUndefined()
expect(KiloSessionProcessor.generationID({ gateway: { generationId: `gen_${"a".repeat(201)}` } })).toBeUndefined()
expect(KiloSessionProcessor.generationID({ gateway: { generationId: 42 } })).toBeUndefined()
expect(KiloSessionProcessor.generationID({ openai: { responseId: "gen_response" } })).toBeUndefined()
})
})
@@ -577,7 +577,14 @@ describe("session processor empty tool-calls", () => {
index: 0,
reason: "stop",
usage: usage(),
providerMetadata: { kilocode: { routedModelID: "openai/gpt-5.5-20260423" } },
providerMetadata: {
kilocode: { routedModelID: "openai/gpt-5.5-20260423" },
gateway: {
generationId: "gen_test",
routing: { finalProvider: "openai" },
marketCost: "0.1",
},
},
}),
LLMEvent.finish({ reason: "stop", usage: usage() }),
)
@@ -632,6 +639,9 @@ describe("session processor empty tool-calls", () => {
providerID: selection.providerID,
modelID: ModelV2.ID.make("openai/gpt-5.5-20260423"),
})
expect(part?.generationID).toBe("gen_test")
expect(part).not.toHaveProperty("providerMetadata")
expect(part).not.toHaveProperty("gateway")
}),
{ git: true },
),
+2 -2
View File
@@ -281,7 +281,7 @@ describe("session.llm.ai-sdk adapter", () => {
{
type: "step-finish",
index: 0,
reason: "unknown",
reason: "other", // kilocode_change
usage: {
inputTokens: 10,
outputTokens: 5,
@@ -294,7 +294,7 @@ describe("session.llm.ai-sdk adapter", () => {
},
{
type: "finish",
reason: "unknown",
reason: "other", // kilocode_change
usage: {
inputTokens: 11,
outputTokens: 6,