fix: gracefully handle Ollama models without tool support

Check model capabilities via /api/show before sending tools.
Models without 'tools' capability get requests without tools
(they can still answer, just without tool use). Result is cached
per client instance. Defense-in-depth: 'does not support' added
to retry nonRetryablePatterns to avoid wasting retries on
permanent errors.
This commit is contained in:
William Valentin
2026-02-07 17:44:47 -08:00
parent a0f5584220
commit 6ed8a4a8bf
4 changed files with 153 additions and 3 deletions
+14
View File
@@ -38,6 +38,11 @@ describe('isRetryable', () => {
expect(isRetryable(error, DEFAULT_RETRY_CONFIG.nonRetryablePatterns)).toBe(false);
});
it('returns false for "does not support" errors', () => {
const error = new Error('registry.ollama.ai/library/qwen2.5:latest does not support tools');
expect(isRetryable(error, DEFAULT_RETRY_CONFIG.nonRetryablePatterns)).toBe(false);
});
it('is case-insensitive when matching patterns', () => {
const error = new Error('AUTHENTICATION error');
expect(isRetryable(error, DEFAULT_RETRY_CONFIG.nonRetryablePatterns)).toBe(false);
@@ -102,6 +107,15 @@ describe('withRetry', () => {
expect(fn).toHaveBeenCalledTimes(1);
});
it('does not retry "does not support tools" errors', async () => {
const fn = vi.fn().mockRejectedValue(
new Error('registry.ollama.ai/library/qwen2.5:latest does not support tools'),
);
await expect(withRetry(fn, fastConfig)).rejects.toThrow('does not support tools');
expect(fn).toHaveBeenCalledTimes(1);
});
it('converts non-Error throws to Error objects', async () => {
const fn = vi.fn().mockRejectedValue('string error');