DefaultUpstreamErrorTranslator.translate at lib/src/main/kotlin/dev/arcp/runtime/UpstreamErrorTranslator.kt:13 lowercases the message and matches "budget" in message && ("exhaust" in message || "exceed" in message). Provider error strings vary wildly and routinely contain unrelated mentions of the words "budget" or "exceed" ("rate limit exceeded", "context budget reached", localized translations, etc.), so this either fires false positives or misses the real signal. When it does fire, it hardcodes currency = "unknown" and discards the original cause, so the caller cannot tell the actual upstream currency or root error apart.
Fix prompt: Replace the substring heuristic with a small extension hook — for example, accept a Map<Regex, (Throwable) -> ARCPException> at construction so deployments configure their own provider mappings, and ship the SDK with an empty default. Where a default is needed, scope it narrowly: match only known upstream exception types (e.g. is com.openai.errors.RateLimitException) instead of the message text. Always pass the original throwable as the cause of the produced ARCPException. Add tests covering: a translator with no rules returns null, a rule that matches returns the right code with the cause preserved, and a non-matching exception returns null.
DefaultUpstreamErrorTranslator.translateatlib/src/main/kotlin/dev/arcp/runtime/UpstreamErrorTranslator.kt:13lowercases the message and matches"budget" in message && ("exhaust" in message || "exceed" in message). Provider error strings vary wildly and routinely contain unrelated mentions of the words "budget" or "exceed" ("rate limit exceeded", "context budget reached", localized translations, etc.), so this either fires false positives or misses the real signal. When it does fire, it hardcodescurrency = "unknown"and discards the original cause, so the caller cannot tell the actual upstream currency or root error apart.Fix prompt: Replace the substring heuristic with a small extension hook — for example, accept a
Map<Regex, (Throwable) -> ARCPException>at construction so deployments configure their own provider mappings, and ship the SDK with an empty default. Where a default is needed, scope it narrowly: match only known upstream exception types (e.g.is com.openai.errors.RateLimitException) instead of the message text. Always pass the original throwable as thecauseof the producedARCPException. Add tests covering: a translator with no rules returnsnull, a rule that matches returns the right code with the cause preserved, and a non-matching exception returnsnull.