1010 */
1111'use server' ;
1212
13- import { makeManagementApiRequest } from '../api/api-config ' ;
13+ import { computeDiff , extractFieldsToUpdate , fetchCurrentEntityState } from './tool-approval.utils ' ;
1414import type { ActionResult } from './types' ;
1515
16- interface ToolMetadata {
17- resource : string ;
18- action : string ;
19- entity : string ;
20- }
21-
22- interface GetEntityParams {
23- toolName : string ;
24- input : Record < string , any > ;
25- tenantId : string ;
26- projectId : string ;
27- }
28-
2916interface FieldDiff {
3017 field : string ;
3118 oldValue : any ;
@@ -39,178 +26,6 @@ interface FetchToolApprovalDiffParams {
3926 projectId : string ;
4027}
4128
42- function parseToolName ( toolName : string ) : ToolMetadata {
43- const parts = toolName . split ( '-' ) ;
44-
45- const actions = [ 'create' , 'update' , 'delete' , 'get' , 'list' ] ;
46- const actionIndex = parts . findIndex ( ( part ) => actions . includes ( part ) ) ;
47-
48- if ( actionIndex === - 1 ) {
49- throw new Error ( `Unable to parse tool name: ${ toolName } ` ) ;
50- }
51-
52- return {
53- resource : parts . slice ( 0 , actionIndex ) . join ( '-' ) ,
54- action : parts [ actionIndex ] ,
55- entity : parts . slice ( actionIndex + 1 ) . join ( '-' ) ,
56- } ;
57- }
58-
59- function extractEntityId ( input : Record < string , any > , metadata : ToolMetadata ) : string | null {
60- const { entity, resource } = metadata ;
61-
62- const request = input . request || input ;
63-
64- const specificIdFields = [ 'id' , `${ entity } Id` , `${ entity . replace ( / - / g, '' ) } Id` ] ;
65-
66- for ( const field of specificIdFields ) {
67- if ( request [ field ] ) {
68- return request [ field ] ;
69- }
70- }
71-
72- const commonIdFields = [ 'agentId' , 'subAgentId' , 'toolId' ] ;
73-
74- if ( ( resource === 'projects' || resource === 'project' ) && request . id ) {
75- return request . id ;
76- }
77-
78- for ( const field of commonIdFields ) {
79- if ( request [ field ] ) {
80- return request [ field ] ;
81- }
82- }
83-
84- return null ;
85- }
86-
87- function pluralizeResource ( resource : string ) : string {
88- const pluralMappings : Record < string , string > = {
89- agent : 'agents' ,
90- 'sub-agent' : 'sub-agents' ,
91- credential : 'credentials' ,
92- function : 'functions' ,
93- } ;
94-
95- if ( pluralMappings [ resource ] ) {
96- return pluralMappings [ resource ] ;
97- }
98-
99- if ( ! resource . endsWith ( 's' ) ) {
100- return `${ resource } s` ;
101- }
102-
103- return resource ;
104- }
105-
106- function buildApiPath (
107- metadata : ToolMetadata ,
108- tenantId : string ,
109- projectId : string ,
110- entityId : string ,
111- additionalParams ?: { agentId ?: string }
112- ) : string {
113- const { resource } = metadata ;
114-
115- const pathMappings : Record <
116- string ,
117- ( tid : string , pid : string , eid : string , params ?: any ) => string
118- > = {
119- projects : ( tid , _pid , eid ) => `tenants/${ tid } /projects/${ eid } ` ,
120- project : ( tid , _pid , eid ) => `tenants/${ tid } /projects/${ eid } ` ,
121- agent : ( tid , pid , eid ) => `tenants/${ tid } /projects/${ pid } /agent/${ eid } ` ,
122- 'sub-agent' : ( tid , pid , eid , params ) => {
123- if ( ! params ?. agentId ) {
124- console . warn ( 'sub-agent path requires agentId but none provided' ) ;
125- return `tenants/${ tid } /projects/${ pid } /agents/MISSING_AGENT_ID/sub-agents/${ eid } ` ;
126- }
127- return `tenants/${ tid } /projects/${ pid } /agents/${ params . agentId } /sub-agents/${ eid } ` ;
128- } ,
129- } ;
130-
131- if ( pathMappings [ resource ] ) {
132- return pathMappings [ resource ] ( tenantId , projectId , entityId , additionalParams ) ;
133- }
134-
135- const pluralEntity = pluralizeResource ( resource ) ;
136-
137- if ( resource . includes ( '-relations' ) ) {
138- return `tenants/${ tenantId } /projects/${ projectId } /${ pluralEntity } /${ entityId } ` ;
139- }
140-
141- return `tenants/${ tenantId } /projects/${ projectId } /${ pluralEntity } /${ entityId } ` ;
142- }
143-
144- async function fetchCurrentEntityState (
145- params : GetEntityParams
146- ) : Promise < Record < string , any > | null > {
147- const { toolName, input, tenantId, projectId } = params ;
148-
149- if (
150- ! toolName . includes ( 'update' ) &&
151- ! toolName . includes ( 'create' ) &&
152- ! toolName . includes ( 'delete' )
153- ) {
154- return null ;
155- }
156-
157- const metadata = parseToolName ( toolName ) ;
158-
159- if ( metadata . action === 'create' ) {
160- return { } ;
161- }
162-
163- const entityId = extractEntityId ( input , metadata ) ;
164-
165- if ( ! entityId ) {
166- console . warn ( `Could not extract entity ID from input for tool: ${ toolName } ` ) ;
167- return null ;
168- }
169-
170- try {
171- // Extract agentId for sub-agents (they're nested under agents)
172- const request = input . request || input ;
173- const agentId = request . agentId ;
174-
175- const apiPath = buildApiPath ( metadata , tenantId , projectId , entityId , { agentId } ) ;
176- const response = await makeManagementApiRequest < any > ( apiPath , {
177- method : 'GET' ,
178- } ) ;
179-
180- const currentState = response . data || response ;
181- return currentState ;
182- } catch ( error ) {
183- console . error ( `Failed to fetch current state for ${ toolName } :` , error ) ;
184- return null ;
185- }
186- }
187-
188- function extractFieldsToUpdate ( input : Record < string , any > ) : Record < string , any > {
189- const request = input . request || input ;
190- return request . body || { } ;
191- }
192-
193- function computeDiff (
194- currentState : Record < string , any > | null ,
195- newValues : Record < string , any >
196- ) : Array < { field : string ; oldValue : any ; newValue : any } > {
197- const diffs : Array < { field : string ; oldValue : any ; newValue : any } > = [ ] ;
198-
199- for ( const [ field , newValue ] of Object . entries ( newValues ) ) {
200- const oldValue = currentState ?. [ field ] ?? '' ;
201-
202- if ( JSON . stringify ( oldValue ) !== JSON . stringify ( newValue ) ) {
203- diffs . push ( {
204- field,
205- oldValue,
206- newValue,
207- } ) ;
208- }
209- }
210-
211- return diffs ;
212- }
213-
21429export async function fetchToolApprovalDiff (
21530 params : FetchToolApprovalDiffParams
21631) : Promise < ActionResult < FieldDiff [ ] > & { entityData ?: Record < string , any > } > {
@@ -248,23 +63,3 @@ export async function fetchToolApprovalDiff(
24863 } ;
24964 }
25065}
251-
252- /**
253- * ⚠️ TESTING EXPORTS ONLY
254- *
255- * These functions are exported for testing purposes only.
256- * Do NOT import these directly from client components - they will still execute server-side,
257- * but importing them from client code breaks the architectural boundary.
258- *
259- * Client components should only import: fetchToolApprovalDiff()
260- */
261- export {
262- fetchCurrentEntityState ,
263- extractFieldsToUpdate ,
264- computeDiff ,
265- parseToolName ,
266- extractEntityId ,
267- buildApiPath ,
268- pluralizeResource ,
269- } ;
270- export type { ToolMetadata , GetEntityParams , FieldDiff } ;
0 commit comments