Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@missionsquad/rosetta-ai",
"version": "1.12.0",
"version": "1.12.1",
"description": "Unified TypeScript SDK for interacting with multiple AI providers (Anthropic, Google, Groq, OpenAI).",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
28 changes: 19 additions & 9 deletions src/core/mapping/gpt5.support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Gpt5Support {
fixedReasoningEffort?: ReasoningEffort
supportsVerbosity: boolean
supportsSampling: 'never' | 'always' | 'only_with_reasoning_none'
supportsFunctionToolsWithReasoning?: boolean
}

// Chat Completions-supported GPT-5 models verified for this implementation.
Expand All @@ -16,62 +17,71 @@ const GPT5_CHAT_COMPLETIONS_SUPPORT: Record<string, Gpt5Support> = {
allowedReasoningEfforts: ['minimal', 'low', 'medium', 'high'],
defaultReasoningEffort: 'medium',
supportsVerbosity: true,
supportsSampling: 'never'
supportsSampling: 'never',
supportsFunctionToolsWithReasoning: true
},
'gpt-5-mini': {
chatCompletionsSupported: true,
allowedReasoningEfforts: ['minimal', 'low', 'medium', 'high'],
defaultReasoningEffort: 'medium',
supportsVerbosity: true,
supportsSampling: 'never'
supportsSampling: 'never',
supportsFunctionToolsWithReasoning: true
},
'gpt-5-nano': {
chatCompletionsSupported: true,
allowedReasoningEfforts: ['minimal', 'low', 'medium', 'high'],
defaultReasoningEffort: 'medium',
supportsVerbosity: true,
supportsSampling: 'never'
supportsSampling: 'never',
supportsFunctionToolsWithReasoning: true
},
'gpt-5.1': {
chatCompletionsSupported: true,
allowedReasoningEfforts: ['none', 'low', 'medium', 'high'],
defaultReasoningEffort: 'none',
supportsVerbosity: true,
supportsSampling: 'never'
supportsSampling: 'never',
supportsFunctionToolsWithReasoning: true
},
'gpt-5.2': {
chatCompletionsSupported: true,
allowedReasoningEfforts: ['none', 'low', 'medium', 'high', 'xhigh'],
defaultReasoningEffort: 'none',
supportsVerbosity: true,
supportsSampling: 'only_with_reasoning_none'
supportsSampling: 'only_with_reasoning_none',
supportsFunctionToolsWithReasoning: true
},
'gpt-5.4': {
chatCompletionsSupported: true,
allowedReasoningEfforts: ['none', 'low', 'medium', 'high', 'xhigh'],
defaultReasoningEffort: 'none',
supportsVerbosity: true,
supportsSampling: 'never'
supportsSampling: 'never',
supportsFunctionToolsWithReasoning: false
},
'gpt-5-chat-latest': {
chatCompletionsSupported: true,
allowedReasoningEfforts: [],
supportsVerbosity: true,
supportsSampling: 'always'
supportsSampling: 'always',
supportsFunctionToolsWithReasoning: true
},
'gpt-5.1-chat-latest': {
chatCompletionsSupported: true,
allowedReasoningEfforts: ['medium'],
fixedReasoningEffort: 'medium',
supportsVerbosity: true,
supportsSampling: 'never'
supportsSampling: 'never',
supportsFunctionToolsWithReasoning: true
},
'gpt-5.2-chat-latest': {
chatCompletionsSupported: true,
allowedReasoningEfforts: ['medium'],
fixedReasoningEffort: 'medium',
supportsVerbosity: true,
supportsSampling: 'never'
supportsSampling: 'never',
supportsFunctionToolsWithReasoning: true
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/core/mapping/openai.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ export class OpenAIMapper implements IProviderMapper {
const isThinking = isThinkingModel(params.model!)
const isGPT5 = isGPT5Model(params.model!)
const hasEffectiveLimit = baseMappedParams.maxTokens !== undefined
const hasFunctionTools = Array.isArray(tools) && tools.length > 0

if (!isThinking) {
// Non-thinking OpenAI models must use max_completion_tokens only.
Expand Down Expand Up @@ -235,7 +236,11 @@ export class OpenAIMapper implements IProviderMapper {
}
}

if (effectiveEffort !== undefined) {
const shouldOmitReasoningForFunctionTools =
hasFunctionTools &&
support.supportsFunctionToolsWithReasoning === false

if (effectiveEffort !== undefined && !shouldOmitReasoningForFunctionTools) {
basePayload.reasoning_effort = effectiveEffort
} else {
delete basePayload.reasoning_effort
Expand Down
22 changes: 22 additions & 0 deletions tests/unit/core/mapping/openai.mapper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,28 @@ describe('OpenAI Mapper', () => {
expect(result.max_completion_tokens).toBe(321)
})

it('[Medium] should omit reasoning_effort for gpt-5.4 when function tools are present', () => {
const params: GenerateParams = {
...baseParams,
model: 'gpt-5.4',
messages: [{ role: 'user', content: 'Generate.' }],
reasoningEffort: 'high',
tools: [
{
type: 'function',
function: {
name: 'myFunc',
parameters: { type: 'object', properties: {} },
zodSchema: z.object({})
}
}
]
}
const result = mapper.mapToProviderParams(params) as any
expect(result.reasoning_effort).toBeUndefined()
expect(result.tools).toHaveLength(1)
})

it('[Medium] should map toolChoice required and none', () => {
const paramsRequired: GenerateParams = { ...baseParams, messages: [], toolChoice: 'required' }
const paramsNone: GenerateParams = { ...baseParams, messages: [], toolChoice: 'none' }
Expand Down
Loading