Skip to content

Commit 68f9812

Browse files
committed
add 2 levels deep nested model
1 parent 5953bb7 commit 68f9812

File tree

1 file changed

+49
-4
lines changed

1 file changed

+49
-4
lines changed

src/providers/google-vertex-ai/utils.test.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ class StatusEnum(StrEnum):
1010
INACTIVE = "INACTIVE"
1111
BANNED = "BANNED"
1212
13+
class PostalAddress(BaseModel):
14+
line1: str
15+
line2: str | None = None
16+
city: str
17+
country: str
18+
1319
class ContactInfo(BaseModel):
1420
email: str = Field(..., description="User's email address")
1521
phone: str | None = Field(None, description="Phone number (E.164 format)")
16-
address: str = Field(..., description="Address")
22+
address: PostalAddress = Field(..., description="Address")
1723
1824
class Job(BaseModel):
1925
title: str
@@ -93,9 +99,8 @@ const userProfileSchema = {
9399
title: 'Phone',
94100
},
95101
address: {
102+
$ref: '#/$defs/PostalAddress',
96103
description: 'Address',
97-
title: 'Address',
98-
type: 'string',
99104
},
100105
},
101106
required: ['email', 'address'],
@@ -238,6 +243,21 @@ const userProfileSchema = {
238243
title: 'Pet',
239244
type: 'object',
240245
},
246+
PostalAddress: {
247+
properties: {
248+
line1: { title: 'Line1', type: 'string' },
249+
line2: {
250+
anyOf: [{ type: 'string' }, { type: 'null' }],
251+
default: null,
252+
title: 'Line2',
253+
},
254+
city: { title: 'City', type: 'string' },
255+
country: { title: 'Country', type: 'string' },
256+
},
257+
required: ['line1', 'city', 'country'],
258+
title: 'PostalAddress',
259+
type: 'object',
260+
},
241261
Preferences: {
242262
properties: {
243263
newsletter_subscribed: {
@@ -420,7 +440,19 @@ describe('derefer', () => {
420440
it('inlines $ref for nested object property (contact)', () => {
421441
expect(derefed.properties.contact.type).toBe('object');
422442
expect(derefed.properties.contact.properties.email.type).toBe('string');
423-
expect(derefed.properties.contact.properties.address.type).toBe('string');
443+
expect(derefed.properties.contact.properties.address.type).toBe('object');
444+
});
445+
446+
it('inlines $ref for nested model inside ContactInfo (address -> PostalAddress)', () => {
447+
const contact = derefed.properties.contact;
448+
expect(contact.type).toBe('object');
449+
450+
const addr = contact.properties.address;
451+
// PostalAddress should be fully inlined
452+
expect(addr.type).toBe('object');
453+
expect(addr.properties.line1.type).toBe('string');
454+
expect(addr.properties.city.type).toBe('string');
455+
expect(addr.properties.country.type).toBe('string');
424456
});
425457

426458
it('inlines $ref for enum via $defs (status)', () => {
@@ -522,6 +554,19 @@ describe('transformGeminiToolParameters', () => {
522554
});
523555
});
524556

557+
it('keeps nested model flattened correctly after deref (contact.address)', () => {
558+
const addr = transformed.properties.contact.properties.address;
559+
expect(addr.type).toBe('object');
560+
expect(addr.properties.line1.type).toBe('string');
561+
// line2 remains nullable string
562+
expect(addr.properties.line2).toEqual({
563+
type: 'string',
564+
nullable: true,
565+
title: 'Line2',
566+
default: null,
567+
});
568+
});
569+
525570
it('flattens anyOf [array-of-model, null] to array schema with nullable: true and preserves metadata (pets)', () => {
526571
const pets = transformed.properties.pets;
527572
expect(pets.type).toBe('array');

0 commit comments

Comments
 (0)