Skip to content

Commit d6ada46

Browse files
committed
feat(ai): Implement Navigation Control & History (#8184)
- Add getRouteHistory and setRoute to RuntimeService (client & server) - Expose get_route_history and set_route via MCP - Update OpenAPI spec - Add tool mappings
1 parent 8f75e34 commit d6ada46

5 files changed

Lines changed: 171 additions & 2 deletions

File tree

ai/mcp/server/neural-link/openapi.yaml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,93 @@ paths:
368368
schema:
369369
$ref: '#/components/schemas/ErrorResponse'
370370

371+
/navigation/history:
372+
post:
373+
summary: Get Route History
374+
operationId: get_route_history
375+
x-pass-as-object: true
376+
description: |
377+
Retrieves the navigation history stack and current route information.
378+
379+
**When to Use:**
380+
To understand where the user is in the application and how they got there.
381+
tags: [Navigation]
382+
requestBody:
383+
content:
384+
application/json:
385+
schema:
386+
$ref: '#/components/schemas/GetRouteHistoryRequest'
387+
responses:
388+
'200':
389+
description: Route history
390+
content:
391+
application/json:
392+
schema:
393+
type: object
394+
properties:
395+
count:
396+
type: integer
397+
windowId:
398+
type: integer
399+
history:
400+
type: array
401+
items:
402+
type: object
403+
'400':
404+
description: Invalid request body
405+
content:
406+
application/json:
407+
schema:
408+
$ref: '#/components/schemas/ErrorResponse'
409+
'500':
410+
description: Internal server error
411+
content:
412+
application/json:
413+
schema:
414+
$ref: '#/components/schemas/ErrorResponse'
415+
416+
/navigation/route/set:
417+
post:
418+
summary: Set Route
419+
operationId: set_route
420+
x-pass-as-object: true
421+
description: |
422+
Navigates the application to a specific route (hash).
423+
424+
**When to Use:**
425+
To drive the application to a specific view or state.
426+
tags: [Navigation]
427+
requestBody:
428+
required: true
429+
content:
430+
application/json:
431+
schema:
432+
$ref: '#/components/schemas/SetRouteRequest'
433+
responses:
434+
'200':
435+
description: Route set successfully
436+
content:
437+
application/json:
438+
schema:
439+
type: object
440+
properties:
441+
status:
442+
type: string
443+
hash:
444+
type: string
445+
'400':
446+
description: Invalid request body
447+
content:
448+
application/json:
449+
schema:
450+
$ref: '#/components/schemas/ErrorResponse'
451+
'500':
452+
description: Internal server error
453+
content:
454+
application/json:
455+
schema:
456+
$ref: '#/components/schemas/ErrorResponse'
457+
371458
/server/start:
372459
post:
373460
summary: Start WebSocket Server
@@ -609,6 +696,31 @@ components:
609696
type: string
610697
description: The target App Worker Session ID
611698

699+
GetRouteHistoryRequest:
700+
type: object
701+
properties:
702+
windowId:
703+
type: integer
704+
description: Optional window ID to get history for.
705+
sessionId:
706+
type: string
707+
description: The target App Worker Session ID
708+
709+
SetRouteRequest:
710+
type: object
711+
required:
712+
- hash
713+
properties:
714+
hash:
715+
type: string
716+
description: The new hash value to set (e.g., "#mainview=home").
717+
windowId:
718+
type: integer
719+
description: Optional window ID to target.
720+
sessionId:
721+
type: string
722+
description: The target App Worker Session ID
723+
612724
SetComponentPropertyRequest:
613725
type: object
614726
required:

ai/mcp/server/neural-link/services/RuntimeService.mjs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ class RuntimeService extends Base {
2525
singleton: true
2626
}
2727

28+
/**
29+
* Retrieves the navigation history stack.
30+
* @param {Object} opts The options object.
31+
* @param {String} opts.sessionId The target session ID.
32+
* @param {Number} [opts.windowId] Optional window ID.
33+
* @returns {Promise<Object>}
34+
*/
35+
async getRouteHistory({sessionId, windowId}) {
36+
return await ConnectionService.call(sessionId, 'get_route_history', {windowId})
37+
}
38+
2839
/**
2940
* Retrieves the topology of all connected windows.
3041
* @returns {Promise<Object[]>} List of windows.
@@ -65,6 +76,18 @@ class RuntimeService extends Base {
6576
async reloadPage({sessionId}) {
6677
return await ConnectionService.call(sessionId, 'reload_page', {})
6778
}
79+
80+
/**
81+
* Sets the application route (hash).
82+
* @param {Object} opts The options object.
83+
* @param {String} opts.hash The new hash value.
84+
* @param {String} opts.sessionId The target session ID.
85+
* @param {Number} [opts.windowId] Optional window ID.
86+
* @returns {Promise<Object>}
87+
*/
88+
async setRoute({hash, sessionId, windowId}) {
89+
return await ConnectionService.call(sessionId, 'set_route', {hash, windowId})
90+
}
6891
}
6992

