diff --git a/lib/mindee/errors/mindee_http_error_v2.rb b/lib/mindee/errors/mindee_http_error_v2.rb index 7daaa8ee..2cde4df5 100644 --- a/lib/mindee/errors/mindee_http_error_v2.rb +++ b/lib/mindee/errors/mindee_http_error_v2.rb @@ -1,25 +1,44 @@ # frozen_string_literal: true require_relative 'mindee_error' +require_relative '../parsing/v2/error_item' module Mindee module Errors # API V2 HttpError class MindeeHTTPErrorV2 < MindeeError - # @return [Integer] + # @return [Integer] The HTTP status code returned by the server. attr_reader :status - # @return [String] + # @return [String] A human-readable explanation specific to the occurrence of the problem. attr_reader :detail + # @return [String] A short, human-readable summary of the problem. + attr_reader :title + # @return [String] A machine-readable code specific to the occurrence of the problem. + attr_reader :code + # @return [Array] A list of explicit error details. + attr_reader :errors # @param http_error [Hash, Parsing::V2::ErrorResponse] def initialize(http_error) if http_error.is_a?(Parsing::V2::ErrorResponse) http_error = { 'detail' => http_error.detail, - 'status' => http_error.status } + 'status' => http_error.status, + 'title' => http_error.title, + 'code' => http_error.code, + 'errors' => http_error.errors } end @status = http_error['status'] @detail = http_error['detail'] - super("HTTP error: #{@status} - #{@detail}") + @title = http_error['title'] + @code = http_error['code'] + @errors = if http_error.key?('errors') + http_error['errors'].map do |error| + Parsing::V2::ErrorItem.new(error) + end + else + [] + end + super("HTTP #{@status} - #{@title} :: #{@code} - #{@detail}") end end end diff --git a/lib/mindee/errors/mindee_http_unknown_error_v2.rb b/lib/mindee/errors/mindee_http_unknown_error_v2.rb new file mode 100644 index 00000000..5f2a9ebe --- /dev/null +++ b/lib/mindee/errors/mindee_http_unknown_error_v2.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require_relative 'mindee_error' + +module Mindee + module Errors + # Unknown HTTP error for the V2 API. + class MindeeHTTPUnknownErrorV2 < MindeeHTTPErrorV2 + def initialize(http_error) + super({ 'detail' => "Couldn't deserialize server error. Found: #{http_error}", + 'status' => -1, + 'title' => 'Unknown Error', + 'code' => '000-000', + 'errors' => nil }) + end + end + end +end diff --git a/lib/mindee/parsing/v2/error_item.rb b/lib/mindee/parsing/v2/error_item.rb new file mode 100644 index 00000000..bc81da6a --- /dev/null +++ b/lib/mindee/parsing/v2/error_item.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Mindee + module Parsing + module V2 + # Individual error item. + class ErrorItem + # @return [String, nil] A JSON Pointer to the location of the body property. + attr_reader :pointer + # @return [String, nil] Explicit information on the issue. + attr_reader :detail + + # @param server_response [Hash] Raw JSON parsed into a Hash. + def initialize(server_response) + @pointer = server_response['pointer'] + @detail = server_response['detail'] + end + end + end + end +end diff --git a/lib/mindee/parsing/v2/error_response.rb b/lib/mindee/parsing/v2/error_response.rb index 91c7d891..6745603e 100644 --- a/lib/mindee/parsing/v2/error_response.rb +++ b/lib/mindee/parsing/v2/error_response.rb @@ -5,21 +5,36 @@ module Parsing module V2 # Encapsulates information returned by the API when an error occurs. class ErrorResponse - # @return [Integer] HTTP status code. + # @return [Integer] The HTTP status code returned by the server. attr_reader :status - # @return [String] Error detail. + # @return [String] A human-readable explanation specific to the occurrence of the problem. attr_reader :detail + # @return [String] A short, human-readable summary of the problem. + attr_reader :title + # @return [String] A machine-readable code specific to the occurrence of the problem. + attr_reader :code + # @return [Array] A list of explicit error details. + attr_reader :errors # @param server_response [Hash] Raw JSON parsed into a Hash. def initialize(server_response) @status = server_response['status'] @detail = server_response['detail'] + @title = server_response['title'] + @code = server_response['code'] + @errors = if server_response.key?('errors') + server_response['errors'].map do |error| + ErrorItem.new(error) + end + else + [] + end end # String representation. # @return [String] def to_s - "Error\n=====\n:Status: #{@status}\n:Detail: #{@detail}" + "HTTP #{@status} - #{@title} :: #{@code} - #{@detail}" end # Hash representation diff --git a/lib/mindee/parsing/v2/inference_result.rb b/lib/mindee/parsing/v2/inference_result.rb index f2c3c78d..8ee1bd1c 100644 --- a/lib/mindee/parsing/v2/inference_result.rb +++ b/lib/mindee/parsing/v2/inference_result.rb @@ -2,6 +2,7 @@ require_relative 'field/inference_fields' require_relative 'raw_text' +require_relative 'rag_metadata' module Mindee module Parsing @@ -12,6 +13,8 @@ class InferenceResult attr_reader :fields # @return [Mindee::Parsing::V2::RawText, nil] Optional extra data. attr_reader :raw_text + # @return [Mindee::Parsing::V2::RAGMetadata, nil] Optional RAG metadata. + attr_reader :rag # @param server_response [Hash] Hash version of the JSON returned by the API. def initialize(server_response) @@ -20,6 +23,7 @@ def initialize(server_response) @fields = Field::InferenceFields.new(server_response['fields']) @raw_text = server_response['raw_text'] ? RawText.new(server_response['raw_text']) : nil + @rag = (V2::RAGMetadata.new(server_response['rag']) if server_response.key?('rag') && server_response['rag']) end # String representation. diff --git a/lib/mindee/parsing/v2/rag_metadata.rb b/lib/mindee/parsing/v2/rag_metadata.rb new file mode 100644 index 00000000..5bebc603 --- /dev/null +++ b/lib/mindee/parsing/v2/rag_metadata.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Mindee + module Parsing + module V2 + # Metadata about the RAG operation. + class RAGMetadata + # The UUID of the matched document used during the RAG operation. + attr_accessor :retrieved_document_id + + def initialize(server_response) + @retrieved_document_id = server_response.fetch('retrieved_document_id', nil) + end + end + end + end +end diff --git a/sig/mindee/errors/mindee_http_error_v2.rbs b/sig/mindee/errors/mindee_http_error_v2.rbs index b687f43c..b6b3d924 100644 --- a/sig/mindee/errors/mindee_http_error_v2.rbs +++ b/sig/mindee/errors/mindee_http_error_v2.rbs @@ -3,9 +3,12 @@ module Mindee module Errors # API V2 HttpError class MindeeHTTPErrorV2 < MindeeError - attr_reader detail: String attr_reader status: Integer + attr_reader code: String + attr_reader title: String + attr_reader errors: Array[Parsing::V2::ErrorItem] + def initialize: (Hash[String, untyped] | Parsing::V2::ErrorResponse) -> void end end diff --git a/sig/mindee/errors/mindee_http_unknown_error_v2.rbs b/sig/mindee/errors/mindee_http_unknown_error_v2.rbs new file mode 100644 index 00000000..459cef08 --- /dev/null +++ b/sig/mindee/errors/mindee_http_unknown_error_v2.rbs @@ -0,0 +1,9 @@ +# lib/mindee/errors/mindee_http_unknown_error_v2.rb +module Mindee + module Errors + # Unknown HTTP error for the V2 API. + class MindeeHTTPUnknownErrorV2 < MindeeHTTPErrorV2 + def initialize: (Hash[String|Symbol, untyped]) -> void + end + end +end diff --git a/sig/mindee/parsing/v2/error_item.rbs b/sig/mindee/parsing/v2/error_item.rbs new file mode 100644 index 00000000..04b4e675 --- /dev/null +++ b/sig/mindee/parsing/v2/error_item.rbs @@ -0,0 +1,13 @@ +# lib/mindee/parsing/v2/error_item.rb +module Mindee + module Parsing + module V2 + class ErrorItem + attr_reader pointer: String + attr_reader detail: String|nil + + def initialize: (Hash[String|Symbol, untyped]) -> void + end + end + end +end diff --git a/sig/mindee/parsing/v2/error_response.rbs b/sig/mindee/parsing/v2/error_response.rbs index 1964d271..7c0fdf55 100644 --- a/sig/mindee/parsing/v2/error_response.rbs +++ b/sig/mindee/parsing/v2/error_response.rbs @@ -5,6 +5,9 @@ module Mindee class ErrorResponse attr_reader detail: String attr_reader status: Integer + attr_reader code: String + attr_reader title: String + attr_reader errors: Array[ErrorItem] def initialize: (Hash[String | Symbol, untyped]) -> void def as_hash: -> Hash[Symbol, String | Integer] diff --git a/sig/mindee/parsing/v2/inference_result.rbs b/sig/mindee/parsing/v2/inference_result.rbs index 5bc3f083..a8342780 100644 --- a/sig/mindee/parsing/v2/inference_result.rbs +++ b/sig/mindee/parsing/v2/inference_result.rbs @@ -5,6 +5,7 @@ module Mindee class InferenceResult attr_reader fields: Field::InferenceFields attr_reader raw_text: RawText? + attr_reader rag: RAGMetadata? def initialize: (Hash[String | Symbol, untyped]) -> void def to_s: -> String diff --git a/sig/mindee/parsing/v2/rag_metadata.rbs b/sig/mindee/parsing/v2/rag_metadata.rbs new file mode 100644 index 00000000..2995de66 --- /dev/null +++ b/sig/mindee/parsing/v2/rag_metadata.rbs @@ -0,0 +1,13 @@ +# lib/mindee/parsing/v2/rag_metadata.rb + +module Mindee + module Parsing + module V2 + class RAGMetadata + attr_accessor retrieved_document_id: string | nil + + def initialize: (Hash[String | Symbol, untyped]) -> void + end + end + end +end diff --git a/spec/openssl_crl_workaround.rb b/spec/openssl_crl_workaround.rb index e76e81fa..1f10c085 100644 --- a/spec/openssl_crl_workaround.rb +++ b/spec/openssl_crl_workaround.rb @@ -2,6 +2,7 @@ require 'openssl' +# Workaround for errors in SSL certificates validations on macOS. params = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS params[:verify_mode] = OpenSSL::SSL::VERIFY_PEER diff --git a/spec/v2/client_v2_integration.rb b/spec/v2/client_v2_integration.rb index 2b65c09a..cd6264a1 100644 --- a/spec/v2/client_v2_integration.rb +++ b/spec/v2/client_v2_integration.rb @@ -1,148 +1,210 @@ # frozen_string_literal: true -RSpec.describe 'Mindee::ClientV2 – integration tests (V2)', :integration, order: :defined do +describe 'Mindee::ClientV2 – integration tests (V2)', :integration, order: :defined do let(:api_key) { ENV.fetch('MINDEE_V2_API_KEY') } let(:model_id) { ENV.fetch('MINDEE_V2_FINDOC_MODEL_ID') } let(:blank_pdf_url) { ENV.fetch('MINDEE_V2_SE_TESTS_BLANK_PDF_URL') } let(:client) { Mindee::ClientV2.new(api_key: api_key) } - - it 'parses an empty multi-page PDF successfully' do - src_path = File.join(FILE_TYPES_DIR, 'pdf', 'multipage_cut-2.pdf') - input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'multipage_cut-2.pdf') - - polling = Mindee::Input::PollingOptions.new( - initial_delay_sec: 3.0, - delay_sec: 1.5, - max_retries: 80 - ) - - params = Mindee::Input::InferenceParameters.new( - model_id, - rag: false, - raw_text: true, - polygon: false, - confidence: false, - file_alias: 'ruby-integration-test', - polling_options: polling - ) - - response = client.enqueue_and_get_inference(input, params) - - expect(response).not_to be_nil - expect(response.inference).not_to be_nil - - file = response.inference.file - expect(file).not_to be_nil - expect(file).to be_a(Mindee::Parsing::V2::InferenceFile) - expect(file.name).to eq('multipage_cut-2.pdf') - expect(file.page_count).to eq(2) - - model = response.inference.model - expect(model).not_to be_nil - expect(model).to be_a(Mindee::Parsing::V2::InferenceModel) - expect(model.id).to eq(model_id) - - active_options = response.inference.active_options - expect(active_options).not_to be_nil - expect(active_options).to be_a(Mindee::Parsing::V2::InferenceActiveOptions) - expect(active_options.raw_text).to eq(true) - expect(active_options.polygon).to eq(false) - expect(active_options.confidence).to eq(false) - expect(active_options.rag).to eq(false) - - result = response.inference.result - expect(result).not_to be_nil - - expect(result.raw_text).not_to be_nil - expect(result.raw_text.pages.length).to eq(2) - - expect(result.fields).not_to be_nil - end - - it 'parses a filled single-page image successfully' do - src_path = File.join(V1_PRODUCT_DATA_DIR, 'financial_document', 'default_sample.jpg') - input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'default_sample.jpg') - - params = Mindee::Input::InferenceParameters.new( - model_id, - raw_text: false, - polygon: false, - confidence: false, - rag: false, - file_alias: 'ruby-integration-test' - ) - - response = client.enqueue_and_get_inference(input, params) - expect(response).not_to be_nil - - file = response.inference.file - expect(file).not_to be_nil - expect(file).to be_a(Mindee::Parsing::V2::InferenceFile) - expect(file.name).to eq('default_sample.jpg') - expect(file.page_count).to eq(1) - - model = response.inference.model - expect(model).not_to be_nil - expect(model).to be_a(Mindee::Parsing::V2::InferenceModel) - expect(model.id).to eq(model_id) - - active_options = response.inference.active_options - expect(active_options).not_to be_nil - expect(active_options).to be_a(Mindee::Parsing::V2::InferenceActiveOptions) - expect(active_options.raw_text).to eq(false) - expect(active_options.polygon).to eq(false) - expect(active_options.confidence).to eq(false) - expect(active_options.rag).to eq(false) - - result = response.inference.result - expect(result).not_to be_nil - - expect(result.raw_text).to be_nil - - fields = result.fields - expect(fields).not_to be_nil - expect(fields['supplier_name']).not_to be_nil - expect(fields['supplier_name'].value).to eq('John Smith') - end - - it 'raises MindeeHTTPErrorV2 (422) on invalid model id' do - src_path = File.join(FILE_TYPES_DIR, 'pdf', 'blank_1.pdf') - input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'blank_1.pdf') - - params = Mindee::Input::InferenceParameters.new('INVALID_MODEL_ID') - - expect do - client.enqueue_inference(input, params) - end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| expect(e.status).to eq(422) } - end - - it 'raises MindeeHTTPErrorV2 (422) on invalid webhook id' do - src_path = File.join(FILE_TYPES_DIR, 'pdf', 'blank_1.pdf') - input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'blank_1.pdf') - - params = Mindee::Input::InferenceParameters.new(model_id, - webhook_ids: ['INVALID_WEBHOOK_ID']) - - expect do - client.enqueue_inference(input, params) - end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| expect(e.status).to eq(422) } + context 'An input file' do + it 'parses an empty multi-page PDF successfully' do + src_path = File.join(FILE_TYPES_DIR, 'pdf', 'multipage_cut-2.pdf') + input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'multipage_cut-2.pdf') + + polling = Mindee::Input::PollingOptions.new( + initial_delay_sec: 3.0, + delay_sec: 1.5, + max_retries: 80 + ) + + params = Mindee::Input::InferenceParameters.new( + model_id, + rag: false, + raw_text: true, + polygon: false, + confidence: false, + file_alias: 'ruby-integration-test', + polling_options: polling + ) + + response = client.enqueue_and_get_inference(input, params) + + expect(response).not_to be_nil + expect(response.inference).not_to be_nil + + file = response.inference.file + expect(file).not_to be_nil + expect(file).to be_a(Mindee::Parsing::V2::InferenceFile) + expect(file.name).to eq('multipage_cut-2.pdf') + expect(file.page_count).to eq(2) + + model = response.inference.model + expect(model).not_to be_nil + expect(model).to be_a(Mindee::Parsing::V2::InferenceModel) + expect(model.id).to eq(model_id) + + active_options = response.inference.active_options + expect(active_options).not_to be_nil + expect(active_options).to be_a(Mindee::Parsing::V2::InferenceActiveOptions) + expect(active_options.raw_text).to eq(true) + expect(active_options.polygon).to eq(false) + expect(active_options.confidence).to eq(false) + expect(active_options.rag).to eq(false) + + result = response.inference.result + expect(result).not_to be_nil + + expect(result.raw_text).not_to be_nil + expect(result.raw_text.pages.length).to eq(2) + + expect(result.fields).not_to be_nil + end + + it 'parses a filled single-page image successfully' do + src_path = File.join(V1_PRODUCT_DATA_DIR, 'financial_document', 'default_sample.jpg') + input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'default_sample.jpg') + + params = Mindee::Input::InferenceParameters.new( + model_id, + raw_text: false, + polygon: false, + confidence: false, + rag: false, + file_alias: 'ruby-integration-test' + ) + + response = client.enqueue_and_get_inference(input, params) + expect(response).not_to be_nil + + file = response.inference.file + expect(file).not_to be_nil + expect(file).to be_a(Mindee::Parsing::V2::InferenceFile) + expect(file.name).to eq('default_sample.jpg') + expect(file.page_count).to eq(1) + + model = response.inference.model + expect(model).not_to be_nil + expect(model).to be_a(Mindee::Parsing::V2::InferenceModel) + expect(model.id).to eq(model_id) + + active_options = response.inference.active_options + expect(active_options).not_to be_nil + expect(active_options).to be_a(Mindee::Parsing::V2::InferenceActiveOptions) + expect(active_options.raw_text).to eq(false) + expect(active_options.polygon).to eq(false) + expect(active_options.confidence).to eq(false) + expect(active_options.rag).to eq(false) + + result = response.inference.result + expect(result).not_to be_nil + + expect(result.raw_text).to be_nil + + fields = result.fields + expect(fields).not_to be_nil + expect(fields['supplier_name']).not_to be_nil + expect(fields['supplier_name'].value).to eq('John Smith') + end end - - it 'raises MindeeHTTPErrorV2 on invalid job id' do - expect do - client.get_inference('INVALID_JOB_ID') - end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| expect(e.status).to eq(422) } + context 'An error' do + it 'raises MindeeHTTPErrorV2 (422) on invalid model id' do + src_path = File.join(FILE_TYPES_DIR, 'pdf', 'blank_1.pdf') + input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'blank_1.pdf') + + params = Mindee::Input::InferenceParameters.new('INVALID_MODEL_ID') + + expect do + client.enqueue_inference(input, params) + end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| expect(e.status).to eq(422) } + end + + it 'raises MindeeHTTPErrorV2 (422) on invalid webhook id' do + src_path = File.join(FILE_TYPES_DIR, 'pdf', 'blank_1.pdf') + input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'blank_1.pdf') + + params = Mindee::Input::InferenceParameters.new(model_id, + webhook_ids: ['INVALID_WEBHOOK_ID']) + + expect do + client.enqueue_inference(input, params) + end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| + expect(e.status).to eq(422) + expect(e.code).to start_with('422-') + expect(e.detail).to_not be_nil + expect(e.title).to_not be_nil + expect(e.errors).to be_an_instance_of(Array) + expect(e.errors.count).to be_positive + } + end + + it 'raises MindeeHTTPErrorV2 (422) on non-existant webhook id' do + src_path = File.join(FILE_TYPES_DIR, 'pdf', 'blank_1.pdf') + input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'blank_1.pdf') + + params = Mindee::Input::InferenceParameters.new(model_id, + webhook_ids: ['fc405e37-4ba4-4d03-aeba-533a8d1f0f21', + 'fc405e37-4ba4-4d03-aeba-533a8d1f0f21']) + + expect do + client.enqueue_inference(input, params) + end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| + expect(e.status).to eq(422) + expect(e.code).to start_with('422-') + expect(e.detail).to_not be_nil + expect(e.title).to_not be_nil + expect(e.errors).to be_an_instance_of(Array) + expect(e.errors.count).to be_positive + expect(e.errors[0]).to be_an_instance_of(Mindee::Parsing::V2::ErrorItem) + } + end + + it 'raises MindeeHTTPErrorV2 on invalid job id' do + expect do + client.get_inference('INVALID_JOB_ID') + end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| + expect(e.status).to eq(422) + expect(e.code).to start_with('422-') + expect(e.detail).to_not be_nil + expect(e.title).to_not be_nil + expect(e.errors).to be_an_instance_of(Array) + expect(e.errors.count).to be_positive + } + end + + it 'raises on invalid model ID' do + expect do + src_path = File.join(V1_PRODUCT_DATA_DIR, 'financial_document', 'default_sample.jpg') + input = Mindee::Input::Source::FileInputSource.new(File.open(src_path, 'rb'), 'default_sample.jpg') + + params = Mindee::Input::InferenceParameters.new( + 'fc405e37-4ba4-4d03-aeba-533a8d1f0f21', + raw_text: false, + polygon: false, + confidence: false, + rag: false, + file_alias: 'ruby-integration-test' + ) + client.enqueue_and_get_inference(input, params) + end.to raise_error(Mindee::Errors::MindeeHTTPErrorV2) { |e| + expect(e.status).to eq(404) + expect(e.code).to start_with('404-') + expect(e.detail).to_not be_nil + expect(e.title).to_not be_nil + expect(e.errors).to be_an_instance_of(Array) + } + end end - it 'parses an URL input source without errors' do - url_input = Mindee::Input::Source::URLInputSource.new(blank_pdf_url) + context 'A remote input source' do + it 'parses an URL input source without errors' do + url_input = Mindee::Input::Source::URLInputSource.new(blank_pdf_url) - params = Mindee::Input::InferenceParameters.new(model_id) + params = Mindee::Input::InferenceParameters.new(model_id) - response = client.enqueue_and_get_inference(url_input, params) + response = client.enqueue_and_get_inference(url_input, params) - expect(response).not_to be_nil - expect(response.inference).not_to be_nil + expect(response).not_to be_nil + expect(response.inference).not_to be_nil + end end end diff --git a/spec/v2/parsing/inference_spec.rb b/spec/v2/parsing/inference_spec.rb index a53c3e00..3285b74b 100644 --- a/spec/v2/parsing/inference_spec.rb +++ b/spec/v2/parsing/inference_spec.rb @@ -13,6 +13,8 @@ let(:raw_text_str_path) { File.join(inference_path, 'raw_texts.txt') } let(:blank_path) { File.join(findoc_path, 'blank.json') } let(:complete_path) { File.join(findoc_path, 'complete.json') } + let(:rag_matched_path) { File.join(inference_path, 'rag_matched.json') } + let(:rag_not_matched_path) { File.join(inference_path, 'rag_not_matched.json') } def load_v2_inference(resource_path) local_response = Mindee::Input::LocalResponse.new(resource_path) @@ -21,7 +23,7 @@ def load_v2_inference(resource_path) simple_field = Mindee::Parsing::V2::Field::SimpleField object_field = Mindee::Parsing::V2::Field::ObjectField - list_field = Mindee::Parsing::V2::Field::ListField + list_field = Mindee::Parsing::V2::Field::ListField field_confidence = Mindee::Parsing::V2::Field::FieldConfidence describe 'simple' do @@ -348,4 +350,17 @@ def load_standard_fields expect(confidence).to be_gteql(1) end end + describe 'RAG Metadata' do + it 'when matched' do + response = load_v2_inference(rag_matched_path) + expect(response.inference).not_to be_nil + expect(response.inference.result.rag.retrieved_document_id).to eq('12345abc-1234-1234-1234-123456789abc') + end + + it 'when not matched' do + response = load_v2_inference(rag_not_matched_path) + expect(response.inference).not_to be_nil + expect(response.inference.result.rag.retrieved_document_id).to be_nil + end + end end