feat: add astra to models (#3755)

This commit is contained in:
Daniel Salazar
2026-09-04 15:56:53 -07:00
committed by GitHub
parent 6ebbc6ae0c
commit 3355190a17
5 changed files with 100 additions and 6 deletions
@@ -154,7 +154,7 @@ describe('OpenAiChatProvider model catalog', () => {
expect(provider.getDefaultModel()).toBe('gpt-5-nano');
});
it('models() filters out responses_api_only entries', () => {
it('models() excludes Responses-only entries and includes dual-API entries', () => {
const { provider } = makeProvider();
const ids = provider.models().map((m) => m.id);
const responsesOnly = OPEN_AI_MODELS.filter(
@@ -165,6 +165,7 @@ describe('OpenAiChatProvider model catalog', () => {
}
// gpt-5-nano is a Chat-Completions model, must be present.
expect(ids).toContain('gpt-5-nano-2025-08-07');
expect(ids).toContain('gpt-6-astra');
});
it('list() flattens canonical ids and aliases', () => {
@@ -269,6 +270,26 @@ describe('OpenAiChatProvider.complete request shape', () => {
expect(args.temperature).toBe(0.4);
});
it('resolves the namespaced GPT-6 Astra alias', async () => {
const { provider } = makeProvider();
createMock.mockResolvedValueOnce(baseCompletion);
await withTestActor(() =>
provider.complete({
model: 'openai/gpt-6-astra',
messages: [{ role: 'user', content: 'hello' }],
}),
);
expect(createMock.mock.calls[0]![0].model).toBe('gpt-6-astra');
expect(recordSpy).toHaveBeenCalledWith(
expect.any(Object),
expect.anything(),
'openai:gpt-6-astra',
expect.any(Object),
);
});
it('forwards temperature 0 and max_tokens 0 instead of dropping them', async () => {
const { provider } = makeProvider();
createMock.mockResolvedValueOnce(baseCompletion);
@@ -161,12 +161,35 @@ describe('OpenAiResponsesChatProvider model catalog', () => {
expect(provider.getDefaultModel()).toBe('gpt-5-nano');
});
it('models() with default args exposes only responses_api_only entries', () => {
it('exposes GPT-6 Astra with its API metadata and pricing', () => {
const { provider } = makeProvider();
const astra = provider.models().find((m) => m.id === 'gpt-6-astra');
expect(astra).toMatchObject({
puterId: 'openai:openai/gpt-6-astra',
modalities: { input: ['text', 'image'], output: ['text'] },
knowledge: '2026-04-30',
release_date: '2026-09-04',
aliases: ['openai/gpt-6-astra'],
costs_currency: 'usd-cents',
costs: {
tokens: 1_000_000,
prompt_tokens: 1000,
cached_tokens: 100,
completion_tokens: 5000,
},
context: 1_050_000,
max_tokens: 128_000,
responses_api: true,
});
expect(astra).not.toHaveProperty('responses_api_only');
});
it('models() exposes Responses-only and dual-API entries', () => {
const { provider } = makeProvider();
const ids = provider.models().map((m: { id: string }) => m.id);
// Sanity: a known responses_api_only model is included.
expect(ids).toContain('o3-pro');
// And a known Chat-Completions-only model is excluded.
expect(ids).toContain('gpt-6-astra');
expect(ids).not.toContain('gpt-5-nano-2025-08-07');
});
@@ -180,11 +203,13 @@ describe('OpenAiResponsesChatProvider model catalog', () => {
expect(ids).toContain('gpt-5-nano-2025-08-07');
});
it('list() flattens canonical ids and aliases for responses-only models', () => {
it('list() flattens canonical ids and aliases for Responses models', () => {
const { provider } = makeProvider();
const ids = provider.list();
expect(ids).toContain('o3-pro');
expect(ids).toContain('openai/o3-pro');
expect(ids).toContain('gpt-6-astra');
expect(ids).toContain('openai/gpt-6-astra');
});
});
@@ -346,6 +371,28 @@ describe('OpenAiResponsesChatProvider model resolution', () => {
usage: { input_tokens: 1, output_tokens: 1 },
};
it('resolves the namespaced GPT-6 Astra alias', async () => {
const { provider } = makeProvider();
responsesCreateMock.mockResolvedValueOnce(baseResponse);
await withTestActor(() =>
provider.complete({
model: 'openai/gpt-6-astra',
messages: [{ role: 'user', content: 'hi' }],
}),
);
expect(responsesCreateMock.mock.calls[0]![0].model).toBe(
'gpt-6-astra',
);
expect(recordSpy).toHaveBeenCalledWith(
expect.any(Object),
expect.anything(),
'openai:gpt-6-astra',
expect.any(Object),
);
});
it('resolves an alias to its canonical id (across the entire model catalog)', async () => {
const { provider } = makeProvider();
responsesCreateMock.mockResolvedValueOnce(baseResponse);
@@ -74,7 +74,9 @@ export class OpenAiResponsesChatProvider implements IChatProvider {
if (extra_params?.no_restrictions) {
return OPEN_AI_MODELS;
}
return OPEN_AI_MODELS.filter((e) => e.responses_api_only === true);
return OPEN_AI_MODELS.filter(
(e) => e.responses_api_only === true || e.responses_api === true,
);
}
list() {
@@ -23,6 +23,28 @@ import type { IChatModel } from '../../types.js';
// Hardcoded from https://models.dev/api.json
export const OPEN_AI_MODELS: IChatModel[] = [
{
puterId: 'openai:openai/gpt-6-astra',
id: 'gpt-6-astra',
modalities: { input: ['text', 'image'], output: ['text'] },
open_weights: false,
tool_call: true,
knowledge: '2026-04-30',
release_date: '2026-09-04',
aliases: ['openai/gpt-6-astra'],
costs_currency: 'usd-cents',
input_cost_key: 'prompt_tokens',
output_cost_key: 'completion_tokens',
costs: {
tokens: 1_000_000,
prompt_tokens: 1000,
cached_tokens: 100,
completion_tokens: 5000,
},
context: 1_050_000,
max_tokens: 128_000,
responses_api: true,
},
{
puterId: 'openai:openai/gpt-5.6-sol',
id: 'gpt-5.6-sol',
+2
View File
@@ -50,6 +50,8 @@ export interface IChatModel<T extends ModelCost = ModelCost> extends Record<
modalities?: ModelModalities;
open_weights?: boolean;
tool_call?: boolean;
responses_api?: boolean;
responses_api_only?: boolean;
knowledge?: string;
release_date?: string;
}