fix(coding): recover provider context failures

This commit is contained in:
brother7 committed 2026-08-26 14:42:01 +08:00
1 parent 9f05e2d7e1
commit a09826676e
8 files changed
+349 -9

No files matched your search

+37
View File
@@ -4,6 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { handleAiProxyRoutes } from '@electron/api/routes/ai-proxy';
import {
clearWorksSquareAIGatewayCredential,
getWorksSquareAIGatewaySnapshot,
seedWorksSquareAIGatewayCredential,
} from '@electron/services/works-square-ai-gateway';
import {
@@ -339,6 +340,42 @@ describe('ai proxy routes', () => {
expect(response.body()).toContain('works_square_gateway_authorize_failed');
});
it('fails fast and expires the gateway credential when Works cannot resolve one-api user context', async () => {
seedWorksSquareAIGatewayCredential({
accessToken: 'ws-ai-token',
expiresIn: 3600,
oneApiBaseUrl: 'https://one-api.example.com/v1',
});
const body = JSON.stringify({
error: {
message: 'works square AI gateway did not return one-api user context',
type: 'one_api_error',
},
});
const fetchMock = vi.fn().mockResolvedValueOnce(
new Response(body, {
status: 502,
headers: { 'content-type': 'application/json' },
}),
);
vi.stubGlobal('fetch', fetchMock);
const response = createResponse();
await handleAiProxyRoutes(
createRequest('POST', { model: 'qwen3.7-max', messages: [{ role: 'user', content: 'secret prompt' }] }),
response.res,
new URL('http://127.0.0.1:13210/api/ai-proxy/v1/chat/completions'),
{} as never,
);
expect(fetchMock).toHaveBeenCalledOnce();
expect(response.statusCode).toBe(401);
expect(response.body()).toBe(body);
expect(getWorksSquareAIGatewaySnapshot()).toMatchObject({ expiresAt: 0 });
expect(JSON.stringify(loggerWarnMock.mock.calls)).not.toContain('secret prompt');
expect(JSON.stringify(loggerWarnMock.mock.calls)).not.toContain('ws-ai-token');
});
it('maps explicit upstream group saturation to a non-retryable response status', async () => {
seedWorksSquareAIGatewayCredential({
accessToken: 'ws-ai-token',