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
23 changes: 17 additions & 6 deletions apps/sim/providers/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,7 @@ describe('transformBlockTool multi-instance unique IDs', () => {
expect(result?.id).toBe('table_query_rows_tbl_abc')
})

it('resolves the canonical table id before enriching the LLM tool schema', async () => {
it('resolves the active table selector before enriching the LLM tool schema', async () => {
const enrichTool = vi.fn(
async (
tableId: string,
Expand All @@ -1646,7 +1646,7 @@ describe('transformBlockTool multi-instance unique IDs', () => {
{
type: 'table',
operation: 'query_rows',
params: { tableSelector: 'tbl_abc' },
params: { tableId: 'tbl_stale', tableSelector: 'tbl_active' },
},
{
selectedOperation: 'query_rows',
Expand All @@ -1672,7 +1672,7 @@ describe('transformBlockTool multi-instance unique IDs', () => {
)

expect(enrichTool).toHaveBeenCalledWith(
'tbl_abc',
'tbl_active',
expect.objectContaining({
properties: expect.objectContaining({ filter: expect.any(Object) }),
}),
Expand All @@ -1683,15 +1683,16 @@ describe('transformBlockTool multi-instance unique IDs', () => {
}
)
expect(result).toMatchObject({
id: 'table_query_rows_tbl_abc',
description: 'Query rows from tbl_abc',
params: { tableSelector: 'tbl_abc' },
id: 'table_query_rows_tbl_active',
description: 'Query rows from tbl_active',
params: { tableId: 'tbl_stale', tableSelector: 'tbl_active' },
parameters: {
properties: {
customer_name: { type: 'string' },
},
},
})
expect(result?.paramsTransform?.(result.params)).toEqual({ tableId: 'tbl_active' })
})

it('appends the table id resolved from the advanced manual input', async () => {
Expand All @@ -1715,6 +1716,16 @@ describe('transformBlockTool multi-instance unique IDs', () => {
expect(result?.id).toBe('table_query_rows_tbl_direct')
})

it('preserves the canonical table id when advanced mode is active', async () => {
const result = await transformTable(
{ tableId: 'tbl_advanced', tableSelector: 'tbl_basic' },
{ '0:tableId': 'advanced' },
0
)
expect(result?.id).toBe('table_query_rows_tbl_advanced')
expect(result?.paramsTransform?.(result.params)).toEqual({ tableId: 'tbl_advanced' })
})

it('falls back to the base tool id when no table is selected', async () => {
const result = await transformTable({})
expect(result?.id).toBe('table_query_rows')
Expand Down
9 changes: 4 additions & 5 deletions apps/sim/providers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,15 +487,16 @@ export function extractAndParseJSON(content: string): any {

/**
* Resolves canonical pair ids (e.g. `tableId`, `knowledgeBaseId`) from a tool's
* raw params, filling them in from their basic/advanced selector subblock source
* values when the canonical key isn't already present.
* raw params, preferring the active basic/advanced selector subblock source over
* a previously resolved canonical value.
*
* Selector subblocks persist their value under the subblock id (e.g.
* `tableSelector`), not the canonical id, so any lookup that keys off the
* canonical id — like the unique-tool-id suffix below — must resolve it first.
* Mode selection mirrors {@link transformBlockTool}'s execution-time
* `paramsTransform` so the resolved id matches the params the tool actually runs
* with.
* with. When the active selector has no value, the original canonical value is
* preserved for direct-id callers and nested tools in advanced mode.
*
* @returns The params with canonical resource ids resolved (non-destructive)
*/
Expand All @@ -507,8 +508,6 @@ function resolveCanonicalResourceParams(
if (canonicalGroups.length === 0) return params
const resolved = { ...params }
for (const group of canonicalGroups) {
const existing = resolved[group.canonicalId]
if (existing !== undefined && existing !== null && existing !== '') continue
// Route through the canonical SOT: an explicit scoped override wins, else the value heuristic -
// no `?? 'basic'` (which ignored an advanced-only value when basic was empty).
const explicitMode = scopedCanonicalModes?.[group.canonicalId]
Expand Down
Loading