mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-01 05:31:18 +00:00
fix(ai): classify failed Google Interactions by reported errors (#58771)
This commit is contained in:
parent
252ed4a2d8
commit
6ac6549a0a
2 changed files with 40 additions and 3 deletions
|
|
@ -155,6 +155,9 @@ const Interaction = Schema.StructWithRest(
|
|||
id: Schema.optional(Schema.String),
|
||||
status: Schema.String,
|
||||
usage: Schema.optional(RawUsage),
|
||||
errors: Schema.optional(
|
||||
Schema.Array(Schema.Struct({ code: Schema.optional(Schema.String), message: Schema.optional(Schema.String) })),
|
||||
),
|
||||
}),
|
||||
[Schema.Record(Schema.String, Schema.Unknown)],
|
||||
)
|
||||
|
|
@ -521,14 +524,17 @@ const step = Effect.fnUntraced(function* (state: ParserState, event: Event) {
|
|||
})
|
||||
case "interaction.completed": {
|
||||
const interaction = event.interaction
|
||||
if (interaction.status === "failed" || interaction.status === "cancelled")
|
||||
if (interaction.status === "failed" || interaction.status === "cancelled") {
|
||||
const messages = (interaction.errors ?? []).flatMap((error) => (error.message?.trim() ? [error.message] : []))
|
||||
return yield* new AIError({
|
||||
reason: classifyProviderFailure({
|
||||
message: `Google Interactions ${interaction.status}`,
|
||||
data: interaction,
|
||||
message: messages.length > 0 ? messages.join("\n") : `Google Interactions ${interaction.status}`,
|
||||
// The first coded error decides the classification; every message stays visible.
|
||||
data: interaction.errors?.find((error) => error.code) ?? interaction,
|
||||
rawBody: encodeJson(event),
|
||||
}),
|
||||
})
|
||||
}
|
||||
if (!["completed", "requires_action", "incomplete"].includes(interaction.status))
|
||||
return yield* ProviderShared.eventError(
|
||||
ADAPTER,
|
||||
|
|
|
|||
|
|
@ -187,6 +187,37 @@ describe("Google Vertex Interactions", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("classifies failed interactions by their reported errors", () =>
|
||||
Effect.gen(function* () {
|
||||
const model = GoogleVertexInteractions.configure({ apiKey: "vertex-key" }).model("gemini-3.8-flash")
|
||||
const cases = [
|
||||
{
|
||||
errors: [{ code: "permission_denied", message: "Access denied" }],
|
||||
tag: "Authentication",
|
||||
message: "Access denied",
|
||||
},
|
||||
{
|
||||
errors: [{ message: "Out of credits" }, { code: "insufficient_quota", message: "Add billing" }],
|
||||
tag: "QuotaExceeded",
|
||||
message: "Out of credits\nAdd billing",
|
||||
},
|
||||
{ errors: [], tag: "UnknownProvider", message: "Google Interactions failed" },
|
||||
]
|
||||
for (const item of cases) {
|
||||
const event = { event_type: "interaction.completed", interaction: { status: "failed", errors: item.errors } }
|
||||
const error = yield* LLMClient.generate(LLM.request({ model, prompt: "Hi" })).pipe(
|
||||
Effect.provide(fixedResponse(sseEvents(event))),
|
||||
Effect.flip,
|
||||
)
|
||||
expect([error.reason._tag, error.reason.message, error.reason.body]).toEqual([
|
||||
item.tag,
|
||||
item.message,
|
||||
JSON.stringify(event),
|
||||
])
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("round-trips tool signatures under Vertex metadata without enabling storage", () =>
|
||||
Effect.gen(function* () {
|
||||
const model = GoogleVertexInteractions.configure({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue