Skip to content

Commit 898ccb1

Browse files
committed
fix(gauge): preserve configured agent filters
1 parent 8ed706e commit 898ccb1

8 files changed

Lines changed: 172 additions & 28 deletions

File tree

‎apps/docs/content/docs/integrations/gauge.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ Change the name or color of a prompt tag.
567567
| `org` | string | Yes | Organization slug or UUID |
568568
| `tagId` | string | Yes | Tag ID |
569569
| `name` | string | No | Tag name \(1–120 characters\) |
570-
| `color` | string | No | Tag color string \(up to 20 characters\) |
570+
| `color` | string | No | Tag color string \(up to 20 characters\); omit to keep unchanged or use "" to clear |
571571

572572
#### Output
573573

‎apps/sim/blocks/blocks/gauge.ts‎

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ export const GaugeBlock: BlockConfig = {
568568
id: 'promptTrackingType',
569569
title: 'Tracking Type',
570570
type: 'dropdown',
571+
paramVisibility: 'user-or-llm',
571572
condition: {
572573
field: 'operation',
573574
value: ['gauge_bulk_update_prompts', 'gauge_update_prompt'],
@@ -776,6 +777,7 @@ export const GaugeBlock: BlockConfig = {
776777
id: 'metadataDataset',
777778
title: 'Dataset',
778779
type: 'dropdown',
780+
paramVisibility: 'user-or-llm',
779781
condition: { field: 'operation', value: 'gauge_get_query_metadata' },
780782
options: [
781783
{ label: 'All Datasets', id: 'all' },
@@ -969,27 +971,20 @@ export const GaugeBlock: BlockConfig = {
969971
config: {
970972
tool: (params) => params.operation,
971973
params: (params) => {
972-
const patch = ['gauge_bulk_update_prompts', 'gauge_update_prompt'].includes(
973-
params.operation
974-
)
975974
return {
976975
...params,
977976
limit: params.limit === '' || params.limit == null ? undefined : Number(params.limit),
978-
topic: params.operation === 'gauge_list_prompts' ? params.topicFilter : params.topic,
979-
topicId: patch && params.topicId === '' ? undefined : params.topicId,
980-
trackingType: patch
981-
? params.promptTrackingType === 'unchanged'
977+
topic: params.topicFilter ?? params.topic,
978+
topicId: params.topicId === '' ? undefined : params.topicId,
979+
trackingType:
980+
params.promptTrackingType === 'unchanged'
982981
? undefined
983-
: params.promptTrackingType
984-
: params.trackingType,
985-
name:
986-
params.operation === 'gauge_update_tag' && params.name === '' ? undefined : params.name,
982+
: (params.promptTrackingType ?? params.trackingType),
983+
name: params.name === '' ? undefined : params.name,
987984
dataset:
988-
params.operation === 'gauge_get_query_metadata'
989-
? params.metadataDataset === 'all'
990-
? undefined
991-
: params.metadataDataset
992-
: params.dataset,
985+
params.metadataDataset === 'all'
986+
? undefined
987+
: (params.metadataDataset ?? params.dataset),
993988
}
994989
},
995990
},

‎apps/sim/providers/utils.test.ts‎

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ vi.mock('@/lib/internal/workflows/read-tool-enrichment', () => ({
1212
}))
1313

1414
import { getParamsForToolOperation } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/param-dependents'
15+
import { GaugeBlock } from '@/blocks/blocks/gauge'
1516
import { GreenhouseV2Block } from '@/blocks/blocks/greenhouse'
1617
import { IntuneBlock } from '@/blocks/blocks/intune'
1718
import { MicrosoftExcelV2Block } from '@/blocks/blocks/microsoft_excel'
@@ -46,6 +47,14 @@ import {
4647
transformBlockTool,
4748
} from '@/providers/utils'
4849
import { useProvidersStore } from '@/stores/providers/store'
50+
import { gaugeGetQueryMetadataTool } from '@/tools/gauge/get_query_metadata'
51+
import { gaugeListPromptsTool } from '@/tools/gauge/list_prompts'
52+
import type {
53+
GaugeGetQueryMetadataParams,
54+
GaugeListPromptsParams,
55+
GaugeUpdatePromptParams,
56+
} from '@/tools/gauge/types'
57+
import { gaugeUpdatePromptTool } from '@/tools/gauge/update_prompt'
4958
import { greenhouseConvertProspectV2Tool } from '@/tools/greenhouse/convert_prospect_v2'
5059
import { greenhouseCreateApplicationV2Tool } from '@/tools/greenhouse/create_application_v2'
5160
import { greenhouseHireApplicationV2Tool } from '@/tools/greenhouse/hire_application_v2'
@@ -79,6 +88,137 @@ const mockGetRotatingApiKey = vi.fn().mockReturnValue('rotating-server-key')
7988
const originalRequire = module.require
8089

8190
describe('integration filters through agent execution', () => {
91+
it.each(['configured', 'model'] as const)(
92+
'retains the %s Gauge topic filter without a stored operation',
93+
async (source) => {
94+
const tool = gaugeListPromptsTool
95+
vi.spyOn(toolMetadata, 'getToolMetadata').mockReturnValue(tool)
96+
const field = getSubBlocksForToolInput(
97+
tool.id,
98+
'gauge',
99+
{ operation: tool.id },
100+
undefined,
101+
GaugeBlock
102+
)?.subBlocks.find((item) => item.canonicalParamId === 'topicFilter')
103+
if (!field) throw new Error('Gauge topic filter control is unavailable')
104+
const providerTool = await transformBlockTool(
105+
{
106+
type: 'gauge',
107+
params: {
108+
org: 'example',
109+
category: 'example',
110+
...(source === 'configured' ? { [field.id]: 'top_configured' } : {}),
111+
},
112+
},
113+
{ selectedOperation: tool.id, getAllBlocks: () => [GaugeBlock], getTool: () => tool }
114+
)
115+
if (!providerTool) throw new Error('Gauge agent tool was not created')
116+
const { executionParams } = prepareToolExecution(
117+
providerTool,
118+
{ topic: 'top_model' },
119+
{},
120+
undefined
121+
)
122+
const params = { ...executionParams, accessToken: 'fixture-token' } as GaugeListPromptsParams
123+
const url =
124+
typeof tool.request.url === 'function' ? tool.request.url(params) : tool.request.url
125+
expect(new URL(url).searchParams.get('topic')).toBe(
126+
source === 'configured' ? 'top_configured' : 'top_model'
127+
)
128+
}
129+
)
130+
131+
it.each(['configured', 'unchanged', 'model'] as const)(
132+
'retains %s Gauge tracking intent without a stored operation',
133+
async (source) => {
134+
const tool = gaugeUpdatePromptTool
135+
vi.spyOn(toolMetadata, 'getToolMetadata').mockReturnValue(tool)
136+
const field = getSubBlocksForToolInput(
137+
tool.id,
138+
'gauge',
139+
{ operation: tool.id },
140+
undefined,
141+
GaugeBlock
142+
)?.subBlocks.find((item) => item.id === 'promptTrackingType')
143+
if (!field && source !== 'model') throw new Error('Gauge tracking control is unavailable')
144+
const providerTool = await transformBlockTool(
145+
{
146+
type: 'gauge',
147+
params: {
148+
org: 'example',
149+
category: 'example',
150+
promptId: 'prompt_example',
151+
...(field && source !== 'model'
152+
? { [field.id]: source === 'unchanged' ? 'unchanged' : 'visibility' }
153+
: {}),
154+
},
155+
},
156+
{ selectedOperation: tool.id, getAllBlocks: () => [GaugeBlock], getTool: () => tool }
157+
)
158+
if (!providerTool) throw new Error('Gauge agent tool was not created')
159+
const { executionParams } = prepareToolExecution(
160+
providerTool,
161+
{ trackingType: 'branded_own' },
162+
{},
163+
undefined
164+
)
165+
const params = { ...executionParams, accessToken: 'fixture-token' } as GaugeUpdatePromptParams
166+
expect(tool.request.body?.(params)).toEqual({
167+
topicId: undefined,
168+
trackingType:
169+
source === 'unchanged'
170+
? undefined
171+
: source === 'configured'
172+
? 'visibility'
173+
: 'branded_own',
174+
})
175+
}
176+
)
177+
178+
it.each(['configured', 'all', 'model'] as const)(
179+
'retains %s Gauge catalog intent without a stored operation',
180+
async (source) => {
181+
const tool = gaugeGetQueryMetadataTool
182+
vi.spyOn(toolMetadata, 'getToolMetadata').mockReturnValue(tool)
183+
const field = getSubBlocksForToolInput(
184+
tool.id,
185+
'gauge',
186+
{ operation: tool.id },
187+
undefined,
188+
GaugeBlock
189+
)?.subBlocks.find((item) => item.id === 'metadataDataset')
190+
if (!field && source !== 'model') throw new Error('Gauge catalog control is unavailable')
191+
const providerTool = await transformBlockTool(
192+
{
193+
type: 'gauge',
194+
params: {
195+
org: 'example',
196+
...(field && source !== 'model'
197+
? { [field.id]: source === 'all' ? 'all' : 'citations' }
198+
: {}),
199+
},
200+
},
201+
{ selectedOperation: tool.id, getAllBlocks: () => [GaugeBlock], getTool: () => tool }
202+
)
203+
if (!providerTool) throw new Error('Gauge agent tool was not created')
204+
const { executionParams } = prepareToolExecution(
205+
providerTool,
206+
{ dataset: 'aiTraffic' },
207+
{},
208+
undefined
209+
)
210+
const params = {
211+
...executionParams,
212+
accessToken: 'fixture-token',
213+
} as GaugeGetQueryMetadataParams
214+
const url =
215+
typeof tool.request.url === 'function' ? tool.request.url(params) : tool.request.url
216+
expect(new URL(url).searchParams.get('dataset')).toBe(
217+
source === 'all' ? null : source === 'configured' ? 'citations' : 'aiTraffic'
218+
)
219+
}
220+
)
221+
82222
it.each([
83223
{
84224
operation: 'list_jobs',

‎apps/sim/tools/gauge/create_prompts.ts‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,15 @@ function selectGaugePromptText(params: { prompts: unknown }): Record<string, unk
6060
/** Rebuilds the original JSON representation after the shared executor projects prompt text. */
6161
function rebuildGaugePrompts(original: unknown, projectedText: unknown): string | GaugePromptIn[] {
6262
const prompts = parseGaugePrompts(original)
63-
if (
64-
!Array.isArray(projectedText) ||
65-
projectedText.length !== prompts.length ||
66-
projectedText.some((text) => typeof text !== 'string')
67-
) {
63+
if (!Array.isArray(projectedText) || projectedText.length !== prompts.length) {
6864
throw new Error('Projected Gauge prompts must match the original prompt batch')
6965
}
70-
const texts = parseGaugeStringArray(projectedText, 'Projected prompt text')
66+
const texts = projectedText.map((text: unknown) => {
67+
if (typeof text !== 'string') {
68+
throw new Error('Projected Gauge prompts must match the original prompt batch')
69+
}
70+
return text
71+
})
7172
const rebuilt = prompts.map((prompt, index) => ({ ...prompt, text: texts[index] ?? '' }))
7273
return typeof original === 'string' ? JSON.stringify(rebuilt) : rebuilt
7374
}

‎apps/sim/tools/gauge/update_tag.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export const gaugeUpdateTagTool: ToolConfig<GaugeUpdateTagParams, GaugeUpdateTag
2929
type: 'string',
3030
required: false,
3131
visibility: 'user-or-llm',
32-
description: 'Tag color string (up to 20 characters)',
32+
description:
33+
'Tag color string (up to 20 characters); omit to keep unchanged or use "" to clear',
3334
},
3435
},
3536
request: {

‎apps/sim/tools/gauge/utils.test.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ describe('Gauge request encoding', () => {
3333
expect(() => parseGaugeStringArray([], 'ids', { min: 1, max: 500 })).toThrow()
3434
expect(() => parseGaugeStringArray(['a', 'b'], 'tagIds', { max: 1 })).toThrow()
3535
})
36+
37+
it.each(['', ' '])('rejects a blank identifier %j instead of sending it to Gauge', (value) => {
38+
expect(() => parseGaugeStringArray([value], 'ids', { min: 1 })).toThrow()
39+
expect(parseGaugeStringArray([' padded-but-nonblank '], 'ids')).toEqual([
40+
' padded-but-nonblank ',
41+
])
42+
})
3643
})
3744

3845
const modelInput = gaugeCreatePromptsTool.request.modelInput

‎apps/sim/tools/gauge/utils.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,16 @@ export function parseGaugeJson(value: unknown, name: string): unknown {
5252
}
5353
}
5454

55-
/** Validates string arrays arriving directly or as JSON from a block field. */
55+
/** Validates nonblank string arrays without changing the supplied values. */
5656
export function parseGaugeStringArray(
5757
value: unknown,
5858
name: string,
5959
bounds: { min?: number; max?: number } = {}
6060
): string[] {
6161
const parsed = parseGaugeJson(value, name)
6262
if (parsed == null && !bounds.min) return []
63-
if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== 'string')) {
64-
throw new Error(`${name} must be a JSON array of strings`)
63+
if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== 'string' || !item.trim())) {
64+
throw new Error(`${name} must be a JSON array of non-empty strings`)
6565
}
6666
if (
6767
(bounds.min !== undefined && parsed.length < bounds.min) ||

‎apps/sim/tools/generated/tool-metadata.ts‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)