feat: include contact verified status with each tool call (#13663)

Co-authored-by: aakashb95 <aakashbakhle@gmail.com>
This commit is contained in:
Shivam Mishra
2026-02-26 16:16:33 +05:30
committed by GitHub
parent 6b3f1114fd
commit 7c60ad9e28
7 changed files with 125 additions and 10 deletions

View File

@@ -249,6 +249,10 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
id: conversation.id,
display_id: conversation.display_id
},
contact_inbox: {
id: conversation.contact_inbox.id,
hmac_verified: conversation.contact_inbox.hmac_verified
},
contact: {
id: contact.id,
email: contact.email,
@@ -272,6 +276,8 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
'X-Chatwoot-Tool-Slug' => custom_tool.slug,
'X-Chatwoot-Conversation-Id' => conversation.id.to_s,
'X-Chatwoot-Conversation-Display-Id' => conversation.display_id.to_s,
'X-Chatwoot-Contact-Inbox-Id' => conversation.contact_inbox.id.to_s,
'X-Chatwoot-Contact-Inbox-Verified' => conversation.contact_inbox.hmac_verified.to_s,
'X-Chatwoot-Contact-Id' => contact.id.to_s,
'X-Chatwoot-Contact-Email' => contact.email
})
@@ -282,6 +288,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
expect(WebMock).to have_requested(:get, 'https://example.com/api/data')
.with(headers: {
'X-Chatwoot-Account-Id' => account.id.to_s,
'X-Chatwoot-Contact-Inbox-Verified' => conversation.contact_inbox.hmac_verified.to_s,
'X-Chatwoot-Contact-Email' => contact.email
})
end
@@ -296,6 +303,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
'Content-Type' => 'application/json',
'X-Chatwoot-Account-Id' => account.id.to_s,
'X-Chatwoot-Tool-Slug' => custom_tool.slug,
'X-Chatwoot-Contact-Inbox-Verified' => conversation.contact_inbox.hmac_verified.to_s,
'X-Chatwoot-Contact-Email' => contact.email
}
)
@@ -316,6 +324,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
.with(headers: {
'Authorization' => 'Bearer test_token',
'X-Chatwoot-Account-Id' => account.id.to_s,
'X-Chatwoot-Contact-Inbox-Verified' => conversation.contact_inbox.hmac_verified.to_s,
'X-Chatwoot-Contact-Id' => contact.id.to_s
})
.to_return(status: 200, body: '{"success": true}')
@@ -336,13 +345,18 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
conversation: {
id: conversation.id,
display_id: conversation.display_id
},
contact_inbox: {
id: conversation.contact_inbox.id,
hmac_verified: conversation.contact_inbox.hmac_verified
}
})
stub_request(:get, 'https://example.com/api/data')
.with(headers: {
'X-Chatwoot-Account-Id' => account.id.to_s,
'X-Chatwoot-Conversation-Id' => conversation.id.to_s
'X-Chatwoot-Conversation-Id' => conversation.id.to_s,
'X-Chatwoot-Contact-Inbox-Verified' => conversation.contact_inbox.hmac_verified.to_s
})
.to_return(status: 200, body: '{"success": true}')
@@ -351,6 +365,32 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
expect(WebMock).to have_requested(:get, 'https://example.com/api/data')
end
it 'defaults contact inbox verified header to false when contact inbox is missing' do
tool_context_without_contact_inbox = Struct.new(:state).new({
account_id: account.id,
assistant_id: assistant.id,
conversation: {
id: conversation.id,
display_id: conversation.display_id
},
contact: {
id: contact.id,
email: contact.email
}
})
stub_request(:get, 'https://example.com/api/data')
.with(headers: {
'X-Chatwoot-Contact-Inbox-Verified' => 'false'
})
.to_return(status: 200, body: '{"success": true}')
tool.perform(tool_context_without_contact_inbox)
expect(WebMock).to have_requested(:get, 'https://example.com/api/data')
.with(headers: { 'X-Chatwoot-Contact-Inbox-Verified' => 'false' })
end
it 'includes contact phone when present' do
contact.update!(phone_number: '+1234567890')
tool_context_with_state.state[:contact][:phone_number] = '+1234567890'
@@ -366,6 +406,22 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
expect(WebMock).to have_requested(:get, 'https://example.com/api/data')
.with(headers: { 'X-Chatwoot-Contact-Phone' => '+1234567890' })
end
it 'includes unverified contact inbox status explicitly as false' do
conversation.contact_inbox.update!(hmac_verified: false)
tool_context_with_state.state[:contact_inbox][:hmac_verified] = false
stub_request(:get, 'https://example.com/api/data')
.with(headers: {
'X-Chatwoot-Contact-Inbox-Verified' => 'false'
})
.to_return(status: 200, body: '{"success": true}')
tool.perform(tool_context_with_state)
expect(WebMock).to have_requested(:get, 'https://example.com/api/data')
.with(headers: { 'X-Chatwoot-Contact-Inbox-Verified' => 'false' })
end
end
end
end

