Skip to content

Commit 8e5a779

Browse files
committed
fix(exa): revert conditional required on Get Contents URLs
The conditional required callback did not work and introduced a regression. `isFieldRequired` in webhook deploy calls `config.required()` with no arguments, so the callback never saw `ids` and left URLs required — an ids-only block would have been reported as missing a required field on deploy. `collectBlockFieldIssues` skips sub-block required checks whose id matches a tool param, so it never evaluated the callback either. Both selectors go back to optional with the exactly-one check in the request body, which is what the integration rules prescribe for mutually exclusive alternate identifiers. Added a comment recording why a conditional required cannot express this, so it is not reattempted.
1 parent af94705 commit 8e5a779

2 files changed

Lines changed: 15 additions & 24 deletions

File tree

apps/sim/blocks/blocks/exa.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ const CATEGORY_OPTIONS = [
2222
* carrying a stored research query forward — it drops any value whose sub-block
2323
* condition no longer matches.
2424
*/
25-
/** True when a sub-block holds a non-empty user value. */
26-
function hasValue(value: unknown): boolean {
27-
return typeof value === 'string' ? value.trim().length > 0 : value != null
28-
}
29-
3025
const LEGACY_RESEARCH_OPERATION = 'exa_research'
3126
const AGENT_OPERATIONS = ['exa_agent', LEGACY_RESEARCH_OPERATION]
3227

@@ -270,17 +265,6 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
270265
placeholder: 'Enter URLs to retrieve content from (comma-separated)...',
271266
description: 'Provide either URLs or Result IDs, not both',
272267
condition: { field: 'operation', value: 'exa_get_contents' },
273-
/**
274-
* Exactly one selector is needed. Inverting the operation match when
275-
* Result IDs are present makes the requirement fall away for this
276-
* operation, so the editor flags an empty config without blocking the
277-
* ids-only path.
278-
*/
279-
required: (values) => ({
280-
field: 'operation',
281-
value: 'exa_get_contents',
282-
not: hasValue(values?.ids),
283-
}),
284268
},
285269
{
286270
id: 'ids',
@@ -291,6 +275,14 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
291275
condition: { field: 'operation', value: 'exa_get_contents' },
292276
mode: 'advanced',
293277
},
278+
/*
279+
* URLs and Result IDs are mutually exclusive alternate identifiers, so both
280+
* stay optional and the request body enforces exactly one. A conditional
281+
* `required` cannot express this: `isFieldRequired` in webhook deploy calls
282+
* the callback with no arguments, so it would mark URLs missing on a valid
283+
* ids-only block, and `collectBlockFieldIssues` skips sub-block required
284+
* checks whose id matches a tool param, so it would never run there anyway.
285+
*/
294286
{
295287
id: 'text',
296288
title: 'Include Text',

apps/sim/tools/exa/exa.test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,13 @@ describe('exa block', () => {
185185
expect(params.effort).toBe('medium')
186186
})
187187

188-
it('requires URLs on Get Contents when no result IDs are supplied', () => {
189-
const urls = ExaBlock.subBlocks.find(
190-
(block) => block.id === 'urls' && block.condition?.value === 'exa_get_contents'
191-
)
192-
const required = urls?.required as (values?: Record<string, unknown>) => { not?: boolean }
193-
expect(required({}).not).toBe(false)
194-
expect(required({ ids: ' ' }).not).toBe(false)
195-
expect(required({ ids: 'id-1' }).not).toBe(true)
188+
it('leaves both Get Contents selectors optional so the ids-only path stays valid', () => {
189+
for (const id of ['urls', 'ids']) {
190+
const selector = ExaBlock.subBlocks.find(
191+
(block) => block.id === id && block.condition?.value === 'exa_get_contents'
192+
)
193+
expect(selector?.required).toBeUndefined()
194+
}
196195
})
197196

198197
it('keeps the legacy model sub-block so the serializer preserves its value', () => {

0 commit comments

Comments
 (0)