Compare commits

...
Author SHA1 Message Date
aakashb95 add3b98e07 fix(captain): bypass Firecrawl cache during sync 2026-06-03 15:52:59 +05:30
tomsideguide 508631a8ca chore(captain): migrate Firecrawl service to v2 API
Update Captain::Tools::FirecrawlService to target api.firecrawl.dev/v2.
Rename crawl params for v2: maxDepth -> maxDiscoveryDepth,
ignoreSitemap:false -> sitemap:'include', and send webhook as an object.
2026-06-02 16:43:04 +01:00
2 changed files with 16 additions and 14 deletions
@@ -1,5 +1,5 @@
class Captain::Tools::FirecrawlService class Captain::Tools::FirecrawlService
BASE_URL = 'https://api.firecrawl.dev/v1'.freeze BASE_URL = 'https://api.firecrawl.dev/v2'.freeze
FIRECRAWL_EXCLUDE_TAGS = %w[iframe .sidebar .cookie-banner [role=navigation] [role=banner] [role=contentinfo]].freeze FIRECRAWL_EXCLUDE_TAGS = %w[iframe .sidebar .cookie-banner [role=navigation] [role=banner] [role=contentinfo]].freeze
def self.configured? def self.configured?
@@ -35,10 +35,10 @@ class Captain::Tools::FirecrawlService
def crawl_payload(url, webhook_url, crawl_limit) def crawl_payload(url, webhook_url, crawl_limit)
{ {
url: url, url: url,
maxDepth: 50, maxDiscoveryDepth: 50,
ignoreSitemap: false, sitemap: 'include',
limit: crawl_limit, limit: crawl_limit,
webhook: webhook_url, webhook: { url: webhook_url },
scrapeOptions: scrape_options scrapeOptions: scrape_options
}.to_json }.to_json
end end
@@ -50,6 +50,7 @@ class Captain::Tools::FirecrawlService
def scrape_options def scrape_options
{ {
onlyMainContent: true, onlyMainContent: true,
maxAge: 0,
formats: ['markdown'], formats: ['markdown'],
excludeTags: FIRECRAWL_EXCLUDE_TAGS excludeTags: FIRECRAWL_EXCLUDE_TAGS
} }
@@ -53,12 +53,13 @@ RSpec.describe Captain::Tools::FirecrawlService do
let(:expected_payload) do let(:expected_payload) do
{ {
url: url, url: url,
maxDepth: 50, maxDiscoveryDepth: 50,
ignoreSitemap: false, sitemap: 'include',
limit: crawl_limit, limit: crawl_limit,
webhook: webhook_url, webhook: { url: webhook_url },
scrapeOptions: { scrapeOptions: {
onlyMainContent: true, onlyMainContent: true,
maxAge: 0,
formats: ['markdown'], formats: ['markdown'],
excludeTags: Captain::Tools::FirecrawlService::FIRECRAWL_EXCLUDE_TAGS excludeTags: Captain::Tools::FirecrawlService::FIRECRAWL_EXCLUDE_TAGS
} }
@@ -74,7 +75,7 @@ RSpec.describe Captain::Tools::FirecrawlService do
context 'when the API call is successful' do context 'when the API call is successful' do
before do before do
stub_request(:post, 'https://api.firecrawl.dev/v1/crawl') stub_request(:post, 'https://api.firecrawl.dev/v2/crawl')
.with( .with(
body: expected_payload, body: expected_payload,
headers: expected_headers headers: expected_headers
@@ -85,7 +86,7 @@ RSpec.describe Captain::Tools::FirecrawlService do
it 'makes a POST request with correct parameters' do it 'makes a POST request with correct parameters' do
service.perform(url, webhook_url, crawl_limit) service.perform(url, webhook_url, crawl_limit)
expect(WebMock).to have_requested(:post, 'https://api.firecrawl.dev/v1/crawl') expect(WebMock).to have_requested(:post, 'https://api.firecrawl.dev/v2/crawl')
.with( .with(
body: expected_payload, body: expected_payload,
headers: expected_headers headers: expected_headers
@@ -95,7 +96,7 @@ RSpec.describe Captain::Tools::FirecrawlService do
it 'uses default crawl limit when not specified' do it 'uses default crawl limit when not specified' do
default_payload = expected_payload.gsub(crawl_limit.to_s, '10') default_payload = expected_payload.gsub(crawl_limit.to_s, '10')
stub_request(:post, 'https://api.firecrawl.dev/v1/crawl') stub_request(:post, 'https://api.firecrawl.dev/v2/crawl')
.with( .with(
body: default_payload, body: default_payload,
headers: expected_headers headers: expected_headers
@@ -104,7 +105,7 @@ RSpec.describe Captain::Tools::FirecrawlService do
service.perform(url, webhook_url) service.perform(url, webhook_url)
expect(WebMock).to have_requested(:post, 'https://api.firecrawl.dev/v1/crawl') expect(WebMock).to have_requested(:post, 'https://api.firecrawl.dev/v2/crawl')
.with( .with(
body: default_payload, body: default_payload,
headers: expected_headers headers: expected_headers
@@ -114,7 +115,7 @@ RSpec.describe Captain::Tools::FirecrawlService do
context 'when the API call fails' do context 'when the API call fails' do
before do before do
stub_request(:post, 'https://api.firecrawl.dev/v1/crawl') stub_request(:post, 'https://api.firecrawl.dev/v2/crawl')
.to_raise(StandardError.new('Connection failed')) .to_raise(StandardError.new('Connection failed'))
end end
@@ -126,14 +127,14 @@ RSpec.describe Captain::Tools::FirecrawlService do
context 'when the API returns an error response' do context 'when the API returns an error response' do
before do before do
stub_request(:post, 'https://api.firecrawl.dev/v1/crawl') stub_request(:post, 'https://api.firecrawl.dev/v2/crawl')
.to_return(status: 422, body: '{"error": "Invalid URL"}') .to_return(status: 422, body: '{"error": "Invalid URL"}')
end end
it 'makes the request but does not raise an error' do it 'makes the request but does not raise an error' do
expect { service.perform(url, webhook_url, crawl_limit) }.not_to raise_error expect { service.perform(url, webhook_url, crawl_limit) }.not_to raise_error
expect(WebMock).to have_requested(:post, 'https://api.firecrawl.dev/v1/crawl') expect(WebMock).to have_requested(:post, 'https://api.firecrawl.dev/v2/crawl')
.with( .with(
body: expected_payload, body: expected_payload,
headers: expected_headers headers: expected_headers