@@ -2,20 +2,40 @@ import {
22 CUA_ACTION_TYPES ,
33 CUA_BATCH_TOOL_NAME ,
44 CUA_NAVIGATION_TOOL_NAME ,
5+ normalizeCuaKeyCombo ,
6+ normalizeCuaKeySequence ,
7+ normalizeCuaModifierKey ,
58 type CuaAction ,
69 type CuaActionType ,
710} from "../common" ;
811
12+ /**
13+ * Native Yutori Navigator n1.5 tool-set ids.
14+ *
15+ * Source of truth:
16+ * - https://docs.yutori.com/reference/n1-5
17+ * - https://docs.yutori.com/llm-quickstart.md
18+ */
919export const YUTORI_N15_CORE_TOOL_SET = "browser_tools_core-20260403" ;
1020export const YUTORI_N15_EXPANDED_TOOL_SET = "browser_tools_expanded-20260403" ;
1121
22+ /**
23+ * DOM/ref-backed Navigator n1.5 actions. We intentionally disable these until
24+ * CuaAgent has the ref/DOM execution path that Yutori documents for the
25+ * expanded tool set.
26+ */
1227export const YUTORI_N15_EXPANDED_ACTION_TYPES = [
1328 "extract_elements" ,
1429 "find" ,
1530 "set_element_value" ,
1631 "execute_js" ,
1732] as const ;
1833
34+ /**
35+ * Navigator n1's fixed legacy browser action space.
36+ *
37+ * Source of truth: https://docs.yutori.com/reference/n1
38+ */
1939export const YUTORI_N1_ACTION_TYPES = [
2040 "left_click" ,
2141 "double_click" ,
@@ -32,6 +52,13 @@ export const YUTORI_N1_ACTION_TYPES = [
3252 "wait" ,
3353] as const ;
3454
55+ /**
56+ * Navigator n1.5 core visual action space. These are the actions available
57+ * when `tool_set` is `browser_tools_core-20260403`, which keeps CuaAgent in the
58+ * pure screenshot/coordinate path and avoids DOM refs.
59+ *
60+ * Source of truth: https://docs.yutori.com/reference/n1-5
61+ */
3562export const YUTORI_N15_CORE_ACTION_TYPES = [
3663 "left_click" ,
3764 "double_click" ,
@@ -74,17 +101,11 @@ const DEFAULT_WAIT_MS = 2000;
74101const NAVIGATION_WAIT_MS = 1500 ;
75102const GOTO_WAIT_MS = 2000 ;
76103
77- const MODIFIER_MAP : Record < string , string > = {
78- alt : "alt" ,
79- command : "super" ,
80- control : "ctrl" ,
81- ctrl : "ctrl" ,
82- cmd : "super" ,
83- meta : "super" ,
84- shift : "shift" ,
85- super : "super" ,
86- } ;
87-
104+ /**
105+ * Yutori n1.5 exposes built-in browser tools via `tool_set`, not by accepting
106+ * client-supplied JSON tool definitions. Keeping this empty prevents us from
107+ * sending duplicate CUA batch/browser tools alongside Yutori's native tools.
108+ */
88109export function createComputerToolDefinitions ( _options ?: unknown ) : [ ] {
89110 return [ ] ;
90111}
@@ -195,34 +216,36 @@ function toTypeActions(args: Record<string, unknown>): CuaAction[] | undefined {
195216 if ( text === undefined ) return undefined ;
196217 const actions : CuaAction [ ] = [ ] ;
197218 if ( args . clear_before_typing === true ) {
198- actions . push ( { type : "keypress" , keys : [ "Control " , "a" ] } , { type : "keypress" , keys : [ "Backspace " ] } ) ;
219+ actions . push ( { type : "keypress" , keys : [ "Control_L " , "a" ] } , { type : "keypress" , keys : [ "BackSpace " ] } ) ;
199220 }
200221 actions . push ( { type : "type" , text } ) ;
201- if ( args . press_enter_after === true ) actions . push ( { type : "keypress" , keys : [ "Enter " ] } ) ;
222+ if ( args . press_enter_after === true ) actions . push ( { type : "keypress" , keys : [ "Return " ] } ) ;
202223 return actions ;
203224}
204225
205226function toKeypressAction ( args : Record < string , unknown > ) : CuaAction [ ] | undefined {
206- const keys = readKeys ( args . key_comb ?? args . key ) ;
207- return keys . length > 0 ? [ { type : "keypress" , keys } ] : undefined ;
227+ const sequence = readKeySequence ( args . key_comb ?? args . key ) ;
228+ return sequence . length > 0 ? sequence . map ( ( keys ) => ( { type : "keypress" , keys } ) ) : undefined ;
208229}
209230
210231function toHoldKeyAction ( args : Record < string , unknown > ) : CuaAction [ ] | undefined {
211- const keys = readKeys ( args . key_comb ?? args . key ) ;
232+ const keys = readKeyCombo ( args . key_comb ?? args . key ) ;
212233 return keys . length > 0 ? [ { type : "keypress" , keys, duration : secondsToMs ( args . duration , 1000 ) } ] : undefined ;
213234}
214235
215- function readKeys ( value : unknown ) : string [ ] {
236+ function readKeyCombo ( value : unknown ) : string [ ] {
237+ if ( typeof value !== "string" ) return [ ] ;
238+ return normalizeCuaKeyCombo ( value ) ;
239+ }
240+
241+ function readKeySequence ( value : unknown ) : string [ ] [ ] {
216242 if ( typeof value !== "string" ) return [ ] ;
217- return value
218- . split ( "+" )
219- . map ( ( part ) => part . trim ( ) )
220- . filter ( Boolean ) ;
243+ return normalizeCuaKeySequence ( value ) ;
221244}
222245
223246function holdKeys ( value : unknown ) : { hold_keys ?: string [ ] } {
224247 if ( typeof value !== "string" ) return { } ;
225- const key = MODIFIER_MAP [ value . trim ( ) . toLowerCase ( ) ] ;
248+ const key = normalizeCuaModifierKey ( value ) ;
226249 return key ? { hold_keys : [ key ] } : { } ;
227250}
228251
0 commit comments