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+ } finally {
100+ await agent . close ( )
101+ }
102+ }
103+
104+ // Handle unhandled promise rejections
105+ process . on ( 'unhandledRejection' , ( reason , promise ) => {
106+ console . error ( 'Unhandled Rejection at:' , promise , 'reason:' , reason )
107+ process . exit ( 1 )
108+ } )
109+
110+ main ( ) . catch ( console . error )
0 commit comments