View File

@@ -341,6 +341,10 @@ RSpec.describe Captain::CustomTool, type: :model do
id: conversation.id,
display_id: conversation.display_id
},
contact_inbox: {
id: conversation.contact_inbox.id,
hmac_verified: conversation.contact_inbox.hmac_verified
},
contact: {
id: contact.id,
email: contact.email,
@@ -376,6 +380,13 @@ RSpec.describe Captain::CustomTool, type: :model do
expect(headers['X-Chatwoot-Contact-Email']).to eq(contact.email)
end
it 'includes contact inbox verification metadata when present' do
headers = tool.build_metadata_headers(state)
expect(headers['X-Chatwoot-Contact-Inbox-Id']).to eq(conversation.contact_inbox.id.to_s)
expect(headers['X-Chatwoot-Contact-Inbox-Verified']).to eq(conversation.contact_inbox.hmac_verified.to_s)
end
it 'handles missing conversation gracefully' do
state[:conversation] = nil
@@ -396,11 +407,21 @@ RSpec.describe Captain::CustomTool, type: :model do
expect(headers['X-Chatwoot-Account-Id']).to eq(account.id.to_s)
end
it 'handles missing contact inbox gracefully' do
state[:contact_inbox] = nil
headers = tool.build_metadata_headers(state)
expect(headers['X-Chatwoot-Contact-Inbox-Id']).to be_nil
expect(headers['X-Chatwoot-Contact-Inbox-Verified']).to eq('false')
end
it 'handles empty state' do
headers = tool.build_metadata_headers({})
expect(headers).to be_a(Hash)
expect(headers['X-Chatwoot-Tool-Slug']).to eq('custom_test_tool')
expect(headers['X-Chatwoot-Contact-Inbox-Verified']).to eq('false')
end
it 'omits contact email header when email is blank' do
@@ -418,6 +439,22 @@ RSpec.describe Captain::CustomTool, type: :model do
expect(headers).not_to have_key('X-Chatwoot-Contact-Phone')
end
it 'includes contact inbox verified header when false' do
state[:contact_inbox][:hmac_verified] = false
headers = tool.build_metadata_headers(state)
expect(headers['X-Chatwoot-Contact-Inbox-Verified']).to eq('false')
end
it 'defaults contact inbox verified header to false when value is nil' do
state[:contact_inbox][:hmac_verified] = nil
headers = tool.build_metadata_headers(state)
expect(headers['X-Chatwoot-Contact-Inbox-Verified']).to eq('false')
end
end
describe '#to_tool_metadata' do

View File

@@ -384,6 +384,15 @@ RSpec.describe Captain::Assistant::AgentRunnerService do
expect(state[:channel_type]).to eq(inbox.channel_type)
end
it 'includes contact inbox attributes when conversation is present' do
state = service.send(:build_state)
expect(state[:contact_inbox]).to include(
id: conversation.contact_inbox.id,
hmac_verified: conversation.contact_inbox.hmac_verified
)
end
it 'includes contact attributes when contact is present' do
state = service.send(:build_state)