@assertrx/dino 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -6
- package/package.json +1 -1
- package/prompts/generate-pom-from-url-cli.md +9 -10
- package/prompts/generate-pom-from-url.md +9 -9
- package/scripts/.playwright-mcp/console-2026-08-27T18-21-56-124Z.log +2 -0
- package/scripts/.playwright-mcp/page-2026-08-27T18-21-56-619Z.yml +52 -0
- package/scripts/.playwright-mcp/page-2026-08-27T18-22-09-918Z.yml +468 -0
- package/scripts/.playwright-mcp/page-2026-08-27T18-22-18-028Z.yml +867 -0
- package/scripts/.playwright-mcp/page-2026-08-27T18-22-26-737Z.yml +34 -0
- package/scripts/.playwright-mcp/page-2026-08-27T18-22-45-030Z.yml +52 -0
- package/scripts/.playwright-mcp/page-2026-08-27T18-22-50-830Z.yml +203 -0
- package/scripts/api-server.mjs +202 -14
- package/scripts/setup-dino-api.bat +31 -24
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
- generic [ref=f10e2]:
|
|
2
|
+
- navigation [ref=f10e3]:
|
|
3
|
+
- generic [ref=f10e8]:
|
|
4
|
+
- button "Google apps" [ref=f10e12] [cursor=pointer]
|
|
5
|
+
- link "Sign in" [ref=f10e16] [cursor=pointer]:
|
|
6
|
+
- /url: https://accounts.google.com/ServiceLogin?hl=en&passive=true&continue=https://www.google.com/imghp%3Fhl%3Den&ec=GAZAAg
|
|
7
|
+
- generic [ref=f10e18]:
|
|
8
|
+
- img "Google Images" [ref=f10e19]
|
|
9
|
+
- generic [ref=f10e20]: Images
|
|
10
|
+
- search [ref=f10e22]:
|
|
11
|
+
- generic [ref=f10e24]:
|
|
12
|
+
- generic [ref=f10e26]:
|
|
13
|
+
- combobox "Search" [active] [ref=f10e33]
|
|
14
|
+
- generic [ref=f10e35]:
|
|
15
|
+
- button "Search by voice" [ref=f10e36] [cursor=pointer]
|
|
16
|
+
- button "Search by image" [ref=f10e39] [cursor=pointer]
|
|
17
|
+
- button "Google Search" [ref=f10e44] [cursor=pointer]
|
|
18
|
+
- contentinfo [ref=f10e47]:
|
|
19
|
+
- generic [ref=f10e48]:
|
|
20
|
+
- generic [ref=f10e49]:
|
|
21
|
+
- link "About" [ref=f10e50] [cursor=pointer]:
|
|
22
|
+
- /url: https://about.google/?utm_source=google-US&utm_medium=referral&utm_campaign=hp-footer&fg=1
|
|
23
|
+
- link "Advertising" [ref=f10e51] [cursor=pointer]:
|
|
24
|
+
- /url: https://www.google.com/intl/en_us/ads/?subid=ww-ww-et-g-awa-a-g_hpafoot1_1!o2&utm_source=google.com&utm_medium=referral&utm_campaign=google_hpafooter&fg=1
|
|
25
|
+
- link "Business" [ref=f10e52] [cursor=pointer]:
|
|
26
|
+
- /url: https://www.google.com/services/?subid=ww-ww-et-g-awa-a-g_hpbfoot1_1!o2&utm_source=google.com&utm_medium=referral&utm_campaign=google_hpbfooter&fg=1
|
|
27
|
+
- link "How Search works" [ref=f10e53] [cursor=pointer]:
|
|
28
|
+
- /url: https://google.com/search/howsearchworks/?fg=1
|
|
29
|
+
- generic [ref=f10e54]:
|
|
30
|
+
- link "Privacy" [ref=f10e55] [cursor=pointer]:
|
|
31
|
+
- /url: https://policies.google.com/privacy?hl=en&fg=1
|
|
32
|
+
- link "Terms" [ref=f10e56] [cursor=pointer]:
|
|
33
|
+
- /url: https://policies.google.com/terms?hl=en&fg=1
|
|
34
|
+
- button "Settings" [ref=f10e60] [cursor=pointer]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
- generic [ref=f11e2]:
|
|
2
|
+
- navigation [ref=f11e3]:
|
|
3
|
+
- link "About" [ref=f11e4] [cursor=pointer]:
|
|
4
|
+
- /url: https://about.google/?fg=1&utm_source=google-US&utm_medium=referral&utm_campaign=hp-header
|
|
5
|
+
- link "Store" [ref=f11e5] [cursor=pointer]:
|
|
6
|
+
- /url: https://store.google.com/US?utm_source=hp_header&utm_medium=google_ooo&utm_campaign=GS100042&hl=en-US
|
|
7
|
+
- generic [ref=f11e7]:
|
|
8
|
+
- generic [ref=f11e8]:
|
|
9
|
+
- link "Gmail" [ref=f11e10] [cursor=pointer]:
|
|
10
|
+
- /url: https://mail.google.com/mail/&ogbl
|
|
11
|
+
- link "Search for Images" [ref=f11e12] [cursor=pointer]:
|
|
12
|
+
- /url: https://www.google.com/imghp?hl=en&ogbl
|
|
13
|
+
- text: Images
|
|
14
|
+
- button "Google apps" [ref=f11e15] [cursor=pointer]
|
|
15
|
+
- link "Sign in" [ref=f11e20] [cursor=pointer]:
|
|
16
|
+
- /url: https://accounts.google.com/ServiceLogin?hl=en&passive=true&continue=https://www.google.com/&ec=futura_exp_og_so_72776762_e
|
|
17
|
+
- generic [ref=f11e22]:
|
|
18
|
+
- link [ref=f11e24] [cursor=pointer]:
|
|
19
|
+
- /url: /search?sca_esv=b3cb815f54d8ec19&q=Which+National+Parks+have+some+of+the+most+scenic+overlooks%3F&udm=50&oi=ddle&noiga=1&ct=460148972&peek_pws=0&aep=84&sa=X&ved=0ahUKEwjx9MrgtsGWAxWpEVkFHdh1AvEQPQgH
|
|
20
|
+
- img "Celebrating National Park Week at Yosemite" [ref=f11e26]
|
|
21
|
+
- button "Share" [ref=f11e28]
|
|
22
|
+
- search [ref=f11e36]:
|
|
23
|
+
- generic [ref=f11e38]:
|
|
24
|
+
- generic [ref=f11e40]:
|
|
25
|
+
- button "Add files and tools" [ref=f11e45] [cursor=pointer]
|
|
26
|
+
- combobox "Search" [active] [ref=f11e50]
|
|
27
|
+
- generic [ref=f11e51]:
|
|
28
|
+
- generic [ref=f11e52]:
|
|
29
|
+
- button "Search by voice" [ref=f11e55] [cursor=pointer]
|
|
30
|
+
- button "Search by image" [ref=f11e60] [cursor=pointer]
|
|
31
|
+
- link "AI Mode" [ref=f11e63] [cursor=pointer]
|
|
32
|
+
- generic [ref=f11e76]:
|
|
33
|
+
- button "Google Search" [ref=f11e77] [cursor=pointer]
|
|
34
|
+
- button "I'm Feeling Lucky" [ref=f11e78] [cursor=pointer]
|
|
35
|
+
- 'link "Celebrate National Park Week: Explore Yosemite with Google 🌲" [ref=f11e88] [cursor=pointer]'
|
|
36
|
+
- contentinfo [ref=f11e90]:
|
|
37
|
+
- generic [ref=f11e91]:
|
|
38
|
+
- generic [ref=f11e92]:
|
|
39
|
+
- link "Advertising" [ref=f11e93] [cursor=pointer]:
|
|
40
|
+
- /url: https://www.google.com/intl/en_us/ads/?subid=ww-ww-et-g-awa-a-g_hpafoot1_1!o2&utm_source=google.com&utm_medium=referral&utm_campaign=google_hpafooter&fg=1
|
|
41
|
+
- link "Business" [ref=f11e94] [cursor=pointer]:
|
|
42
|
+
- /url: https://www.google.com/services/?subid=ww-ww-et-g-awa-a-g_hpbfoot1_1!o2&utm_source=google.com&utm_medium=referral&utm_campaign=google_hpbfooter&fg=1
|
|
43
|
+
- link "How Search works" [ref=f11e95] [cursor=pointer]:
|
|
44
|
+
- /url: https://google.com/search/howsearchworks/?fg=1
|
|
45
|
+
- link "Build, create, and do more with AI tools from Google" [ref=f11e97] [cursor=pointer]:
|
|
46
|
+
- /url: https://ai.google/helpful-tools/?utm_source=googlehpfooter&utm_medium=housepromos&utm_campaign=bottom-footer
|
|
47
|
+
- generic [ref=f11e98]:
|
|
48
|
+
- link "Privacy" [ref=f11e99] [cursor=pointer]:
|
|
49
|
+
- /url: https://policies.google.com/privacy?hl=en&fg=1
|
|
50
|
+
- link "Terms" [ref=f11e100] [cursor=pointer]:
|
|
51
|
+
- /url: https://policies.google.com/terms?hl=en&fg=1
|
|
52
|
+
- button "Settings" [ref=f11e104] [cursor=pointer]
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
- generic [ref=f11e2]:
|
|
2
|
+
- navigation [ref=f11e3]:
|
|
3
|
+
- link "About" [ref=f11e4] [cursor=pointer]:
|
|
4
|
+
- /url: https://about.google/?fg=1&utm_source=google-US&utm_medium=referral&utm_campaign=hp-header
|
|
5
|
+
- link "Store" [ref=f11e5] [cursor=pointer]:
|
|
6
|
+
- /url: https://store.google.com/US?utm_source=hp_header&utm_medium=google_ooo&utm_campaign=GS100042&hl=en-US
|
|
7
|
+
- generic [ref=f11e7]:
|
|
8
|
+
- generic [ref=f11e8]:
|
|
9
|
+
- link "Gmail" [ref=f11e10] [cursor=pointer]:
|
|
10
|
+
- /url: https://mail.google.com/mail/&ogbl
|
|
11
|
+
- link "Search for Images" [ref=f11e12] [cursor=pointer]:
|
|
12
|
+
- /url: https://www.google.com/imghp?hl=en&ogbl
|
|
13
|
+
- text: Images
|
|
14
|
+
- button "Google apps" [expanded] [ref=f11e15] [cursor=pointer]
|
|
15
|
+
- generic [ref=f11e19]:
|
|
16
|
+
- link "Sign in" [ref=f11e20] [cursor=pointer]:
|
|
17
|
+
- /url: https://accounts.google.com/ServiceLogin?hl=en&passive=true&continue=https://www.google.com/&ec=futura_exp_og_so_72776762_e
|
|
18
|
+
- iframe [active] [ref=f11e107]:
|
|
19
|
+
- complementary [ref=f12e7]:
|
|
20
|
+
- generic "Google apps" [ref=f12e8]:
|
|
21
|
+
- generic [ref=f12e9]:
|
|
22
|
+
- generic [ref=f12e10]:
|
|
23
|
+
- link "Sign in" [active] [ref=f12e11] [cursor=pointer]:
|
|
24
|
+
- /url: https://accounts.google.com/ServiceLogin?continue=https://www.google.com/?zx=1787854964982
|
|
25
|
+
- text: to arrange apps
|
|
26
|
+
- generic [ref=f12e12]:
|
|
27
|
+
- list [ref=f12e15]:
|
|
28
|
+
- listitem [ref=f12e16]:
|
|
29
|
+
- link "Account, row 1 of 5 and column 1 of 3 in the first section" [ref=f12e17] [cursor=pointer]:
|
|
30
|
+
- /url: https://myaccount.google.com/?utm_source=OGB&utm_medium=app
|
|
31
|
+
- generic [ref=f12e20]: Account
|
|
32
|
+
- listitem [ref=f12e21]:
|
|
33
|
+
- link "Search, row 1 of 5 and column 2 of 3 in the first section" [ref=f12e22] [cursor=pointer]:
|
|
34
|
+
- /url: https://www.google.com/
|
|
35
|
+
- generic [ref=f12e25]: Search
|
|
36
|
+
- listitem [ref=f12e26]:
|
|
37
|
+
- link "Maps, row 1 of 5 and column 3 of 3 in the first section" [ref=f12e27] [cursor=pointer]:
|
|
38
|
+
- /url: https://maps.google.com/
|
|
39
|
+
- generic [ref=f12e30]: Maps
|
|
40
|
+
- listitem [ref=f12e31]:
|
|
41
|
+
- link "YouTube, row 2 of 5 and column 1 of 3 in the first section" [ref=f12e32] [cursor=pointer]:
|
|
42
|
+
- /url: https://www.youtube.com
|
|
43
|
+
- generic [ref=f12e35]: YouTube
|
|
44
|
+
- listitem [ref=f12e36]:
|
|
45
|
+
- link "News, row 2 of 5 and column 2 of 3 in the first section" [ref=f12e37] [cursor=pointer]:
|
|
46
|
+
- /url: https://news.google.com
|
|
47
|
+
- generic [ref=f12e40]: News
|
|
48
|
+
- listitem [ref=f12e41]:
|
|
49
|
+
- link "Gmail, row 2 of 5 and column 3 of 3 in the first section" [ref=f12e42] [cursor=pointer]:
|
|
50
|
+
- /url: https://mail.google.com/mail/
|
|
51
|
+
- generic [ref=f12e45]: Gmail
|
|
52
|
+
- listitem [ref=f12e46]:
|
|
53
|
+
- link "Meet, row 3 of 5 and column 1 of 3 in the first section" [ref=f12e47] [cursor=pointer]:
|
|
54
|
+
- /url: https://meet.google.com?hs=197
|
|
55
|
+
- generic [ref=f12e50]: Meet
|
|
56
|
+
- listitem [ref=f12e51]:
|
|
57
|
+
- link "Chat, row 3 of 5 and column 2 of 3 in the first section" [ref=f12e52] [cursor=pointer]:
|
|
58
|
+
- /url: https://chat.google.com
|
|
59
|
+
- generic [ref=f12e55]: Chat
|
|
60
|
+
- listitem [ref=f12e56]:
|
|
61
|
+
- link "Contacts, row 3 of 5 and column 3 of 3 in the first section" [ref=f12e57] [cursor=pointer]:
|
|
62
|
+
- /url: https://contacts.google.com/
|
|
63
|
+
- generic [ref=f12e60]: Contacts
|
|
64
|
+
- listitem [ref=f12e61]:
|
|
65
|
+
- link "Drive, row 4 of 5 and column 1 of 3 in the first section" [ref=f12e62] [cursor=pointer]:
|
|
66
|
+
- /url: https://drive.google.com/
|
|
67
|
+
- generic [ref=f12e65]: Drive
|
|
68
|
+
- listitem [ref=f12e66]:
|
|
69
|
+
- link "Calendar, row 4 of 5 and column 2 of 3 in the first section" [ref=f12e67] [cursor=pointer]:
|
|
70
|
+
- /url: https://calendar.google.com/calendar
|
|
71
|
+
- generic [ref=f12e70]: Calendar
|
|
72
|
+
- listitem [ref=f12e71]:
|
|
73
|
+
- link "Play, row 4 of 5 and column 3 of 3 in the first section" [ref=f12e72] [cursor=pointer]:
|
|
74
|
+
- /url: https://play.google.com/
|
|
75
|
+
- generic [ref=f12e75]: Play
|
|
76
|
+
- listitem [ref=f12e76]:
|
|
77
|
+
- link "Translate, row 5 of 5 and column 1 of 3 in the first section" [ref=f12e77] [cursor=pointer]:
|
|
78
|
+
- /url: https://translate.google.com/
|
|
79
|
+
- generic [ref=f12e80]: Translate
|
|
80
|
+
- listitem [ref=f12e81]:
|
|
81
|
+
- link "Photos, row 5 of 5 and column 2 of 3 in the first section" [ref=f12e82] [cursor=pointer]:
|
|
82
|
+
- /url: https://photos.google.com/
|
|
83
|
+
- generic [ref=f12e85]: Photos
|
|
84
|
+
- listitem [ref=f12e86]:
|
|
85
|
+
- link "Shopping, row 5 of 5 and column 3 of 3 in the first section" [ref=f12e87] [cursor=pointer]:
|
|
86
|
+
- /url: https://www.google.com/shopping?source=og
|
|
87
|
+
- generic [ref=f12e90]: Shopping
|
|
88
|
+
- list [ref=f12e93]:
|
|
89
|
+
- listitem [ref=f12e94]:
|
|
90
|
+
- link "Finance, row 1 of 7 and column 1 of 3 in the second section" [ref=f12e95] [cursor=pointer]:
|
|
91
|
+
- /url: https://www.google.com/finance
|
|
92
|
+
- generic [ref=f12e98]: Finance
|
|
93
|
+
- listitem [ref=f12e99]:
|
|
94
|
+
- link "Docs, row 1 of 7 and column 2 of 3 in the second section" [ref=f12e100] [cursor=pointer]:
|
|
95
|
+
- /url: https://docs.google.com/document/?usp=docs_alc
|
|
96
|
+
- generic [ref=f12e103]: Docs
|
|
97
|
+
- listitem [ref=f12e104]:
|
|
98
|
+
- link "Sheets, row 1 of 7 and column 3 of 3 in the second section" [ref=f12e105] [cursor=pointer]:
|
|
99
|
+
- /url: https://docs.google.com/spreadsheets/?usp=sheets_alc
|
|
100
|
+
- generic [ref=f12e108]: Sheets
|
|
101
|
+
- listitem [ref=f12e109]:
|
|
102
|
+
- link "Slides, row 2 of 7 and column 1 of 3 in the second section" [ref=f12e110] [cursor=pointer]:
|
|
103
|
+
- /url: https://docs.google.com/presentation/?usp=slides_alc
|
|
104
|
+
- generic [ref=f12e113]: Slides
|
|
105
|
+
- listitem [ref=f12e114]:
|
|
106
|
+
- link "Books, row 2 of 7 and column 2 of 3 in the second section" [ref=f12e115] [cursor=pointer]:
|
|
107
|
+
- /url: https://books.google.com/
|
|
108
|
+
- generic [ref=f12e118]: Books
|
|
109
|
+
- listitem [ref=f12e119]:
|
|
110
|
+
- link "Blogger, row 2 of 7 and column 3 of 3 in the second section" [ref=f12e120] [cursor=pointer]:
|
|
111
|
+
- /url: https://www.blogger.com/
|
|
112
|
+
- generic [ref=f12e123]: Blogger
|
|
113
|
+
- listitem [ref=f12e124]:
|
|
114
|
+
- link "Keep, row 3 of 7 and column 1 of 3 in the second section" [ref=f12e125] [cursor=pointer]:
|
|
115
|
+
- /url: https://keep.google.com
|
|
116
|
+
- generic [ref=f12e128]: Keep
|
|
117
|
+
- listitem [ref=f12e129]:
|
|
118
|
+
- link "Earth, row 3 of 7 and column 2 of 3 in the second section" [ref=f12e130] [cursor=pointer]:
|
|
119
|
+
- /url: https://earth.google.com/web/
|
|
120
|
+
- generic [ref=f12e133]: Earth
|
|
121
|
+
- listitem [ref=f12e134]:
|
|
122
|
+
- link "Saved, row 3 of 7 and column 3 of 3 in the second section" [ref=f12e135] [cursor=pointer]:
|
|
123
|
+
- /url: https://www.google.com/save
|
|
124
|
+
- generic [ref=f12e138]: Saved
|
|
125
|
+
- listitem [ref=f12e139]:
|
|
126
|
+
- link "Arts and Culture, row 4 of 7 and column 1 of 3 in the second section" [ref=f12e140] [cursor=pointer]:
|
|
127
|
+
- /url: https://artsandculture.google.com/?utm_source=ogs.google.com&utm_medium=referral
|
|
128
|
+
- generic [ref=f12e143]: Arts and Culture
|
|
129
|
+
- listitem [ref=f12e144]:
|
|
130
|
+
- link "Google Ads, row 4 of 7 and column 2 of 3 in the second section" [ref=f12e145] [cursor=pointer]:
|
|
131
|
+
- /url: https://ads.google.com/ups/routing?subid=ww-ww-xs-ip-awhc-a-ogb_cons!o2&source=203
|
|
132
|
+
- generic [ref=f12e148]: Google Ads
|
|
133
|
+
- listitem [ref=f12e149]:
|
|
134
|
+
- link "Merchant Center, row 4 of 7 and column 3 of 3 in the second section" [ref=f12e150] [cursor=pointer]:
|
|
135
|
+
- /url: https://merchants.google.com
|
|
136
|
+
- generic [ref=f12e153]: Merchant Center
|
|
137
|
+
- listitem [ref=f12e154]:
|
|
138
|
+
- link "Travel, row 5 of 7 and column 1 of 3 in the second section" [ref=f12e155] [cursor=pointer]:
|
|
139
|
+
- /url: https://www.google.com/travel/?dest_src=al
|
|
140
|
+
- generic [ref=f12e158]: Travel
|
|
141
|
+
- listitem [ref=f12e159]:
|
|
142
|
+
- link "Forms, row 5 of 7 and column 2 of 3 in the second section" [ref=f12e160] [cursor=pointer]:
|
|
143
|
+
- /url: https://docs.google.com/forms/
|
|
144
|
+
- generic [ref=f12e163]: Forms
|
|
145
|
+
- listitem [ref=f12e164]:
|
|
146
|
+
- link "Store, row 5 of 7 and column 3 of 3 in the second section" [ref=f12e165] [cursor=pointer]:
|
|
147
|
+
- /url: https://store.google.com?utm_source=app_launcher&utm_medium=google_oo&utm_campaign=GS107345
|
|
148
|
+
- generic [ref=f12e168]: Store
|
|
149
|
+
- listitem [ref=f12e169]:
|
|
150
|
+
- link "Chrome Web Store, row 6 of 7 and column 1 of 3 in the second section" [ref=f12e170] [cursor=pointer]:
|
|
151
|
+
- /url: https://chrome.google.com/webstore?utm_source=app-launcher
|
|
152
|
+
- generic [ref=f12e173]: Chrome Web Store
|
|
153
|
+
- listitem [ref=f12e174]:
|
|
154
|
+
- link "Google Fi Wireless, row 6 of 7 and column 2 of 3 in the second section" [ref=f12e175] [cursor=pointer]:
|
|
155
|
+
- /url: https://fi.google.com/?utm_source=app_launcher&utm_medium=embedded_promo
|
|
156
|
+
- generic [ref=f12e178]: Google Fi Wireless
|
|
157
|
+
- listitem [ref=f12e179]:
|
|
158
|
+
- link "Google Analytics, row 6 of 7 and column 3 of 3 in the second section" [ref=f12e180] [cursor=pointer]:
|
|
159
|
+
- /url: https://analytics.google.com/analytics/web?utm_source=OGB&utm_medium=app
|
|
160
|
+
- generic [ref=f12e183]: Google Analytics
|
|
161
|
+
- listitem [ref=f12e184]:
|
|
162
|
+
- link "YouTube Music, row 7 of 7 and column 1 of 3 in the second section" [ref=f12e185] [cursor=pointer]:
|
|
163
|
+
- /url: https://music.youtube.com?utm_source=app_launcher
|
|
164
|
+
- generic [ref=f12e188]: YouTube Music
|
|
165
|
+
- link "More from Google (opens a new tab)" [ref=f12e190] [cursor=pointer]:
|
|
166
|
+
- /url: https://about.google/products/
|
|
167
|
+
- text: More from Google
|
|
168
|
+
- generic [ref=f11e22]:
|
|
169
|
+
- link [ref=f11e24] [cursor=pointer]:
|
|
170
|
+
- /url: /search?sca_esv=b3cb815f54d8ec19&q=Which+National+Parks+have+some+of+the+most+scenic+overlooks%3F&udm=50&oi=ddle&noiga=1&ct=460148972&peek_pws=0&aep=84&sa=X&ved=0ahUKEwjx9MrgtsGWAxWpEVkFHdh1AvEQPQgH
|
|
171
|
+
- img "Celebrating National Park Week at Yosemite" [ref=f11e26]
|
|
172
|
+
- button "Share" [ref=f11e28]
|
|
173
|
+
- search [ref=f11e36]:
|
|
174
|
+
- generic [ref=f11e38]:
|
|
175
|
+
- generic [ref=f11e40]:
|
|
176
|
+
- button "Add files and tools" [ref=f11e45] [cursor=pointer]
|
|
177
|
+
- combobox "Search" [ref=f11e50]
|
|
178
|
+
- generic [ref=f11e51]:
|
|
179
|
+
- generic [ref=f11e52]:
|
|
180
|
+
- button "Search by voice" [ref=f11e55] [cursor=pointer]
|
|
181
|
+
- button "Search by image" [ref=f11e60] [cursor=pointer]
|
|
182
|
+
- link "AI Mode" [ref=f11e63] [cursor=pointer]
|
|
183
|
+
- generic [ref=f11e76]:
|
|
184
|
+
- button "Google Search" [ref=f11e77] [cursor=pointer]
|
|
185
|
+
- button "I'm Feeling Lucky" [ref=f11e78] [cursor=pointer]
|
|
186
|
+
- 'link "Celebrate National Park Week: Explore Yosemite with Google 🌲" [ref=f11e88] [cursor=pointer]'
|
|
187
|
+
- contentinfo [ref=f11e90]:
|
|
188
|
+
- generic [ref=f11e91]:
|
|
189
|
+
- generic [ref=f11e92]:
|
|
190
|
+
- link "Advertising" [ref=f11e93] [cursor=pointer]:
|
|
191
|
+
- /url: https://www.google.com/intl/en_us/ads/?subid=ww-ww-et-g-awa-a-g_hpafoot1_1!o2&utm_source=google.com&utm_medium=referral&utm_campaign=google_hpafooter&fg=1
|
|
192
|
+
- link "Business" [ref=f11e94] [cursor=pointer]:
|
|
193
|
+
- /url: https://www.google.com/services/?subid=ww-ww-et-g-awa-a-g_hpbfoot1_1!o2&utm_source=google.com&utm_medium=referral&utm_campaign=google_hpbfooter&fg=1
|
|
194
|
+
- link "How Search works" [ref=f11e95] [cursor=pointer]:
|
|
195
|
+
- /url: https://google.com/search/howsearchworks/?fg=1
|
|
196
|
+
- link "Build, create, and do more with AI tools from Google" [ref=f11e97] [cursor=pointer]:
|
|
197
|
+
- /url: https://ai.google/helpful-tools/?utm_source=googlehpfooter&utm_medium=housepromos&utm_campaign=bottom-footer
|
|
198
|
+
- generic [ref=f11e98]:
|
|
199
|
+
- link "Privacy" [ref=f11e99] [cursor=pointer]:
|
|
200
|
+
- /url: https://policies.google.com/privacy?hl=en&fg=1
|
|
201
|
+
- link "Terms" [ref=f11e100] [cursor=pointer]:
|
|
202
|
+
- /url: https://policies.google.com/terms?hl=en&fg=1
|
|
203
|
+
- button "Settings" [ref=f11e104] [cursor=pointer]
|
package/scripts/api-server.mjs
CHANGED
|
@@ -100,25 +100,119 @@ async function loadPrompt(name, params = {}) {
|
|
|
100
100
|
return content;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
/**
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Create a fresh ModelRuntime.
|
|
105
|
+
*
|
|
106
|
+
* Runtime API keys set on this instance are isolated to the current request.
|
|
107
|
+
*/
|
|
108
|
+
async function createModelRuntime() {
|
|
109
|
+
return ModelRuntime.create({
|
|
106
110
|
allowModelNetwork: false,
|
|
107
111
|
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolve runtime API keys from the request body.
|
|
116
|
+
*
|
|
117
|
+
* Supports three styles:
|
|
118
|
+
* - `apiKeys`: { "anthropic": "...", "openai": "..." }
|
|
119
|
+
* - `provider` + `apiKey`: set one key for an explicit provider
|
|
120
|
+
* - `apiKey` only (legacy): set key for the first available provider, falling back to anthropic
|
|
121
|
+
*/
|
|
122
|
+
function resolveApiKeys(body, availableModels) {
|
|
123
|
+
const keys = [];
|
|
124
|
+
|
|
125
|
+
if (body.apiKeys && typeof body.apiKeys === "object") {
|
|
126
|
+
for (const [providerId, key] of Object.entries(body.apiKeys)) {
|
|
127
|
+
if (typeof key === "string" && key.trim().length > 0) {
|
|
128
|
+
keys.push({ provider: providerId, key });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return keys;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (body.apiKey && typeof body.apiKey === "string" && body.apiKey.trim().length > 0) {
|
|
135
|
+
const provider = body.provider && typeof body.provider === "string"
|
|
136
|
+
? body.provider
|
|
137
|
+
: availableModels.length > 0
|
|
138
|
+
? availableModels[0].provider
|
|
139
|
+
: "anthropic";
|
|
140
|
+
keys.push({ provider, key: body.apiKey });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return keys;
|
|
144
|
+
}
|
|
108
145
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Resolve a model object from the request body.
|
|
148
|
+
*
|
|
149
|
+
* Accepts:
|
|
150
|
+
* - string: "anthropic/claude-opus-4-5" or "claude-opus-4-5"
|
|
151
|
+
* - object: { provider: "anthropic", id: "claude-opus-4-5" }
|
|
152
|
+
*
|
|
153
|
+
* If no model is requested, returns undefined so the agent picks a default.
|
|
154
|
+
*/
|
|
155
|
+
function resolveModel(modelRuntime, modelSelector, configuredProviders) {
|
|
156
|
+
if (!modelSelector) return undefined;
|
|
157
|
+
|
|
158
|
+
let providerId;
|
|
159
|
+
let modelId;
|
|
160
|
+
|
|
161
|
+
if (typeof modelSelector === "string") {
|
|
162
|
+
const parts = modelSelector.split("/");
|
|
163
|
+
if (parts.length === 2) {
|
|
164
|
+
[providerId, modelId] = parts;
|
|
116
165
|
} else {
|
|
117
|
-
|
|
118
|
-
|
|
166
|
+
modelId = modelSelector;
|
|
167
|
+
providerId = configuredProviders[0] ?? "anthropic";
|
|
119
168
|
}
|
|
169
|
+
} else if (typeof modelSelector === "object") {
|
|
170
|
+
providerId = modelSelector.provider;
|
|
171
|
+
modelId = modelSelector.id ?? modelSelector.modelId;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!providerId || !modelId) {
|
|
175
|
+
throw new Error(`Invalid model selector: ${JSON.stringify(modelSelector)}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const model = modelRuntime.getModel(providerId, modelId);
|
|
179
|
+
if (!model) {
|
|
180
|
+
throw new Error(`Model not found: ${providerId}/${modelId}`);
|
|
120
181
|
}
|
|
121
182
|
|
|
183
|
+
if (!modelRuntime.hasConfiguredAuth(providerId)) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Provider "${providerId}" is not configured with an API key. ` +
|
|
186
|
+
`Provide an apiKey or apiKeys for this provider.`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return model;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Create a single-use pi agent session. */
|
|
194
|
+
async function createSession({ cwd, apiKey, apiKeys, provider, model: modelSelector }) {
|
|
195
|
+
const modelRuntime = await createModelRuntime();
|
|
196
|
+
|
|
197
|
+
// Resolve keys before selecting a model so we know which providers are configured.
|
|
198
|
+
const availableBeforeKeys = modelRuntime.getAvailableSnapshot();
|
|
199
|
+
const keysToSet = resolveApiKeys({ apiKey, apiKeys, provider }, availableBeforeKeys);
|
|
200
|
+
|
|
201
|
+
// Set all runtime API keys in parallel.
|
|
202
|
+
await Promise.all(
|
|
203
|
+
keysToSet.map(({ provider: providerId, key }) =>
|
|
204
|
+
modelRuntime.setRuntimeApiKey(providerId, key).catch((err) => {
|
|
205
|
+
throw new Error(`Failed to set API key for ${providerId}: ${err.message}`);
|
|
206
|
+
})
|
|
207
|
+
)
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// Refresh availability after keys are set so the model picker sees configured providers.
|
|
211
|
+
await modelRuntime.getAvailable();
|
|
212
|
+
|
|
213
|
+
const configuredProviders = keysToSet.map((entry) => entry.provider);
|
|
214
|
+
const model = resolveModel(modelRuntime, modelSelector, configuredProviders);
|
|
215
|
+
|
|
122
216
|
const agentDir = getAgentDir();
|
|
123
217
|
|
|
124
218
|
const loader = new DefaultResourceLoader({
|
|
@@ -133,6 +227,7 @@ async function createSession({ cwd, apiKey }) {
|
|
|
133
227
|
modelRuntime,
|
|
134
228
|
resourceLoader: loader,
|
|
135
229
|
sessionManager: SessionManager.inMemory(),
|
|
230
|
+
...(model ? { model } : {}),
|
|
136
231
|
});
|
|
137
232
|
|
|
138
233
|
return session;
|
|
@@ -185,6 +280,88 @@ app.get("/api/prompts/:name", async (request, reply) => {
|
|
|
185
280
|
};
|
|
186
281
|
});
|
|
187
282
|
|
|
283
|
+
// List providers and their auth/configuration status
|
|
284
|
+
app.get("/api/providers", async (request, reply) => {
|
|
285
|
+
try {
|
|
286
|
+
const modelRuntime = await createModelRuntime();
|
|
287
|
+
const providers = modelRuntime.getProviders().map((provider) => ({
|
|
288
|
+
id: provider.id,
|
|
289
|
+
name: provider.name ?? provider.id,
|
|
290
|
+
authStatus: modelRuntime.getProviderAuthStatus(provider.id),
|
|
291
|
+
modelCount: modelRuntime.getModels(provider.id).length,
|
|
292
|
+
}));
|
|
293
|
+
return { providers };
|
|
294
|
+
} catch (err) {
|
|
295
|
+
reply.code(500);
|
|
296
|
+
return { error: `Failed to list providers: ${err.message}` };
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// List available models. Optionally filter with ?provider=<id>.
|
|
301
|
+
app.get("/api/models", async (request, reply) => {
|
|
302
|
+
try {
|
|
303
|
+
const { provider } = request.query;
|
|
304
|
+
const modelRuntime = await createModelRuntime();
|
|
305
|
+
await modelRuntime.getAvailable();
|
|
306
|
+
const models = modelRuntime.getAvailableSnapshot();
|
|
307
|
+
const filtered = provider
|
|
308
|
+
? models.filter((model) => model.provider === provider)
|
|
309
|
+
: models;
|
|
310
|
+
return {
|
|
311
|
+
models: filtered.map((model) => ({
|
|
312
|
+
provider: model.provider,
|
|
313
|
+
id: model.id,
|
|
314
|
+
name: model.name ?? model.id,
|
|
315
|
+
thinking: model.thinking,
|
|
316
|
+
})),
|
|
317
|
+
};
|
|
318
|
+
} catch (err) {
|
|
319
|
+
reply.code(500);
|
|
320
|
+
return { error: `Failed to list models: ${err.message}` };
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// List models available for the provided credentials (per-request keys).
|
|
325
|
+
// Accepts provider+apiKey or an apiKeys map; without keys, lists models from
|
|
326
|
+
// env/stored credentials. Used by clients to validate a key and pick a model.
|
|
327
|
+
app.post("/api/models", async (request, reply) => {
|
|
328
|
+
try {
|
|
329
|
+
const { provider, apiKey, apiKeys } = request.body || {};
|
|
330
|
+
const modelRuntime = await createModelRuntime();
|
|
331
|
+
|
|
332
|
+
const availableBeforeKeys = modelRuntime.getAvailableSnapshot();
|
|
333
|
+
const keysToSet = resolveApiKeys({ provider, apiKey, apiKeys }, availableBeforeKeys);
|
|
334
|
+
|
|
335
|
+
await Promise.all(
|
|
336
|
+
keysToSet.map(({ provider: providerId, key }) =>
|
|
337
|
+
modelRuntime.setRuntimeApiKey(providerId, key).catch((err) => {
|
|
338
|
+
throw new Error(`Failed to set API key for ${providerId}: ${err.message}`);
|
|
339
|
+
})
|
|
340
|
+
)
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
await modelRuntime.getAvailable();
|
|
344
|
+
|
|
345
|
+
let models = modelRuntime.getAvailableSnapshot();
|
|
346
|
+
if (provider) {
|
|
347
|
+
models = models.filter((model) => model.provider === provider);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
providers: [...new Set(keysToSet.map((entry) => entry.provider))],
|
|
352
|
+
models: models.map((model) => ({
|
|
353
|
+
provider: model.provider,
|
|
354
|
+
id: model.id,
|
|
355
|
+
name: model.name ?? model.id,
|
|
356
|
+
thinking: model.thinking,
|
|
357
|
+
})),
|
|
358
|
+
};
|
|
359
|
+
} catch (err) {
|
|
360
|
+
reply.code(500);
|
|
361
|
+
return { error: `Failed to list models: ${err.message}` };
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
188
365
|
// Execute a prompt (SSE streaming)
|
|
189
366
|
app.post("/api/prompts/:name", async (request, reply) => {
|
|
190
367
|
const { name } = request.params;
|
|
@@ -196,6 +373,9 @@ app.post("/api/prompts/:name", async (request, reply) => {
|
|
|
196
373
|
|
|
197
374
|
const {
|
|
198
375
|
apiKey,
|
|
376
|
+
apiKeys,
|
|
377
|
+
provider,
|
|
378
|
+
model,
|
|
199
379
|
cwd = process.cwd(),
|
|
200
380
|
stream = true,
|
|
201
381
|
...params
|
|
@@ -221,7 +401,13 @@ app.post("/api/prompts/:name", async (request, reply) => {
|
|
|
221
401
|
// Create session
|
|
222
402
|
let session;
|
|
223
403
|
try {
|
|
224
|
-
session = await createSession({
|
|
404
|
+
session = await createSession({
|
|
405
|
+
cwd: resolve(cwd),
|
|
406
|
+
apiKey,
|
|
407
|
+
apiKeys,
|
|
408
|
+
provider,
|
|
409
|
+
model,
|
|
410
|
+
});
|
|
225
411
|
} catch (err) {
|
|
226
412
|
reply.code(500);
|
|
227
413
|
return { error: `Failed to create agent session: ${err.message}` };
|
|
@@ -313,7 +499,9 @@ try {
|
|
|
313
499
|
await app.listen({ port: PORT, host: HOST });
|
|
314
500
|
console.log(`🦕 Dino API server running at http://${HOST}:${PORT}`);
|
|
315
501
|
console.log(` Prompts: http://${HOST}:${PORT}/api/prompts`);
|
|
502
|
+
console.log(` Providers: http://${HOST}:${PORT}/api/providers`);
|
|
503
|
+
console.log(` Models: http://${HOST}:${PORT}/api/models`);
|
|
316
504
|
} catch (err) {
|
|
317
505
|
app.log.error(err);
|
|
318
506
|
process.exit(1);
|
|
319
|
-
}
|
|
507
|
+
}
|