Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
423ae34
feat: add request queue implementation
leocavalcante Dec 30, 2025
7e994e0
feat: integrate request queue with rate limiting
leocavalcante Dec 30, 2025
4f52b53
chore: update bun lockfile
leocavalcante Dec 30, 2025
c7d9af4
chore: add .claude/ to gitignore
leocavalcante Dec 30, 2025
de62cfc
feat: add rate limit header parser
leocavalcante Jan 8, 2026
05d5c16
feat: add headers callback to createChatCompletions
leocavalcante Jan 8, 2026
fb14a52
feat: implement adaptive rate limiting from response headers
leocavalcante Jan 8, 2026
bcdd23a
test: add comprehensive tests for rate limit parser
leocavalcante Jan 8, 2026
94ea329
docs: clarify rate limit headers are GitHub/Copilot style
leocavalcante Jan 8, 2026
19deaf4
fix: make rate limiting opt-in by removing default value
leocavalcante Jan 8, 2026
69e0302
refactor: remove adaptive rate limiting feature
leocavalcante Jan 8, 2026
30e8a06
feat: add automatic retry and resilient rate limit handling
leocavalcante Jan 8, 2026
f8062aa
feat: improve resilience and add rate limit headers
leocavalcante Jan 8, 2026
2886886
fix: prevent "Body already used" error in HTTPError handling
leocavalcante Jan 8, 2026
b1305c1
feat: implement bidirectional adaptive rate limiting
leocavalcante Jan 8, 2026
41e3f4a
fix: don't override default 1s rate limit at startup
leocavalcante Jan 8, 2026
5a47bff
feat: make adaptive rate limiting more conservative
leocavalcante Jan 8, 2026
2339859
feat: add adaptive decrease strategy and request caching
leocavalcante Jan 8, 2026
9344ed2
feat: implement tiered conservative buffer strategy for rate limits
leocavalcante Jan 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ node_modules/
# aider
.aider*

# claude
.claude/

# eslint cache
.eslintcache

Expand Down
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 39 additions & 2 deletions src/lib/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,57 @@ import type { ContentfulStatusCode } from "hono/utils/http-status"

import consola from "consola"

import { RateLimitError } from "./retry"

export class HTTPError extends Error {
response: Response
errorBody?: string

constructor(message: string, response: Response) {
constructor(message: string, response: Response, errorBody?: string) {
super(message)
this.response = response
this.errorBody = errorBody
}
}

export async function forwardError(c: Context, error: unknown) {
consola.error("Error occurred:", error)

// Handle rate limit errors with detailed retry information
if (error instanceof RateLimitError) {
const retryAfter = error.retryInfo.retryAfter
const message =
error.retryInfo.exceeded ?
`Rate limit exceeded: ${error.retryInfo.exceeded}. Retry after ${retryAfter} seconds.`
: `Rate limit exceeded. Retry after ${retryAfter} seconds.`

return c.json(
{
error: {
message,
type: "rate_limit_error",
retry_after: retryAfter,
exceeded: error.retryInfo.exceeded,
},
},
429,
{
"Retry-After": retryAfter.toString(),
},
)
}

if (error instanceof HTTPError) {
const errorText = await error.response.text()
// Use cached error body if available, otherwise try to read it
let errorText = error.errorBody
if (!errorText) {
try {
errorText = await error.response.text()
} catch {
errorText = "Failed to read error body"
}
}

let errorJson: unknown
try {
errorJson = JSON.parse(errorText)
Expand Down
Loading