* feat(api): classify openai-compatible provider failures * Update src/services/api/providerConfig.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/services/api/errors.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat(api): harden openai-compatible diagnostics and env fallback * Update src/services/api/openaiShim.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/services/api/openaiShim.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/services/api/errors.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/services/api/errors.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix openaiShim duplicate requests and diagnostics * remove unused url from http failure classifier * dedupe env diagnostic warnings * Remove hardcoded URLs from OpenAI error tests Removed hardcoded URLs from network failure classification tests. * Update providerConfig.envDiagnostics.test.ts * fix(openai-shim): return successful responses and restore localhost classifier tests * Update src/services/api/openaiShim.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/services/api/openaiShim.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/services/api/openaiShim.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import { APIError } from '@anthropic-ai/sdk'
|
|
import { expect, test } from 'bun:test'
|
|
|
|
import { getAssistantMessageFromError } from './errors.js'
|
|
|
|
function getFirstText(message: ReturnType<typeof getAssistantMessageFromError>): string {
|
|
const first = message.message.content[0]
|
|
if (!first || typeof first !== 'object' || !('text' in first)) {
|
|
return ''
|
|
}
|
|
return typeof first.text === 'string' ? first.text : ''
|
|
}
|
|
|
|
test('maps endpoint_not_found category markers to actionable setup guidance', () => {
|
|
const error = APIError.generate(
|
|
404,
|
|
undefined,
|
|
'OpenAI API error 404: Not Found [openai_category=endpoint_not_found] Hint: Confirm OPENAI_BASE_URL includes /v1.',
|
|
new Headers(),
|
|
)
|
|
|
|
const message = getAssistantMessageFromError(error, 'qwen2.5-coder:7b')
|
|
const text = getFirstText(message)
|
|
|
|
expect(message.isApiErrorMessage).toBe(true)
|
|
expect(text).toContain('Provider endpoint was not found')
|
|
expect(text).toContain('OPENAI_BASE_URL')
|
|
expect(text).toContain('/v1')
|
|
})
|
|
|
|
test('maps tool_call_incompatible category markers to model/tool guidance', () => {
|
|
const error = APIError.generate(
|
|
400,
|
|
undefined,
|
|
'OpenAI API error 400: tool_calls are not supported [openai_category=tool_call_incompatible]',
|
|
new Headers(),
|
|
)
|
|
|
|
const message = getAssistantMessageFromError(error, 'qwen2.5-coder:7b')
|
|
const text = getFirstText(message)
|
|
|
|
expect(text).toContain('rejected tool-calling payloads')
|
|
expect(text).toContain('/model')
|
|
})
|