feat: recognize claude-code llm backend

This commit is contained in:
Andrey Avtomonov 2026-05-15 16:01:33 +02:00
parent cb16f8a61c
commit 4af3a6f20b
8 changed files with 199 additions and 12 deletions

View file

@ -61,4 +61,17 @@ describe('KTX LLM health check', () => {
message: '401 invalid x-api-key [redacted]',
});
});
it('reports claude-code as unsupported by the AI SDK health check', async () => {
const result = await runKtxLlmHealthCheck({
backend: 'claude-code',
modelSlots: { default: 'sonnet' },
promptCaching: { enabled: false },
});
expect(result).toEqual({
ok: false,
message: expect.stringContaining('claude-code is not an AI SDK LanguageModel backend'),
});
});
});

View file

@ -302,4 +302,14 @@ describe('createKtxLlmProvider', () => {
expect(provider.promptCachingConfig().enabled).toBe(false);
expect(provider.cacheMarker('1h', 'claude-sonnet-4-6')).toBeUndefined();
});
it('throws instead of falling through when an unsupported LLM backend is passed to the AI SDK provider factory', () => {
expect(() =>
createKtxLlmProvider({
backend: 'claude-code',
modelSlots: { default: 'sonnet' },
promptCaching: { enabled: false },
}),
).toThrow('claude-code is not an AI SDK LanguageModel backend');
});
});

View file

@ -175,14 +175,18 @@ class DefaultKtxLlmProvider implements KtxLlmProvider {
return (modelId) => vertex(modelId);
}
const gateway = (deps.createGateway ?? createGateway)({
...(config.gateway?.apiKey ? { apiKey: config.gateway.apiKey } : {}),
...(config.gateway?.baseURL ? { baseURL: config.gateway.baseURL } : {}),
headers: {
'anthropic-beta': ANTHROPIC_BETA_HEADER,
},
});
return (modelId) => gateway(modelId);
if (config.backend === 'gateway') {
const gateway = (deps.createGateway ?? createGateway)({
...(config.gateway?.apiKey ? { apiKey: config.gateway.apiKey } : {}),
...(config.gateway?.baseURL ? { baseURL: config.gateway.baseURL } : {}),
headers: {
'anthropic-beta': ANTHROPIC_BETA_HEADER,
},
});
return (modelId) => gateway(modelId);
}
throw new Error(`${config.backend} is not an AI SDK LanguageModel backend; use KtxLlmRuntimePort`);
}
}

View file

@ -3,7 +3,7 @@ import type { LanguageModel, TelemetrySettings, ToolCallRepairFunction, ToolSet
export const KTX_MODEL_ROLES = ['default', 'triage', 'candidateExtraction', 'curator', 'reconcile', 'repair'] as const;
export type KtxModelRole = (typeof KTX_MODEL_ROLES)[number];
export type KtxLlmBackend = 'anthropic' | 'vertex' | 'gateway';
export type KtxLlmBackend = 'anthropic' | 'vertex' | 'gateway' | 'claude-code';
export type KtxPromptCacheTtl = '5m' | '1h';
export type KtxJsonValue =