7093
export default Neo.setupClass(RuntimeService);

ai/mcp/server/neural-link/services/toolService.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const serviceMapping = {
1717
get_component_tree : ComponentService .getComponentTree .bind(ComponentService),
1818
get_drag_state : InteractionService.getDragState .bind(InteractionService),
1919
get_record : DataService .getRecord .bind(DataService),
20+
get_route_history : RuntimeService .getRouteHistory .bind(RuntimeService),
2021
get_vdom_tree : ComponentService .getVdomTree .bind(ComponentService),
2122
get_vnode_tree : ComponentService .getVnodeTree .bind(ComponentService),
2223
get_window_topology : RuntimeService .getWindowTopology .bind(RuntimeService),
@@ -27,6 +28,7 @@ const serviceMapping = {
2728
query_component : ComponentService .queryComponent .bind(ComponentService),
2829
reload_page : RuntimeService .reloadPage .bind(RuntimeService),
2930
set_component_property: ComponentService .setComponentProperty.bind(ComponentService),
31+
set_route : RuntimeService .setRoute .bind(RuntimeService),
3032
start_ws_server : ConnectionService .startServer .bind(ConnectionService),
3133
stop_ws_server : ConnectionService .stopServer .bind(ConnectionService)
3234
};

src/ai/Client.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ class Client extends Base {
8585
list_stores : me.services.data,
8686

8787
get_drag : me.services.runtime,
88+
get_route : me.services.runtime,
8889
get_window : me.services.runtime,
89-
reload_page : me.services.runtime
90+
reload_page : me.services.runtime,
91+
set_route : me.services.runtime
9092
};
9193

9294
Neo.currentWorker.on({

src/ai/client/RuntimeService.mjs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import Service from './Service.mjs';
1+
import HashHistory from '../../util/HashHistory.mjs';
2+
import Service from './Service.mjs';
23

34
/**
45
* Handles runtime environment related Neural Link requests.
@@ -38,6 +39,22 @@ class RuntimeService extends Service {
3839
return {};
3940
}
4041

42+
/**
43+
* @param {Object} params
44+
* @returns {Object}
45+
*/
46+
getRouteHistory(params) {
47+
const
48+
windowId = params.windowId,
49+
stack = HashHistory.getStack(windowId);
50+
51+
return {
52+
count : stack.length,
53+
history : stack,
54+
windowId: windowId || null
55+
}
56+
}
57+
4158
/**
4259
* @param {Object} params
4360
* @returns {Object}
@@ -68,6 +85,19 @@ class RuntimeService extends Service {
6885
Neo.Main.reloadWindow();
6986
return {status: 'reloading'};
7087
}
88+
89+
/**
90+
* @param {Object} params
91+
* @returns {Object}
92+
*/
93+
setRoute(params) {
94+
Neo.Main.setRoute({
95+
value : params.hash,
96+
windowId: params.windowId
97+
});
98+
99+
return {status: 'ok', hash: params.hash}
100+
}
71101
}
72102

73103
export default Neo.setupClass(RuntimeService);

0 commit comments

Comments
 (0)