diff --git a/enterprise/app/services/captain/codex/translator.rb b/enterprise/app/services/captain/codex/translator.rb index 8a703322a..035759491 100644 --- a/enterprise/app/services/captain/codex/translator.rb +++ b/enterprise/app/services/captain/codex/translator.rb @@ -15,10 +15,12 @@ class Captain::Codex::Translator body = { model: chat_body['model'] || chat_body[:model], input: input, + # Codex exige o campo instructions sempre. Se não vier system message, + # usamos uma string com um espaço pra satisfazer o endpoint sem influenciar o comportamento. + instructions: instructions.presence || ' ', store: false, stream: true # Codex exige streaming sempre — o Client agrega. } - body[:instructions] = instructions if instructions body[:max_output_tokens] = chat_body['max_tokens'] if chat_body['max_tokens'] tools = chat_body['tools'] || chat_body[:tools] diff --git a/spec/enterprise/services/captain/codex/translator_spec.rb b/spec/enterprise/services/captain/codex/translator_spec.rb index 22e448ae7..7fcd8248c 100644 --- a/spec/enterprise/services/captain/codex/translator_spec.rb +++ b/spec/enterprise/services/captain/codex/translator_spec.rb @@ -130,6 +130,20 @@ RSpec.describe Captain::Codex::Translator do expect(result.keys).not_to include(:temperature, :top_p, :frequency_penalty) end + + it 'always includes instructions (empty placeholder when no system message)' do + chat = { + 'model' => 'gpt-5.4', + 'messages' => [{ 'role' => 'user', 'content' => 'Oi' }] + } + + result = described_class.chat_to_responses(chat) + + # Codex exige o campo instructions mesmo sem system message. + expect(result).to have_key(:instructions) + expect(result[:instructions]).not_to be_nil + expect(result[:instructions]).not_to eq('') + end end describe '.responses_to_chat' do