[codex] align antigravity special-model non-stream path with CPA (#444)
* align antigravity special-model non-stream path with cpa * fix antigravity tail aggregation review feedback * fix antigravity fallback aggregation review feedback
This commit is contained in:
@@ -1144,7 +1144,7 @@ describe('gemini native proxy routes', () => {
|
||||
expect(targetUrl).toBe('https://api.openai.com/v1/responses');
|
||||
});
|
||||
|
||||
it('routes Gemini native generateContent requests to antigravity upstreams through the internal content endpoint', async () => {
|
||||
it('routes Gemini native generateContent requests to antigravity special models through the internal stream endpoint and aggregates back to Gemini JSON', async () => {
|
||||
selectChannelMock.mockReturnValue({
|
||||
channel: { id: 43, routeId: 22 },
|
||||
site: { id: 79, name: 'antigravity-site', url: 'https://cloudcode-pa.googleapis.com', platform: 'antigravity' },
|
||||
@@ -1163,28 +1163,16 @@ describe('gemini native proxy routes', () => {
|
||||
tokenValue: 'antigravity-access-token',
|
||||
actualModel: 'gemini-3-pro-preview',
|
||||
});
|
||||
fetchMock.mockResolvedValue(new Response(JSON.stringify({
|
||||
response: {
|
||||
responseId: 'antigravity-response-1',
|
||||
modelVersion: 'gemini-3-pro-preview',
|
||||
candidates: [
|
||||
{
|
||||
content: {
|
||||
role: 'model',
|
||||
parts: [{ text: 'hello from antigravity' }],
|
||||
},
|
||||
finishReason: 'STOP',
|
||||
},
|
||||
],
|
||||
usageMetadata: {
|
||||
promptTokenCount: 8,
|
||||
candidatesTokenCount: 4,
|
||||
totalTokenCount: 12,
|
||||
},
|
||||
},
|
||||
}), {
|
||||
fetchMock.mockResolvedValue(new Response([
|
||||
'data: {"response":{"responseId":"antigravity-response-1","modelVersion":"gemini-3-pro-preview","candidates":[{"content":{"role":"model","parts":[{"text":"hello "}]},"index":0}]}}',
|
||||
'',
|
||||
'data: {"response":{"candidates":[{"content":{"role":"model","parts":[{"text":"from antigravity"}]},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":8,"candidatesTokenCount":4,"totalTokenCount":12}}}',
|
||||
'',
|
||||
'data: [DONE]',
|
||||
'',
|
||||
].join('\n'), {
|
||||
status: 200,
|
||||
headers: { 'content-type': 'application/json' },
|
||||
headers: { 'content-type': 'text/event-stream; charset=utf-8' },
|
||||
}));
|
||||
|
||||
const response = await app.inject({
|
||||
@@ -1205,11 +1193,11 @@ describe('gemini native proxy routes', () => {
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
const [targetUrl, requestInit] = fetchMock.mock.calls[0] as [string, RequestInit];
|
||||
expect(targetUrl).toBe('https://daily-cloudcode-pa.googleapis.com/v1internal:generateContent');
|
||||
expect(targetUrl).toBe('https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse');
|
||||
expect(requestInit.headers).toMatchObject({
|
||||
Authorization: 'Bearer antigravity-access-token',
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
Accept: 'text/event-stream',
|
||||
'User-Agent': 'antigravity/1.19.6 darwin/arm64',
|
||||
});
|
||||
const upstreamBody = JSON.parse(String(requestInit.body));
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('dispatchRuntimeRequest', () => {
|
||||
fetchMock.mockReset();
|
||||
});
|
||||
|
||||
it('routes antigravity runtime requests through daily then sandbox base urls and rewrites the payload fingerprint', async () => {
|
||||
it('routes standard antigravity runtime requests through daily then sandbox base urls and rewrites the payload fingerprint', async () => {
|
||||
const { dispatchRuntimeRequest } = await import('./runtimeExecutor.js');
|
||||
const request: BuiltEndpointRequest = {
|
||||
endpoint: 'chat',
|
||||
@@ -29,7 +29,7 @@ describe('dispatchRuntimeRequest', () => {
|
||||
},
|
||||
body: {
|
||||
project: 'project-demo',
|
||||
model: 'gemini-3-pro-preview',
|
||||
model: 'gemini-2.5-pro',
|
||||
request: {
|
||||
contents: [
|
||||
{
|
||||
@@ -41,7 +41,7 @@ describe('dispatchRuntimeRequest', () => {
|
||||
},
|
||||
runtime: {
|
||||
executor: 'antigravity',
|
||||
modelName: 'gemini-3-pro-preview',
|
||||
modelName: 'gemini-2.5-pro',
|
||||
stream: false,
|
||||
},
|
||||
};
|
||||
@@ -86,7 +86,7 @@ describe('dispatchRuntimeRequest', () => {
|
||||
const upstreamBody = JSON.parse(String(firstInit.body));
|
||||
expect(upstreamBody).toMatchObject({
|
||||
project: 'project-demo',
|
||||
model: 'gemini-3-pro-preview',
|
||||
model: 'gemini-2.5-pro',
|
||||
userAgent: 'antigravity',
|
||||
requestType: 'agent',
|
||||
request: {
|
||||
@@ -102,6 +102,169 @@ describe('dispatchRuntimeRequest', () => {
|
||||
expect(upstreamBody.requestId).toMatch(/^agent-[0-9a-f-]{36}$/i);
|
||||
});
|
||||
|
||||
it('routes antigravity gemini-3-pro non-stream requests through the stream endpoint and aggregates SSE back to JSON', async () => {
|
||||
const { dispatchRuntimeRequest } = await import('./runtimeExecutor.js');
|
||||
const request: BuiltEndpointRequest = {
|
||||
endpoint: 'chat',
|
||||
path: '/v1internal:streamGenerateContent?alt=sse',
|
||||
headers: {
|
||||
Authorization: 'Bearer antigravity-token',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
project: 'project-demo',
|
||||
model: 'gemini-3-pro-low',
|
||||
request: {
|
||||
contents: [
|
||||
{
|
||||
role: 'user',
|
||||
parts: [{ text: 'hello runtime executor' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
runtime: {
|
||||
executor: 'antigravity',
|
||||
modelName: 'gemini-3-pro-low',
|
||||
stream: false,
|
||||
action: 'streamGenerateContent',
|
||||
},
|
||||
};
|
||||
|
||||
fetchMock.mockResolvedValueOnce(new Response([
|
||||
'data: {"response":{"responseId":"antigravity-stream-1","modelVersion":"gemini-3-pro-low","candidates":[{"content":{"role":"model","parts":[{"text":"hello "}]},"index":0}]}}',
|
||||
'',
|
||||
'data: {"response":{"candidates":[{"content":{"role":"model","parts":[{"text":"from antigravity"}]},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":5,"candidatesTokenCount":4,"totalTokenCount":9}}}',
|
||||
'',
|
||||
'data: [DONE]',
|
||||
'',
|
||||
].join('\n'), {
|
||||
status: 200,
|
||||
headers: { 'content-type': 'text/event-stream; charset=utf-8' },
|
||||
}) as unknown as Awaited<ReturnType<typeof fetch>>);
|
||||
|
||||
const response = await dispatchRuntimeRequest({
|
||||
siteUrl: 'https://cloudcode-pa.googleapis.com',
|
||||
request,
|
||||
buildInit: (_url, nextRequest) => ({
|
||||
method: 'POST',
|
||||
headers: nextRequest.headers,
|
||||
body: JSON.stringify(nextRequest.body),
|
||||
}),
|
||||
});
|
||||
|
||||
expect(response.ok).toBe(true);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMock.mock.calls[0]?.[0]).toBe('https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse');
|
||||
|
||||
const requestInit = fetchMock.mock.calls[0]?.[1] as RequestInit;
|
||||
expect(requestInit.headers).toMatchObject({
|
||||
Authorization: 'Bearer antigravity-token',
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'text/event-stream',
|
||||
'User-Agent': 'antigravity/1.19.6 darwin/arm64',
|
||||
});
|
||||
|
||||
const upstreamBody = JSON.parse(String(requestInit.body));
|
||||
expect(upstreamBody).toMatchObject({
|
||||
project: 'project-demo',
|
||||
model: 'gemini-3-pro-low',
|
||||
userAgent: 'antigravity',
|
||||
requestType: 'agent',
|
||||
});
|
||||
|
||||
expect(response.headers.get('content-type')).toContain('application/json');
|
||||
await expect(response.json()).resolves.toEqual({
|
||||
responseId: 'antigravity-stream-1',
|
||||
modelVersion: 'gemini-3-pro-low',
|
||||
candidates: [
|
||||
{
|
||||
index: 0,
|
||||
content: {
|
||||
role: 'model',
|
||||
parts: [{ text: 'hello from antigravity' }],
|
||||
},
|
||||
finishReason: 'STOP',
|
||||
},
|
||||
],
|
||||
usageMetadata: {
|
||||
promptTokenCount: 5,
|
||||
candidatesTokenCount: 4,
|
||||
totalTokenCount: 9,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('aggregates an unterminated trailing SSE event for antigravity non-stream stream-endpoint requests', async () => {
|
||||
const { dispatchRuntimeRequest } = await import('./runtimeExecutor.js');
|
||||
const request: BuiltEndpointRequest = {
|
||||
endpoint: 'chat',
|
||||
path: '/v1internal:streamGenerateContent?alt=sse',
|
||||
headers: {
|
||||
Authorization: 'Bearer antigravity-token',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
project: 'project-demo',
|
||||
model: 'gemini-3-pro-low',
|
||||
request: {
|
||||
contents: [
|
||||
{
|
||||
role: 'user',
|
||||
parts: [{ text: 'hello runtime executor' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
runtime: {
|
||||
executor: 'antigravity',
|
||||
modelName: 'gemini-3-pro-low',
|
||||
stream: false,
|
||||
action: 'streamGenerateContent',
|
||||
},
|
||||
};
|
||||
|
||||
fetchMock.mockResolvedValueOnce(new Response([
|
||||
'data: {"response":{"responseId":"antigravity-stream-tail","modelVersion":"gemini-3-pro-low","candidates":[{"content":{"role":"model","parts":[{"text":"hello "}]},"index":0}]}}',
|
||||
'',
|
||||
'data: {"response":{"candidates":[{"content":{"role":"model","parts":[{"text":"tail"}]},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":7,"candidatesTokenCount":5,"totalTokenCount":12}}}',
|
||||
].join('\n'), {
|
||||
status: 200,
|
||||
headers: { 'content-type': 'text/event-stream; charset=utf-8' },
|
||||
}) as unknown as Awaited<ReturnType<typeof fetch>>);
|
||||
|
||||
const response = await dispatchRuntimeRequest({
|
||||
siteUrl: 'https://cloudcode-pa.googleapis.com',
|
||||
request,
|
||||
buildInit: (_url, nextRequest) => ({
|
||||
method: 'POST',
|
||||
headers: nextRequest.headers,
|
||||
body: JSON.stringify(nextRequest.body),
|
||||
}),
|
||||
});
|
||||
|
||||
expect(response.ok).toBe(true);
|
||||
await expect(response.json()).resolves.toEqual({
|
||||
responseId: 'antigravity-stream-tail',
|
||||
modelVersion: 'gemini-3-pro-low',
|
||||
candidates: [
|
||||
{
|
||||
index: 0,
|
||||
content: {
|
||||
role: 'model',
|
||||
parts: [{ text: 'hello tail' }],
|
||||
},
|
||||
finishReason: 'STOP',
|
||||
},
|
||||
],
|
||||
usageMetadata: {
|
||||
promptTokenCount: 7,
|
||||
candidatesTokenCount: 5,
|
||||
totalTokenCount: 12,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps gemini-cli countTokens payload lean while forcing a model-aware user agent', async () => {
|
||||
const { dispatchRuntimeRequest } = await import('./runtimeExecutor.js');
|
||||
const request: BuiltEndpointRequest = {
|
||||
@@ -181,7 +344,7 @@ describe('dispatchRuntimeRequest', () => {
|
||||
},
|
||||
body: {
|
||||
project: 'project-demo',
|
||||
model: 'gemini-3-pro-preview',
|
||||
model: 'gemini-2.5-pro',
|
||||
request: {
|
||||
contents: [
|
||||
{
|
||||
@@ -193,7 +356,7 @@ describe('dispatchRuntimeRequest', () => {
|
||||
},
|
||||
runtime: {
|
||||
executor: 'antigravity',
|
||||
modelName: 'gemini-3-pro-preview',
|
||||
modelName: 'gemini-2.5-pro',
|
||||
stream: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1211,11 +1211,18 @@ describe('buildUpstreamEndpointRequest', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(request.path).toBe('/v1internal:generateContent');
|
||||
expect(request.path).toBe('/v1internal:streamGenerateContent?alt=sse');
|
||||
expect(request.headers.Authorization).toBe('Bearer oauth-access-token');
|
||||
expect(request.headers.Accept).toBe('text/event-stream');
|
||||
expect(request.headers['User-Agent']).toBe('antigravity/1.19.6 darwin/arm64');
|
||||
expect(request.headers['X-Goog-Api-Client']).toBeUndefined();
|
||||
expect(request.headers['Client-Metadata']).toBeUndefined();
|
||||
expect(request.runtime).toMatchObject({
|
||||
executor: 'antigravity',
|
||||
modelName: 'gemini-3-pro-preview',
|
||||
stream: false,
|
||||
action: 'streamGenerateContent',
|
||||
});
|
||||
expect(request.body).toEqual({
|
||||
project: 'project-demo',
|
||||
model: 'gemini-3-pro-preview',
|
||||
|
||||
Reference in New Issue
Block a user