Skip to content

Commit 99c92fd

Browse files
committed
fix(browser): align form schemas and activity titles
1 parent c3d2981 commit 99c92fd

5 files changed

Lines changed: 127 additions & 16 deletions

File tree

apps/sim/lib/copilot/generated/tool-catalog-v1.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -819,48 +819,71 @@ export const BrowserFillForm: ToolCatalogEntry = {
819819
route: 'client',
820820
mode: 'async',
821821
parameters: {
822-
type: 'object',
822+
additionalProperties: false,
823823
properties: {
824824
fields: {
825-
type: 'array',
826825
description:
827826
"Ordered list of 1–8 fields with unique elementId refs from the current top page's latest snapshot. Supply exactly one matching value parameter per kind.",
828827
items: {
829-
type: 'object',
828+
oneOf: [
829+
{
830+
additionalProperties: false,
831+
properties: { elementId: {}, kind: { enum: ['text'] }, text: {} },
832+
required: ['text'],
833+
},
834+
{
835+
additionalProperties: false,
836+
properties: { elementId: {}, kind: { enum: ['select'] }, value: {} },
837+
required: ['value'],
838+
},
839+
{
840+
additionalProperties: false,
841+
properties: { checked: {}, elementId: {}, kind: { enum: ['checked'] } },
842+
required: ['checked'],
843+
},
844+
],
830845
properties: {
831846
checked: {
832-
type: 'boolean',
833847
description:
834848
'Desired state for kind=checked. A radio can only be set true; native checkboxes may be true or false.',
849+
type: 'boolean',
835850
},
836851
elementId: {
837-
type: 'number',
838852
description:
839853
"Nonnegative integer element ref from the current page's latest snapshot.",
854+
maximum: 9007199254740991,
855+
minimum: 0,
856+
type: 'integer',
840857
},
841858
kind: {
842-
type: 'string',
843859
description:
844860
'text requires text; select requires value; checked requires checked. Do not supply parameters for another kind.',
845861
enum: ['text', 'select', 'checked'],
862+
type: 'string',
846863
},
847864
text: {
848-
type: 'string',
849865
description:
850866
'Replacement content for kind=text, including empty to clear. At most 4096 characters. Ordinary input or textarea only.',
867+
maxLength: 4096,
868+
type: 'string',
851869
},
852870
value: {
853-
type: 'string',
854871
description:
855872
'Option value or visible label for kind=select. At most 4096 characters. Native single-selection dropdown only.',
873+
maxLength: 4096,
874+
type: 'string',
856875
},
857876
},
858877
required: ['elementId', 'kind'],
878+
type: 'object',
859879
},
860880
maxItems: 8,
881+
minItems: 1,
882+
type: 'array',
861883
},
862884
},
863885
required: ['fields'],
886+
type: 'object',
864887
},
865888
resultSchema: {
866889
type: 'object',

apps/sim/lib/copilot/generated/tool-schemas-v1.ts

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -614,48 +614,89 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
614614
},
615615
browser_fill_form: {
616616
parameters: {
617-
type: 'object',
617+
additionalProperties: false,
618618
properties: {
619619
fields: {
620-
type: 'array',
621620
description:
622621
"Ordered list of 1–8 fields with unique elementId refs from the current top page's latest snapshot. Supply exactly one matching value parameter per kind.",
623622
items: {
624-
type: 'object',
623+
oneOf: [
624+
{
625+
additionalProperties: false,
626+
properties: {
627+
elementId: {},
628+
kind: {
629+
enum: ['text'],
630+
},
631+
text: {},
632+
},
633+
required: ['text'],
634+
},
635+
{
636+
additionalProperties: false,
637+
properties: {
638+
elementId: {},
639+
kind: {
640+
enum: ['select'],
641+
},
642+
value: {},
643+
},
644+
required: ['value'],
645+
},
646+
{
647+
additionalProperties: false,
648+
properties: {
649+
checked: {},
650+
elementId: {},
651+
kind: {
652+
enum: ['checked'],
653+
},
654+
},
655+
required: ['checked'],
656+
},
657+
],
625658
properties: {
626659
checked: {
627-
type: 'boolean',
628660
description:
629661
'Desired state for kind=checked. A radio can only be set true; native checkboxes may be true or false.',
662+
type: 'boolean',
630663
},
631664
elementId: {
632-
type: 'number',
633665
description:
634666
"Nonnegative integer element ref from the current page's latest snapshot.",
667+
maximum: 9007199254740991,
668+
minimum: 0,
669+
type: 'integer',
635670
},
636671
kind: {
637-
type: 'string',
638672
description:
639673
'text requires text; select requires value; checked requires checked. Do not supply parameters for another kind.',
640674
enum: ['text', 'select', 'checked'],
675+
type: 'string',
641676
},
642677
text: {
643-
type: 'string',
644678
description:
645679
'Replacement content for kind=text, including empty to clear. At most 4096 characters. Ordinary input or textarea only.',
680+
maxLength: 4096,
681+
type: 'string',
646682
},
647683
value: {
648-
type: 'string',
649684
description:
650685
'Option value or visible label for kind=select. At most 4096 characters. Native single-selection dropdown only.',
686+
maxLength: 4096,
687+
type: 'string',
651688
},
652689
},
653690
required: ['elementId', 'kind'],
691+
type: 'object',
654692
},
655693
maxItems: 8,
694+
minItems: 1,
695+
type: 'array',
656696
},
657697
},
658698
required: ['fields'],
699+
type: 'object',
659700
},
660701
resultSchema: {
661702
type: 'object',

apps/sim/lib/copilot/tools/server/generated-schema.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,45 @@ import { describe, expect, it } from 'vitest'
55
import { validateGeneratedToolPayload } from '@/lib/copilot/tools/server/generated-schema'
66
import { OrchestrationError } from '@/lib/core/orchestration/types'
77

8+
describe('validateGeneratedToolPayload browser_fill_form parameters', () => {
9+
it('accepts mixed fields, including empty text and false checked state', () => {
10+
const payload = {
11+
fields: [
12+
{ elementId: 0, kind: 'text', text: '' },
13+
{ elementId: 1, kind: 'select', value: 'pro' },
14+
{ elementId: 2, kind: 'checked', checked: false },
15+
],
16+
}
17+
expect(validateGeneratedToolPayload('browser_fill_form', 'parameters', payload)).toBe(payload)
18+
})
19+
20+
it.each([
21+
{ fields: [] },
22+
{
23+
fields: Array.from({ length: 9 }, (_, elementId) => ({ elementId, kind: 'text', text: '' })),
24+
},
25+
{ fields: [{ elementId: 1, kind: 'text' }] },
26+
{ fields: [{ elementId: 1, kind: 'select' }] },
27+
{ fields: [{ elementId: 1, kind: 'checked' }] },
28+
{ fields: [{ elementId: 1, kind: 'text', text: 'a', value: 'a' }] },
29+
{ fields: [{ elementId: 1, kind: 'select', value: 'a', checked: false }] },
30+
{ fields: [{ elementId: 1, kind: 'checked', checked: false, text: '' }] },
31+
{ fields: [{ elementId: 1, kind: 'checked', checked: 'false' }] },
32+
{ fields: [{ elementId: 1, kind: 'text', text: null }] },
33+
{ fields: [{ elementId: 1, kind: 'text', text: '', submit: true }] },
34+
{ fields: [{ elementId: -1, kind: 'text', text: '' }] },
35+
{ fields: [{ elementId: 1.5, kind: 'text', text: '' }] },
36+
{ fields: [{ elementId: Number.MAX_SAFE_INTEGER + 1, kind: 'text', text: '' }] },
37+
{ fields: [{ elementId: 1, kind: 'text', text: 'a'.repeat(4097) }] },
38+
{ fields: [{ elementId: 1, kind: 'select', value: 'a'.repeat(4097) }] },
39+
{ fields: [{ elementId: 1, kind: 'text', text: '' }], submit: true },
40+
])('rejects malformed form payload %# through the generated contract', (payload) => {
41+
expect(() => validateGeneratedToolPayload('browser_fill_form', 'parameters', payload)).toThrow(
42+
OrchestrationError
43+
)
44+
})
45+
})
46+
847
/**
948
* The shapes below are what an agent actually sent when the catalog advertised
1049
* `updates` as a bare array: the provider-path sanitizer filled the missing

apps/sim/lib/copilot/tools/tool-display.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,12 @@ describe('resource-naming titles', () => {
763763
})
764764

765765
it('describes semantic browser controls without exposing element ids', () => {
766+
expect(
767+
getToolDisplayTitle('browser_fill_form', {
768+
fields: [{ elementId: 42, kind: 'text', text: 'private form content' }],
769+
})
770+
).toBe('Filling form')
771+
expect(getToolCompletedTitle('Filling form')).toBe('Filled form')
766772
expect(getToolDisplayTitle('browser_find', { query: 'Submit order' })).toBe(
767773
'Finding "Submit order"'
768774
)

apps/sim/lib/copilot/tools/tool-display.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ const TOOL_TITLES: Record<string, string> = {
635635

636636
browser_drag: 'Dragging element',
637637
browser_select_option: 'Selecting option',
638+
browser_fill_form: 'Filling form',
638639
browser_set_checked: 'Updating control',
639640
browser_hover: 'Hovering element',
640641
browser_zoom: 'Changing page zoom',
@@ -1332,6 +1333,7 @@ const COMPLETED_VERB_REWRITES: Record<string, string> = {
13321333
Extracting: 'Extracted',
13331334
Fading: 'Faded',
13341335
Finding: 'Found',
1336+
Filling: 'Filled',
13351337
Gathering: 'Gathered',
13361338
Generating: 'Generated',
13371339
Going: 'Went',

0 commit comments

Comments
 (0)