Skip to content

Commit b8f54bf

Browse files
committed
refactor(ai): Extract ComponentService from ConnectionService (#8178)
- Created ComponentService for handling component inspection/modification - Exposed ConnectionService.call() as a public method for RPC transport - Removed component logic from ConnectionService to reduce complexity - Updated toolService to route component tools to the new service
1 parent 7663897 commit b8f54bf

3 files changed

Lines changed: 100 additions & 70 deletions

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import Base from '../../../../../src/core/Base.mjs';
2+
import ConnectionService from './ConnectionService.mjs';
3+
4+
/**
5+
* @summary Manages component-related operations for the Neural Link MCP Server.
6+
*
7+
* This service provides tools for inspecting and modifying components within the connected
8+
* Neo.mjs application. It delegates the actual transport to `ConnectionService`.
9+
*
10+
* @class Neo.ai.mcp.server.neural-link.services.ComponentService
11+
* @extends Neo.core.Base
12+
* @singleton
13+
*/
14+
class ComponentService extends Base {
15+
static config = {
16+
/**
17+
* @member {String} className='Neo.ai.mcp.server.neural-link.services.ComponentService'
18+
* @protected
19+
*/
20+
className: 'Neo.ai.mcp.server.neural-link.services.ComponentService',
21+
/**
22+
* @member {Boolean} singleton=true
23+
* @protected
24+
*/
25+
singleton: true
26+
}
27+
28+
/**
29+
* Retrieves a property from a component by its ID.
30+
* @param {Object} opts The options object.
31+
* @param {String} opts.id The component ID.
32+
* @param {String} opts.property The property name to retrieve.
33+
* @param {String} [opts.sessionId] The target session ID.
34+
* @returns {Promise<any>} The value of the property.
35+
*/
36+
async getComponentProperty({id, property, sessionId}) {
37+
return await ConnectionService.call(sessionId, 'get_component_property', {id, property});
38+
}
39+
40+
/**
41+
* Retrieves the full component tree of the application.
42+
* @param {Object} opts The options object.
43+
* @param {Number} [opts.depth] The depth limit.
44+
* @param {String} [opts.rootId] Optional root component ID.
45+
* @param {String} [opts.sessionId] The target session ID.
46+
* @returns {Promise<Object>} The component tree structure.
47+
*/
48+
async getComponentTree({depth, rootId, sessionId}) {
49+
return await ConnectionService.call(sessionId, 'get_component_tree', {depth, rootId});
50+
}
51+
52+
/**
53+
* Retrieves the VDOM tree of a component.
54+
* @param {Object} opts The options object.
55+
* @param {Number} [opts.depth] The depth limit.
56+
* @param {String} [opts.rootId] Optional root component ID.
57+
* @param {String} [opts.sessionId] The target session ID.
58+
* @returns {Promise<Object>} The VDOM tree structure.
59+
*/
60+
async getVdomTree({depth, rootId, sessionId}) {
61+
return await ConnectionService.call(sessionId, 'get_vdom_tree', {depth, rootId});
62+
}
63+
64+
/**
65+
* Retrieves the VNode tree of a component.
66+
* @param {Object} opts The options object.
67+
* @param {Number} [opts.depth] The depth limit.
68+
* @param {String} [opts.rootId] Optional root component ID.
69+
* @param {String} [opts.sessionId] The target session ID.
70+
* @returns {Promise<Object>} The VNode tree structure.
71+
*/
72+
async getVnodeTree({depth, rootId, sessionId}) {
73+
return await ConnectionService.call(sessionId, 'get_vnode_tree', {depth, rootId});
74+
}
75+
76+
/**
77+
* Sets a property on a component by its ID.
78+
* @param {Object} opts The options object.
79+
* @param {String} opts.id The component ID.
80+
* @param {String} opts.property The property name to set.
81+
* @param {*} opts.value The value to set.
82+
* @param {String} [opts.sessionId] The target session ID.
83+
* @returns {Promise<void>}
84+
*/
85+
async setComponentProperty({id, property, value, sessionId}) {
86+
return await ConnectionService.call(sessionId, 'set_component_property', {id, property, value});
87+
}
88+
}
89+
90+
export default Neo.setupClass(ComponentService);

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

Lines changed: 4 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,8 @@ class ConnectionService extends Base {
202202
* @param {String} method The RPC method name.
203203
* @param {Object} [params={}] The RPC parameters.
204204
* @returns {Promise<any>} Resolves with the RPC result or rejects with an error.
205-
* @private
206205
*/
207-
#call(sessionId, method, params={}) {
206+
call(sessionId, method, params={}) {
208207
return new Promise((resolve, reject) => {
209208
const ws = this.sessions.get(sessionId);
210209

@@ -215,7 +214,7 @@ class ConnectionService extends Base {
215214
const lastId = Array.from(this.sessions.keys()).pop();
216215
logger.warn(`No sessionId provided. Defaulting to ${lastId}`);
217216
// Recursive call with the found ID
218-
return this.#call(lastId, method, params).then(resolve).catch(reject);
217+
return this.call(lastId, method, params).then(resolve).catch(reject);
219218
}
220219
logger.error(`Session not found. Requested: ${sessionId}, Active: ${Array.from(this.sessions.keys()).join(', ')}`);
221220
return reject(new Error(`Session not found: ${sessionId || 'No active sessions'}`));
@@ -261,62 +260,14 @@ class ConnectionService extends Base {
261260
}
262261
}
263262

264-
/**
265-
* Retrieves a property from a component by its ID.
266-
* @param {Object} opts The options object.
267-
* @param {String} opts.id The component ID.
268-
* @param {String} opts.property The property name to retrieve.
269-
* @param {String} [opts.sessionId] The target session ID.
270-
* @returns {Promise<any>} The value of the property.
271-
*/
272-
async getComponentProperty({id, property, sessionId}) {
273-
return await this.#call(sessionId, 'get_component_property', {id, property})
274-
}
275-
276-
/**
277-
* Retrieves the full component tree of the application.
278-
* @param {Object} opts The options object.
279-
* @param {Number} [opts.depth] The depth limit.
280-
* @param {String} [opts.rootId] Optional root component ID.
281-
* @param {String} [opts.sessionId] The target session ID.
282-
* @returns {Promise<Object>} The component tree structure.
283-
*/
284-
async getComponentTree({depth, rootId, sessionId}) {
285-
return await this.#call(sessionId, 'get_component_tree', {depth, rootId})
286-
}
287-
288-
/**
289-
* Retrieves the VDOM tree of a component.
290-
* @param {Object} opts The options object.
291-
* @param {Number} [opts.depth] The depth limit.
292-
* @param {String} [opts.rootId] Optional root component ID.
293-
* @param {String} [opts.sessionId] The target session ID.
294-
* @returns {Promise<Object>} The VDOM tree structure.
295-
*/
296-
async getVdomTree({depth, rootId, sessionId}) {
297-
return await this.#call(sessionId, 'get_vdom_tree', {depth, rootId})
298-
}
299-
300-
/**
301-
* Retrieves the VNode tree of a component.
302-
* @param {Object} opts The options object.
303-
* @param {Number} [opts.depth] The depth limit.
304-
* @param {String} [opts.rootId] Optional root component ID.
305-
* @param {String} [opts.sessionId] The target session ID.
306-
* @returns {Promise<Object>} The VNode tree structure.
307-
*/
308-
async getVnodeTree({depth, rootId, sessionId}) {
309-
return await this.#call(sessionId, 'get_vnode_tree', {depth, rootId})
310-
}
311-
312263
/**
313264
* Retrieves the state of the DragCoordinator.
314265
* @param {Object} opts
315266
* @param {String} [opts.sessionId]
316267
* @returns {Promise<Object>}
317268
*/
318269
async getDragState({sessionId}) {
319-
return await this.#call(sessionId, 'get_drag_state', {})
270+
return await this.call(sessionId, 'get_drag_state', {})
320271
}
321272

322273
/**
@@ -377,21 +328,9 @@ class ConnectionService extends Base {
377328
* @returns {Promise<void>}
378329
*/
379330
async reloadPage({sessionId}) {
380-
return await this.#call(sessionId, 'reload_page', {})
331+
return await this.call(sessionId, 'reload_page', {})
381332
}
382333

383-
/**
384-
* Sets a property on a component by its ID.
385-
* @param {Object} opts The options object.
386-
* @param {String} opts.id The component ID.
387-
* @param {String} opts.property The property name to set.
388-
* @param {*} opts.value The value to set.
389-
* @param {String} [opts.sessionId] The target session ID.
390-
* @returns {Promise<void>}
391-
*/
392-
async setComponentProperty({id, property, value, sessionId}) {
393-
return await this.#call(sessionId, 'set_component_property', {id, property, value})
394-
}
395334
}
396335

397336
export default Neo.setupClass(ConnectionService);

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import path from 'path';
22
import {fileURLToPath} from 'url';
33
import ToolService from '../../../ToolService.mjs';
4+
import ComponentService from './ComponentService.mjs';
45
import ConnectionService from './ConnectionService.mjs';
56
import HealthService from './HealthService.mjs';
67

@@ -9,16 +10,16 @@ const __dirname = path.dirname(__filename);
910
const openApiFilePath = path.join(__dirname, '../openapi.yaml');
1011

1112
const serviceMapping = {
12-
get_component_property: ConnectionService.getComponentProperty.bind(ConnectionService),
13-
get_component_tree : ConnectionService.getComponentTree.bind(ConnectionService),
13+
get_component_property: ComponentService.getComponentProperty.bind(ComponentService),
14+
get_component_tree : ComponentService.getComponentTree.bind(ComponentService),
1415
get_drag_state : ConnectionService.getDragState.bind(ConnectionService),
15-
get_vdom_tree : ConnectionService.getVdomTree.bind(ConnectionService),
16-
get_vnode_tree : ConnectionService.getVnodeTree.bind(ConnectionService),
16+
get_vdom_tree : ComponentService.getVdomTree.bind(ComponentService),
17+
get_vnode_tree : ComponentService.getVnodeTree.bind(ComponentService),
1718
get_window_topology : ConnectionService.getWindowTopology.bind(ConnectionService),
1819
get_worker_topology : ConnectionService.getWorkerTopology.bind(ConnectionService),
1920
healthcheck : HealthService.healthcheck.bind(HealthService),
2021
reload_page : ConnectionService.reloadPage.bind(ConnectionService),
21-
set_component_property: ConnectionService.setComponentProperty.bind(ConnectionService)
22+
set_component_property: ComponentService.setComponentProperty.bind(ComponentService)
2223
};
2324

2425
const toolService = Neo.create(ToolService, {

0 commit comments

Comments
 (0)