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
42 changes: 42 additions & 0 deletions apps/sim/tools/error-extractors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,46 @@ describe('Error Extractors', () => {
)
})
})

describe('wiza-errors', () => {
it('extracts the message nested under status', () => {
const errorInfo: ErrorInfo = {
status: 400,
statusText: 'Bad Request',
data: { status: { code: 400, message: 'The size parameter is not allowed.' } },
}

expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe(
'The size parameter is not allowed.'
)
})

it('falls back to a top-level message', () => {
const errorInfo: ErrorInfo = { status: 401, data: { message: 'Unauthorized' } }

expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe('Unauthorized')
})

it('keeps plain-text bodies', () => {
const errorInfo: ErrorInfo = { status: 502, data: 'Bad gateway' }

expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe('Bad gateway')
})

it('ignores a non-string top-level message', () => {
const errorInfo: ErrorInfo = { status: 422, data: { message: ['bad filter'] } }

expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe(
'Request failed with status 422'
)
})

it('falls back to the status when Wiza sends an empty message', () => {
const errorInfo: ErrorInfo = { status: 400, data: { status: { code: 400, message: '' } } }

expect(extractErrorMessage(errorInfo, ErrorExtractorId.WIZA_ERRORS)).toBe(
'Request failed with status 400'
)
})
})
})
15 changes: 15 additions & 0 deletions apps/sim/tools/error-extractors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,20 @@ const ERROR_EXTRACTORS: ErrorExtractorConfig[] = [
return parts.length > 0 ? parts.join(': ') : undefined
},
},
{
id: 'wiza-errors',
description:
'Wiza API error envelope: {status: {code, message}}, plus plain-text bodies. The message is nested under status, so the generic extractors miss it',
examples: ['Wiza'],
extract: (errorInfo) => {
const data = errorInfo?.data
const candidates = [data, data?.status?.message, data?.message]
for (const candidate of candidates) {
if (typeof candidate === 'string' && candidate.trim()) return candidate.trim()
}
return undefined
},
},
{
id: 'crunchbase-errors',
description:
Expand Down Expand Up @@ -680,6 +694,7 @@ export const ErrorExtractorId = {
POSTHOG_ERRORS: 'posthog-errors',
QUICKBOOKS_FAULT: 'quickbooks-fault',
PROSPEO_ERRORS: 'prospeo-errors',
WIZA_ERRORS: 'wiza-errors',
CRUNCHBASE_ERRORS: 'crunchbase-errors',
PITCHBOOK_ERRORS: 'pitchbook-errors',
SPLUNK_ERRORS: 'splunk-errors',
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/tools/wiza/company_enrichment.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ErrorExtractorId } from '@/tools/error-extractors'
import type { ToolConfig } from '@/tools/types'
import { wizaHosting } from '@/tools/wiza/hosting'
import type { WizaCompanyEnrichmentParams, WizaCompanyEnrichmentResponse } from '@/tools/wiza/types'
Expand All @@ -11,6 +12,7 @@ export const wizaCompanyEnrichmentTool: ToolConfig<
description:
'Enrich a company by name, domain, LinkedIn ID, or LinkedIn slug with detailed firmographic data',
version: '1.0.0',
errorExtractor: ErrorExtractorId.WIZA_ERRORS,

hosting: wizaHosting<WizaCompanyEnrichmentParams>((_params, output) => {
// 2 API credits per successful company match; no charge on a no-match.
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/tools/wiza/get_credits.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ErrorExtractorId } from '@/tools/error-extractors'
import type { ToolConfig } from '@/tools/types'
import type { WizaGetCreditsParams, WizaGetCreditsResponse } from '@/tools/wiza/types'

Expand All @@ -6,6 +7,7 @@ export const wizaGetCreditsTool: ToolConfig<WizaGetCreditsParams, WizaGetCredits
name: 'Wiza Get Credits',
description: 'Retrieve the remaining credits on your Wiza account',
version: '1.0.0',
errorExtractor: ErrorExtractorId.WIZA_ERRORS,

params: {
apiKey: {
Expand Down
17 changes: 16 additions & 1 deletion apps/sim/tools/wiza/individual_reveal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { sleep } from '@sim/utils/helpers'
import { ErrorExtractorId, extractErrorMessage } from '@/tools/error-extractors'
import type { ToolConfig } from '@/tools/types'
import { wizaHosting } from '@/tools/wiza/hosting'
import type {
Expand Down Expand Up @@ -77,6 +78,7 @@ export const wizaIndividualRevealTool: ToolConfig<
description:
'Reveal a contact via LinkedIn URL, name + company/domain, or email. Starts the reveal and polls until it resolves. Uses 2 credits per valid email and 5 credits per phone, charged only on success.',
version: '1.0.0',
errorExtractor: ErrorExtractorId.WIZA_ERRORS,
Comment thread
TheodoreSpeaks marked this conversation as resolved.

hosting: wizaHosting<WizaIndividualRevealParams>((_params, output) => {
let credits = 0
Expand Down Expand Up @@ -238,9 +240,22 @@ export const wizaIndividualRevealTool: ToolConfig<
consecutiveErrors += 1
if (consecutiveErrors >= MAX_CONSECUTIVE_POLL_ERRORS) {
const errorText = await statusResponse.text().catch(() => '')
let errorData: unknown
try {
errorData = JSON.parse(errorText)
} catch {
errorData = errorText
}
return {
success: false,
error: `Wiza API error: ${statusResponse.status} - ${errorText}`,
error: extractErrorMessage(
{
status: statusResponse.status,
statusText: statusResponse.statusText,
data: errorData,
},
ErrorExtractorId.WIZA_ERRORS
),
output: result.output,
}
}
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/tools/wiza/prospect_search.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isRecordLike } from '@sim/utils/object'
import { ErrorExtractorId } from '@/tools/error-extractors'
import type { ToolConfig } from '@/tools/types'
import { wizaHosting } from '@/tools/wiza/hosting'
import type { WizaProspectSearchParams, WizaProspectSearchResponse } from '@/tools/wiza/types'
Expand All @@ -11,6 +12,7 @@ export const wizaProspectSearchTool: ToolConfig<
name: 'Wiza Prospect Search',
description: "Search Wiza's database of prospects using person, company, and financial filters",
version: '1.0.0',
errorExtractor: ErrorExtractorId.WIZA_ERRORS,

hosting: wizaHosting<WizaProspectSearchParams>(() => {
// Prospect search returns profiles without contact data and consumes no credits;
Expand Down
Loading