Skip to content

Commit 7262270

Browse files
authored
feat: structured output
feat: structured output
2 parents c38012e + edbe528 commit 7262270

File tree

3 files changed

+355
-11
lines changed

3 files changed

+355
-11
lines changed

examples/structured_output.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* Structured Output Example - City Research with Playwright
3+
*
4+
* This example demonstrates intelligent structured output by researching Padova, Italy.
5+
* The agent becomes schema-aware and will intelligently retry to gather missing
6+
* information until all required fields can be populated.
7+
*/
8+
9+
import { ChatOpenAI } from '@langchain/openai'
10+
import { config } from 'dotenv'
11+
import { z } from 'zod'
12+
import { MCPAgent, MCPClient } from '../index.js'
13+
14+
// Load environment variables from .env file
15+
config()
16+
17+
// Define the structured output schema using Zod
18+
const CityInfoSchema = z.object({
19+
name: z.string().describe('Official name of the city'),
20+
country: z.string().describe('Country where the city is located'),
21+
region: z.string().describe('Region or state within the country'),
22+
population: z.number().describe('Current population count'),
23+
area_km2: z.number().describe('Area in square kilometers'),
24+
foundation_date: z.string().describe('When the city was founded (approximate year or period)'),
25+
mayor: z.string().describe('Current mayor or city leader'),
26+
famous_landmarks: z.array(z.string()).describe('List of famous landmarks, monuments, or attractions'),
27+
universities: z.array(z.string()).describe('List of major universities or educational institutions'),
28+
economy_sectors: z.array(z.string()).describe('Main economic sectors or industries'),
29+
sister_cities: z.array(z.string()).describe('Twin cities or sister cities partnerships'),
30+
historical_significance: z.string().describe('Brief description of historical importance'),
31+
climate_type: z.string().nullable().describe('Type of climate (e.g., Mediterranean, Continental)'),
32+
elevation_meters: z.number().nullable().describe('Elevation above sea level in meters'),
33+
})
34+
35+
type CityInfo = z.infer<typeof CityInfoSchema>
36+
37+
async function main() {
38+
const mcpConfig = {
39+
mcpServers: {
40+
playwright: {
41+
command: 'npx',
42+
args: ['@playwright/mcp@latest'],
43+
env: {
44+
DISPLAY: ':1',
45+
},
46+
},
47+
},
48+
}
49+
50+
const client = new MCPClient(mcpConfig)
51+
const llm = new ChatOpenAI({ model: 'gpt-4o' })
52+
const agent = new MCPAgent({ llm, client, maxSteps: 50, memoryEnabled: true })
53+
54+
try {
55+
// Use structured output with intelligent retry
56+
// The agent will:
57+
// 1. Know exactly what information it needs to collect
58+
// 2. Attempt structured output at finish points
59+
// 3. Continue execution if required information is missing
60+
// 4. Only finish when all required fields can be populated
61+
const result: CityInfo = await agent.run(
62+
`
63+
Research comprehensive information about the city of Padova (also known as Padua) in Italy.
64+
65+
Visit multiple reliable sources like Wikipedia, official city websites, tourism sites,
66+
and university websites to gather detailed information including demographics, history,
67+
governance, education, economy, landmarks, and international relationships.
68+
`,
69+
50, // maxSteps
70+
true, // manageConnector
71+
[], // externalHistory
72+
CityInfoSchema, // outputSchema - this enables structured output
73+
)
74+
75+
// Now you have strongly-typed, validated data!
76+
console.log(`Name: ${result.name}`)
77+
console.log(`Country: ${result.country}`)
78+
console.log(`Region: ${result.region}`)
79+
console.log(`Population: ${result.population.toLocaleString()}`)
80+
console.log(`Area: ${result.area_km2} km²`)
81+
console.log(`Foundation: ${result.foundation_date}`)
82+
console.log(`Mayor: ${result.mayor}`)
83+
console.log(`Universities: ${result.universities.join(', ')}`)
84+
console.log(`Economy: ${result.economy_sectors.join(', ')}`)
85+
console.log(`Landmarks: ${result.famous_landmarks.join(', ')}`)
86+
console.log(`Sister Cities: ${result.sister_cities.length > 0 ? result.sister_cities.join(', ') : 'None'}`)
87+
console.log(`Historical Significance: ${result.historical_significance}`)
88+
89+
if (result.climate_type) {
90+
console.log(`Climate: ${result.climate_type}`)
91+
}
92+
93+
if (result.elevation_meters !== null) {
94+
console.log(`Elevation: ${result.elevation_meters} meters`)
95+
}
96+
}
97+
catch (error) {
98+
console.error('Error:', error)
99+
}
100+
finally {
101+
await agent.close()
102+
}
103+
}
104+
105+
// Handle unhandled promise rejections
106+
process.on('unhandledRejection', (reason, promise) => {
107+
console.error('Unhandled Rejection at:', promise, 'reason:', reason)
108+
process.exit(1)
109+
})
110+
111+
main().catch(console.error)

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@
7373
"example:sandbox": "npm run build && node dist/examples/sandbox_everything.js",
7474
"example:oauth": "npm run build && node dist/examples/simple_oauth_example.js",
7575
"example:blender": "npm run build && node dist/examples/blender_use.js",
76-
"example:add_server": "npm run build && node dist/examples/add_server_tool.js"
76+
"example:add_server": "npm run build && node dist/examples/add_server_tool.js",
77+
"example:structured": "npm run build && node dist/examples/structured_output.js"
7778
},
7879
"dependencies": {
7980
"@dmitryrechkin/json-schema-to-zod": "^1.0.1",

0 commit comments

Comments
 (0)