From 033cdc5dd0903e1dbffc5734ecf61b64d8e0c1e8 Mon Sep 17 00:00:00 2001 From: "Bhavya ." Date: Mon, 15 Dec 2025 14:55:10 +0530 Subject: [PATCH 1/5] Adding Invoke Nested Agent operation --- Localize/lang/strings.json | 2 + .../laDesignerConsumption.tsx | 1 + .../laDesignerConsumptionV2.tsx | 1 + .../templates/app/TemplatesConsumption.tsx | 1 + libs/designer-v2/src/lib/common/constants.ts | 1 + .../recommendation/azureResourceSelection.tsx | 21 +++++ libs/designer/src/lib/common/constants.ts | 1 + .../recommendation/azureResourceSelection.tsx | 21 +++++ .../__mocks__/builtInOperationResponse.ts | 21 +++++ .../lib/base/search.ts | 8 ++ .../manifests/invokeNestedAgent.ts | 84 +++++++++++++++++++ .../lib/consumption/operationmanifest.ts | 18 +++- .../consumption/operations/invokeWorkflow.ts | 23 +++++ .../lib/consumption/search.ts | 1 + .../designer-client-services/lib/search.ts | 1 + package.json | 8 +- pnpm-lock.yaml | 66 +++++++-------- 17 files changed, 243 insertions(+), 36 deletions(-) create mode 100644 libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts diff --git a/Localize/lang/strings.json b/Localize/lang/strings.json index 746ec9e6fb9..ebfe62e4f83 100644 --- a/Localize/lang/strings.json +++ b/Localize/lang/strings.json @@ -1150,6 +1150,7 @@ "QHdKnm": "Drag and connect nodes to transform", "QIzNzB": "Toggle the agent log panel.", "QKC8fv": "Enter variable name", + "QMuDPI": "Select workflow with an Agent loop", "QMyMOI": "Description", "QNfUf/": "Full screen", "QT4IaP": "Filtered!", @@ -2714,6 +2715,7 @@ "_QHdKnm.comment": "default placeholder text", "_QIzNzB.comment": "Toggle the agent log panel aria label text", "_QKC8fv.comment": "Placeholder for variable name", + "_QMuDPI.comment": "Select workflow with an Agent loop", "_QMyMOI.comment": "Description label", "_QNfUf/.comment": "Full Screen token picker", "_QT4IaP.comment": "Filtered text", diff --git a/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumption.tsx b/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumption.tsx index a4d841e1164..c318a5fbdbf 100644 --- a/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumption.tsx +++ b/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumption.tsx @@ -427,6 +427,7 @@ const getDesignerServices = ( ...defaultServiceParams, clientSupportedOperations: [ ['/connectionProviders/workflow', 'invokeWorkflow'], + ['/connectionProviders/workflow', 'invokenestedagent'], ['connectionProviders/xmlOperations', 'xmlValidation'], ['connectionProviders/xmlOperations', 'xmlTransform'], ['connectionProviders/liquidOperations', 'liquidJsonToJson'], diff --git a/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumptionV2.tsx b/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumptionV2.tsx index 8772309a0aa..79b98dab346 100644 --- a/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumptionV2.tsx +++ b/apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumptionV2.tsx @@ -539,6 +539,7 @@ const getDesignerServices = ( ...defaultServiceParams, clientSupportedOperations: [ ['/connectionProviders/workflow', 'invokeWorkflow'], + ['/connectionProviders/workflow', 'invokenestedagent'], ['connectionProviders/xmlOperations', 'xmlValidation'], ['connectionProviders/xmlOperations', 'xmlTransform'], ['connectionProviders/liquidOperations', 'liquidJsonToJson'], diff --git a/apps/Standalone/src/templates/app/TemplatesConsumption.tsx b/apps/Standalone/src/templates/app/TemplatesConsumption.tsx index 56b2b2495c0..85ab95e7521 100644 --- a/apps/Standalone/src/templates/app/TemplatesConsumption.tsx +++ b/apps/Standalone/src/templates/app/TemplatesConsumption.tsx @@ -366,6 +366,7 @@ const getResourceBasedServices = ( ...defaultServiceParams, clientSupportedOperations: [ ['/connectionProviders/workflow', 'invokeWorkflow'], + ['/connectionProviders/workflow', 'invokenestedagent'], ['connectionProviders/xmlOperations', 'xmlValidation'], ['connectionProviders/xmlOperations', 'xmlTransform'], ['connectionProviders/liquidOperations', 'liquidJsonToJson'], diff --git a/libs/designer-v2/src/lib/common/constants.ts b/libs/designer-v2/src/lib/common/constants.ts index 4ce0c037346..6f819729f0f 100644 --- a/libs/designer-v2/src/lib/common/constants.ts +++ b/libs/designer-v2/src/lib/common/constants.ts @@ -979,6 +979,7 @@ export default { SELECT_BATCH_WORKFLOW_ACTION: 'sendtobatch', SELECT_BATCH_WORKFLOW_TRIGGER: 'sendtobatchtrigger', SELECT_MANUAL_WORKFLOW_ACTION: 'invokeworkflow', + SELECT_NESTED_AGENT_WORKFLOW_ACTION: 'invokenestedagent', }, CHANNELS: { INPUT: '-inputchannel-', diff --git a/libs/designer-v2/src/lib/ui/panel/recommendation/azureResourceSelection.tsx b/libs/designer-v2/src/lib/ui/panel/recommendation/azureResourceSelection.tsx index 2a287ee49bc..d8c06ab5b79 100644 --- a/libs/designer-v2/src/lib/ui/panel/recommendation/azureResourceSelection.tsx +++ b/libs/designer-v2/src/lib/ui/panel/recommendation/azureResourceSelection.tsx @@ -62,6 +62,11 @@ export const AzureResourceSelection = (props: AzureResourceSelectionProps) => { id: 'DXwS7e', description: "Select workflow with 'An HTTP Request' trigger", }); + const nestedAgentWorkflowTitleText = intl.formatMessage({ + defaultMessage: 'Select workflow with an Agent loop', + id: 'QMuDPI', + description: 'Select workflow with an Agent loop', + }); const batchWorkflowTitleText = intl.formatMessage({ defaultMessage: 'Select a Batch Workflow resource', id: 'gvDMuq', @@ -210,6 +215,21 @@ export const AzureResourceSelection = (props: AzureResourceSelectionProps) => { break; } + case Constants.AZURE_RESOURCE_ACTION_TYPES.SELECT_NESTED_AGENT_WORKFLOW_ACTION: { + setTitleText(nestedAgentWorkflowTitleText); + setResourceTypes(['agentWorkflow']); + setGetResourcesCallbacks(() => [() => SearchService().getAgentWorkflows?.()]); + setSubmitCallback(() => () => { + addResourceOperation({ + name: getResourceName(selectedResources[0]), + presetParameterValues: { + 'host.workflow.id': selectedResources[0].id, + }, + }); + }); + break; + } + case Constants.AZURE_RESOURCE_ACTION_TYPES.SELECT_BATCH_WORKFLOW_ACTION: { setTitleText(batchWorkflowTitleText); setResourceTypes(['batchWorkflow', 'trigger']); @@ -241,6 +261,7 @@ export const AzureResourceSelection = (props: AzureResourceSelectionProps) => { swaggerFunctionAppTitleText, getOptionsFromPaths, manualWorkflowTitleText, + nestedAgentWorkflowTitleText, operation.id, selectedResources, ]); diff --git a/libs/designer/src/lib/common/constants.ts b/libs/designer/src/lib/common/constants.ts index ea7b2511943..96ea9766ee5 100644 --- a/libs/designer/src/lib/common/constants.ts +++ b/libs/designer/src/lib/common/constants.ts @@ -984,6 +984,7 @@ export default { SELECT_BATCH_WORKFLOW_ACTION: 'sendtobatch', SELECT_BATCH_WORKFLOW_TRIGGER: 'sendtobatchtrigger', SELECT_MANUAL_WORKFLOW_ACTION: 'invokeworkflow', + SELECT_NESTED_AGENT_WORKFLOW_ACTION: 'invokenestedagent', }, CHANNELS: { INPUT: '-inputchannel-', diff --git a/libs/designer/src/lib/ui/panel/recommendation/azureResourceSelection.tsx b/libs/designer/src/lib/ui/panel/recommendation/azureResourceSelection.tsx index 2a287ee49bc..d8c06ab5b79 100644 --- a/libs/designer/src/lib/ui/panel/recommendation/azureResourceSelection.tsx +++ b/libs/designer/src/lib/ui/panel/recommendation/azureResourceSelection.tsx @@ -62,6 +62,11 @@ export const AzureResourceSelection = (props: AzureResourceSelectionProps) => { id: 'DXwS7e', description: "Select workflow with 'An HTTP Request' trigger", }); + const nestedAgentWorkflowTitleText = intl.formatMessage({ + defaultMessage: 'Select workflow with an Agent loop', + id: 'QMuDPI', + description: 'Select workflow with an Agent loop', + }); const batchWorkflowTitleText = intl.formatMessage({ defaultMessage: 'Select a Batch Workflow resource', id: 'gvDMuq', @@ -210,6 +215,21 @@ export const AzureResourceSelection = (props: AzureResourceSelectionProps) => { break; } + case Constants.AZURE_RESOURCE_ACTION_TYPES.SELECT_NESTED_AGENT_WORKFLOW_ACTION: { + setTitleText(nestedAgentWorkflowTitleText); + setResourceTypes(['agentWorkflow']); + setGetResourcesCallbacks(() => [() => SearchService().getAgentWorkflows?.()]); + setSubmitCallback(() => () => { + addResourceOperation({ + name: getResourceName(selectedResources[0]), + presetParameterValues: { + 'host.workflow.id': selectedResources[0].id, + }, + }); + }); + break; + } + case Constants.AZURE_RESOURCE_ACTION_TYPES.SELECT_BATCH_WORKFLOW_ACTION: { setTitleText(batchWorkflowTitleText); setResourceTypes(['batchWorkflow', 'trigger']); @@ -241,6 +261,7 @@ export const AzureResourceSelection = (props: AzureResourceSelectionProps) => { swaggerFunctionAppTitleText, getOptionsFromPaths, manualWorkflowTitleText, + nestedAgentWorkflowTitleText, operation.id, selectedResources, ]); diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/__test__/__mocks__/builtInOperationResponse.ts b/libs/logic-apps-shared/src/designer-client-services/lib/__test__/__mocks__/builtInOperationResponse.ts index 28aebb6a491..358a7fa17b7 100644 --- a/libs/logic-apps-shared/src/designer-client-services/lib/__test__/__mocks__/builtInOperationResponse.ts +++ b/libs/logic-apps-shared/src/designer-client-services/lib/__test__/__mocks__/builtInOperationResponse.ts @@ -1815,6 +1815,27 @@ export const almostAllBuiltInOperations: DiscoveryOperation[]> { + const requestWorkflows = await this.getWorkflows(`contains(Trigger, 'Request') and (${ISE_RESOURCE_ID} eq null)`); + return requestWorkflows.filter((workflow: any) => { + const triggers = workflow.properties?.definition?.triggers ?? {}; + return Object.values(triggers).some((trigger: any) => trigger.kind?.toLowerCase() === 'agent'); + }); + } + public async getBatchWorkflows(): Promise[]> { return this.getWorkflows(`contains(Trigger, 'Batch') and (${ISE_RESOURCE_ID} eq null)`); } diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts new file mode 100644 index 00000000000..746adcc8cef --- /dev/null +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts @@ -0,0 +1,84 @@ +import type { OperationManifest } from '../../../../utils/src'; +import { coreBadge } from '../../badges'; +import { invokeWorkflowGroup } from '../operations'; + +export const invokeNestedAgentManifest = { + properties: { + iconUri: invokeWorkflowGroup.properties.iconUri, + brandColor: invokeWorkflowGroup.properties.brandColor, + summary: 'Choose a Logic Apps workflow', + description: 'Send a task to a nested agent workflow in the same region', + + environmentBadge: coreBadge, + + inputs: { + type: 'object', + required: ['host'], + properties: { + taskMessage: { + title: 'Task Message', + type: 'string', + description: 'The task message to send to the nested agent', + 'x-ms-visibility': 'important', + }, + host: { + type: 'object', + required: ['workflow'], + properties: { + workflow: { + type: 'object', + required: ['id'], + properties: { + id: { + title: 'Workflow Id', + type: 'string', + }, + }, + }, + }, + }, + }, + }, + inputsLocation: ['inputs'], + isInputsOptional: false, + autoCast: true, + + outputs: { + type: 'object', + properties: { + body: { + title: 'Body', + }, + headers: { + type: 'object', + title: 'Headers', + }, + statusCode: { + type: 'integer', + title: 'Status Code', + }, + }, + }, + isOutputsOptional: false, + includeRootOutputs: true, + + connector: invokeWorkflowGroup, + + settings: { + operationOptions: { + options: ['DisableAsyncPattern', 'DisableAutomaticDecompression'], + scopes: ['action'], + }, + retryPolicy: { + scopes: ['action'], + }, + secureData: {}, + trackedProperties: { + scopes: ['action'], + }, + timeout: { + scopes: ['action'], + }, + }, + }, +} as OperationManifest; diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operationmanifest.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operationmanifest.ts index ba27b7d0f0f..320a17439a4 100644 --- a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operationmanifest.ts +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operationmanifest.ts @@ -22,11 +22,19 @@ import { selectFunctionManifest } from './manifests/functions'; import { inlineCodeManifest } from './manifests/inlinecode'; import { integrationAccountArtifactLookupManifest } from './manifests/integrationaccountartifactlookup'; import { invokeWorkflowManifest } from './manifests/invokeWorkflow'; +import { invokeNestedAgentManifest } from './manifests/invokeNestedAgent'; import { liquidJsonToJsonManifest, liquidJsonToTextManifest, liquidXmlToJsonManifest, liquidXmlToTextManifest } from './manifests/liquid'; import { rosettaNetEncodeManifest, rosettaNetDecodeManifest, rosettaNetWaitForResponseManifest } from './manifests/rosettanet'; import { selectSwaggerFunctionManifest } from './manifests/swaggerFunctions'; import { xmlTransformManifest, xmlValidationManifest } from './manifests/xml'; -import { functionGroup, functionOperation, invokeWorkflowGroup, invokeWorkflowOperation, swaggerFunctionOperation } from './operations'; +import { + functionGroup, + functionOperation, + invokeWorkflowGroup, + invokeWorkflowOperation, + invokeNestedAgentOperation, + swaggerFunctionOperation, +} from './operations'; import { getBuiltInConnectorsInConsumption } from './search'; import agentloop from './manifests/agentloop'; import a2arequestManifest from './manifests/a2arequest'; @@ -66,6 +74,12 @@ export class ConsumptionOperationManifestService extends BaseOperationManifestSe operationId: invokeWorkflowOperation.id, }; + case 'nestedagent': + return { + connectorId: invokeWorkflowGroup.id, + operationId: invokeNestedAgentOperation.id, + }; + case 'function': return { connectorId: functionGroup.id, @@ -188,6 +202,7 @@ const apimanagementtrigger = 'apimanagementtrigger'; const appservice = 'appservice'; const appservicetrigger = 'appservicetrigger'; const invokeworkflow = 'invokeworkflow'; +const invokenestedagent = 'invokenestedagent'; const sendtobatch = 'sendtobatch'; const batch = 'batch'; @@ -219,6 +234,7 @@ const supportedConsumptionManifestObjects = new Map([ ['azurefunction', selectFunctionManifest], ['azureswaggerfunction', selectSwaggerFunctionManifest], [invokeworkflow, invokeWorkflowManifest], + [invokenestedagent, invokeNestedAgentManifest], [sendtobatch, sendToBatchManifest], [batch, batchTriggerManifest], [as2encode, as2EncodeManifest], diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operations/invokeWorkflow.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operations/invokeWorkflow.ts index dd22baa1a15..c44ce6a5124 100644 --- a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operations/invokeWorkflow.ts +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/operations/invokeWorkflow.ts @@ -37,3 +37,26 @@ export const invokeWorkflowOperation = { iconUri, }, }; + +export const invokeNestedAgentOperation = { + id: 'invokenestedagent', + name: 'invokenestedagent', + type: 'nestedagent', + properties: { + api: { + id: '/connectionProviders/workflow', + name: 'connectionProviders/workflow', + displayName: 'Azure Logic Apps', + iconUri, + brandColor, + description: 'Azure Logic Apps', + }, + capabilities: ['azureResourceSelection'], + summary: 'Choose a Nested Agent workflow', + description: 'Send a task to a nested agent workflow in the same region', + visibility: 'Important', + operationType: 'NestedAgent', + brandColor, + iconUri, + }, +}; diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/search.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/search.ts index 48b52f7f577..03a6190cf8c 100644 --- a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/search.ts +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/search.ts @@ -93,6 +93,7 @@ export class ConsumptionSearchService extends BaseSearchService { OperationsData.appServiceTriggerOperation, OperationsData.functionOperation, OperationsData.invokeWorkflowOperation, + OperationsData.invokeNestedAgentOperation, OperationsData.sendToBatchOperation, OperationsData.batchTriggerOperation, OperationsData.as2EncodeOperation, diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/search.ts b/libs/logic-apps-shared/src/designer-client-services/lib/search.ts index 07b29ced969..7cd316e0d2c 100644 --- a/libs/logic-apps-shared/src/designer-client-services/lib/search.ts +++ b/libs/logic-apps-shared/src/designer-client-services/lib/search.ts @@ -13,6 +13,7 @@ export interface ISearchService { getBuiltInConnectors(): Promise; getAllOperations(): Promise; getRequestWorkflows?(): Promise[]>; + getAgentWorkflows?(): Promise[]>; getBatchWorkflows?(): Promise[]>; getWorkflowTriggers?(workflowId: string): Promise[]>; getAzureOperationsByPage(page: number): Promise; diff --git a/package.json b/package.json index 512f769180a..34091b8650b 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "rimraf": "^5.0.5", "sherif": "^0.8.4", "tsup": "^8.0.2", - "turbo": "^2.3.0", + "turbo": "^2.6.3", "typescript": "5.7.2", "typescript-eslint": "7.7.0", "vite-plugin-mkcert": "^1.17.8", @@ -68,7 +68,11 @@ }, "license": "MIT", "lint-staged": { - "*.{js,ts,tsx}": ["npm run extract", "eslint --cache --fix", "biome check --write"] + "*.{js,ts,tsx}": [ + "npm run extract", + "eslint --cache --fix", + "biome check --write" + ] }, "private": true, "scripts": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8112ee07292..e7186bb4007 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -237,8 +237,8 @@ importers: specifier: ^8.0.2 version: 8.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.7.2))(typescript@5.7.2) turbo: - specifier: ^2.3.0 - version: 2.3.0 + specifier: ^2.6.3 + version: 2.6.3 typescript: specifier: 5.7.2 version: 5.7.2 @@ -13853,38 +13853,38 @@ packages: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - turbo-darwin-64@2.3.0: - resolution: {integrity: sha512-pji+D49PhFItyQjf2QVoLZw2d3oRGo8gJgKyOiRzvip78Rzie74quA8XNwSg/DuzM7xx6gJ3p2/LylTTlgZXxQ==} + turbo-darwin-64@2.6.3: + resolution: {integrity: sha512-BlJJDc1CQ7SK5Y5qnl7AzpkvKSnpkfPmnA+HeU/sgny3oHZckPV2776ebO2M33CYDSor7+8HQwaodY++IINhYg==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.3.0: - resolution: {integrity: sha512-AJrGIL9BO41mwDF/IBHsNGwvtdyB911vp8f5mbNo1wG66gWTvOBg7WCtYQBvCo11XTenTfXPRSsAb7w3WAZb6w==} + turbo-darwin-arm64@2.6.3: + resolution: {integrity: sha512-MwVt7rBKiOK7zdYerenfCRTypefw4kZCue35IJga9CH1+S50+KTiCkT6LBqo0hHeoH2iKuI0ldTF2a0aB72z3w==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.3.0: - resolution: {integrity: sha512-jZqW6vc2sPJT3M/3ZmV1Cg4ecQVPqsbHncG/RnogHpBu783KCSXIndgxvUQNm9qfgBYbZDBnP1md63O4UTElhw==} + turbo-linux-64@2.6.3: + resolution: {integrity: sha512-cqpcw+dXxbnPtNnzeeSyWprjmuFVpHJqKcs7Jym5oXlu/ZcovEASUIUZVN3OGEM6Y/OTyyw0z09tOHNt5yBAVg==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.3.0: - resolution: {integrity: sha512-HUbDLJlvd/hxuyCNO0BmEWYQj0TugRMvSQeG8vHJH+Lq8qOgDAe7J0K73bFNbZejZQxW3C3XEiZFB3pnpO78+A==} + turbo-linux-arm64@2.6.3: + resolution: {integrity: sha512-MterpZQmjXyr4uM7zOgFSFL3oRdNKeflY7nsjxJb2TklsYqiu3Z9pQ4zRVFFH8n0mLGna7MbQMZuKoWqqHb45w==} cpu: [arm64] os: [linux] - turbo-windows-64@2.3.0: - resolution: {integrity: sha512-c5rxrGNTYDWX9QeMzWLFE9frOXnKjHGEvQMp1SfldDlbZYsloX9UKs31TzUThzfTgTiz8NYuShaXJ2UvTMnV/g==} + turbo-windows-64@2.6.3: + resolution: {integrity: sha512-biDU70v9dLwnBdLf+daoDlNJVvqOOP8YEjqNipBHzgclbQlXbsi6Gqqelp5er81Qo3BiRgmTNx79oaZQTPb07Q==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.3.0: - resolution: {integrity: sha512-7qfUuYhfIVb1AZgs89DxhXK+zZez6O2ocmixEQ4hXZK7ytnBt5vaz2zGNJJKFNYIL5HX1C3tuHolnpNgDNCUIg==} + turbo-windows-arm64@2.6.3: + resolution: {integrity: sha512-dDHVKpSeukah3VsI/xMEKeTnV9V9cjlpFSUs4bmsUiLu3Yv2ENlgVEZv65wxbeE0bh0jjpmElDT+P1KaCxArQQ==} cpu: [arm64] os: [win32] - turbo@2.3.0: - resolution: {integrity: sha512-/uOq5o2jwRPyaUDnwBpOR5k9mQq4c3wziBgWNWttiYQPmbhDtrKYPRBxTvA2WpgQwRIbt8UM612RMN8n/TvmHA==} + turbo@2.6.3: + resolution: {integrity: sha512-bf6YKUv11l5Xfcmg76PyWoy/e2vbkkxFNBGJSnfdSXQC33ZiUfutYh6IXidc5MhsnrFkWfdNNLyaRk+kHMLlwA==} hasBin: true tweetnacl@0.14.5: @@ -23048,7 +23048,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.15 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(@vitest/ui@3.2.4)(happy-dom@20.0.2)(jiti@1.21.0)(jsdom@26.1.0)(less@4.2.0)(terser@5.30.2)(yaml@2.7.0) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.12.7)(@vitest/ui@3.2.4)(happy-dom@20.0.2)(jiti@1.21.0)(jsdom@24.0.0)(less@4.2.0)(terser@5.30.2)(yaml@2.7.0) '@vitest/utils@3.2.4': dependencies: @@ -31345,32 +31345,32 @@ snapshots: tunnel@0.0.6: {} - turbo-darwin-64@2.3.0: + turbo-darwin-64@2.6.3: optional: true - turbo-darwin-arm64@2.3.0: + turbo-darwin-arm64@2.6.3: optional: true - turbo-linux-64@2.3.0: + turbo-linux-64@2.6.3: optional: true - turbo-linux-arm64@2.3.0: + turbo-linux-arm64@2.6.3: optional: true - turbo-windows-64@2.3.0: + turbo-windows-64@2.6.3: optional: true - turbo-windows-arm64@2.3.0: + turbo-windows-arm64@2.6.3: optional: true - turbo@2.3.0: + turbo@2.6.3: optionalDependencies: - turbo-darwin-64: 2.3.0 - turbo-darwin-arm64: 2.3.0 - turbo-linux-64: 2.3.0 - turbo-linux-arm64: 2.3.0 - turbo-windows-64: 2.3.0 - turbo-windows-arm64: 2.3.0 + turbo-darwin-64: 2.6.3 + turbo-darwin-arm64: 2.6.3 + turbo-linux-64: 2.6.3 + turbo-linux-arm64: 2.6.3 + turbo-windows-64: 2.6.3 + turbo-windows-arm64: 2.6.3 tweetnacl@0.14.5: {} @@ -31924,15 +31924,15 @@ snapshots: '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 chai: 5.2.0 - debug: 4.4.3 + debug: 4.4.1(supports-color@8.1.1) expect-type: 1.2.1 magic-string: 0.30.17 pathe: 2.0.3 - picomatch: 4.0.3 + picomatch: 4.0.2 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.15 + tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 vite: 6.4.1(@types/node@24.7.2)(jiti@1.21.0)(less@4.2.0)(terser@5.30.2)(yaml@2.7.0) From b1186c9f66fd0307afe5910e129310b7a71a87a1 Mon Sep 17 00:00:00 2001 From: "Bhavya ." Date: Mon, 15 Dec 2025 15:17:24 +0530 Subject: [PATCH 2/5] Reset package files to main --- package.json | 8 ++---- pnpm-lock.yaml | 66 +++++++++++++++++++++++++------------------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 34091b8650b..512f769180a 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "rimraf": "^5.0.5", "sherif": "^0.8.4", "tsup": "^8.0.2", - "turbo": "^2.6.3", + "turbo": "^2.3.0", "typescript": "5.7.2", "typescript-eslint": "7.7.0", "vite-plugin-mkcert": "^1.17.8", @@ -68,11 +68,7 @@ }, "license": "MIT", "lint-staged": { - "*.{js,ts,tsx}": [ - "npm run extract", - "eslint --cache --fix", - "biome check --write" - ] + "*.{js,ts,tsx}": ["npm run extract", "eslint --cache --fix", "biome check --write"] }, "private": true, "scripts": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c82333af91..ce926a80a2d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -237,8 +237,8 @@ importers: specifier: ^8.0.2 version: 8.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.12.7)(typescript@5.7.2))(typescript@5.7.2) turbo: - specifier: ^2.6.3 - version: 2.6.3 + specifier: ^2.3.0 + version: 2.3.0 typescript: specifier: 5.7.2 version: 5.7.2 @@ -13815,38 +13815,38 @@ packages: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - turbo-darwin-64@2.6.3: - resolution: {integrity: sha512-BlJJDc1CQ7SK5Y5qnl7AzpkvKSnpkfPmnA+HeU/sgny3oHZckPV2776ebO2M33CYDSor7+8HQwaodY++IINhYg==} + turbo-darwin-64@2.3.0: + resolution: {integrity: sha512-pji+D49PhFItyQjf2QVoLZw2d3oRGo8gJgKyOiRzvip78Rzie74quA8XNwSg/DuzM7xx6gJ3p2/LylTTlgZXxQ==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.6.3: - resolution: {integrity: sha512-MwVt7rBKiOK7zdYerenfCRTypefw4kZCue35IJga9CH1+S50+KTiCkT6LBqo0hHeoH2iKuI0ldTF2a0aB72z3w==} + turbo-darwin-arm64@2.3.0: + resolution: {integrity: sha512-AJrGIL9BO41mwDF/IBHsNGwvtdyB911vp8f5mbNo1wG66gWTvOBg7WCtYQBvCo11XTenTfXPRSsAb7w3WAZb6w==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.6.3: - resolution: {integrity: sha512-cqpcw+dXxbnPtNnzeeSyWprjmuFVpHJqKcs7Jym5oXlu/ZcovEASUIUZVN3OGEM6Y/OTyyw0z09tOHNt5yBAVg==} + turbo-linux-64@2.3.0: + resolution: {integrity: sha512-jZqW6vc2sPJT3M/3ZmV1Cg4ecQVPqsbHncG/RnogHpBu783KCSXIndgxvUQNm9qfgBYbZDBnP1md63O4UTElhw==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.6.3: - resolution: {integrity: sha512-MterpZQmjXyr4uM7zOgFSFL3oRdNKeflY7nsjxJb2TklsYqiu3Z9pQ4zRVFFH8n0mLGna7MbQMZuKoWqqHb45w==} + turbo-linux-arm64@2.3.0: + resolution: {integrity: sha512-HUbDLJlvd/hxuyCNO0BmEWYQj0TugRMvSQeG8vHJH+Lq8qOgDAe7J0K73bFNbZejZQxW3C3XEiZFB3pnpO78+A==} cpu: [arm64] os: [linux] - turbo-windows-64@2.6.3: - resolution: {integrity: sha512-biDU70v9dLwnBdLf+daoDlNJVvqOOP8YEjqNipBHzgclbQlXbsi6Gqqelp5er81Qo3BiRgmTNx79oaZQTPb07Q==} + turbo-windows-64@2.3.0: + resolution: {integrity: sha512-c5rxrGNTYDWX9QeMzWLFE9frOXnKjHGEvQMp1SfldDlbZYsloX9UKs31TzUThzfTgTiz8NYuShaXJ2UvTMnV/g==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.6.3: - resolution: {integrity: sha512-dDHVKpSeukah3VsI/xMEKeTnV9V9cjlpFSUs4bmsUiLu3Yv2ENlgVEZv65wxbeE0bh0jjpmElDT+P1KaCxArQQ==} + turbo-windows-arm64@2.3.0: + resolution: {integrity: sha512-7qfUuYhfIVb1AZgs89DxhXK+zZez6O2ocmixEQ4hXZK7ytnBt5vaz2zGNJJKFNYIL5HX1C3tuHolnpNgDNCUIg==} cpu: [arm64] os: [win32] - turbo@2.6.3: - resolution: {integrity: sha512-bf6YKUv11l5Xfcmg76PyWoy/e2vbkkxFNBGJSnfdSXQC33ZiUfutYh6IXidc5MhsnrFkWfdNNLyaRk+kHMLlwA==} + turbo@2.3.0: + resolution: {integrity: sha512-/uOq5o2jwRPyaUDnwBpOR5k9mQq4c3wziBgWNWttiYQPmbhDtrKYPRBxTvA2WpgQwRIbt8UM612RMN8n/TvmHA==} hasBin: true tweetnacl@0.14.5: @@ -22982,7 +22982,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.15 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.12.7)(@vitest/ui@3.2.4)(happy-dom@20.0.2)(jiti@1.21.0)(jsdom@24.0.0)(less@4.2.0)(terser@5.30.2)(yaml@2.7.0) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(@vitest/ui@3.2.4)(happy-dom@20.0.2)(jiti@1.21.0)(jsdom@26.1.0)(less@4.2.0)(terser@5.30.2)(yaml@2.7.0) '@vitest/utils@3.2.4': dependencies: @@ -31270,32 +31270,32 @@ snapshots: tunnel@0.0.6: {} - turbo-darwin-64@2.6.3: + turbo-darwin-64@2.3.0: optional: true - turbo-darwin-arm64@2.6.3: + turbo-darwin-arm64@2.3.0: optional: true - turbo-linux-64@2.6.3: + turbo-linux-64@2.3.0: optional: true - turbo-linux-arm64@2.6.3: + turbo-linux-arm64@2.3.0: optional: true - turbo-windows-64@2.6.3: + turbo-windows-64@2.3.0: optional: true - turbo-windows-arm64@2.6.3: + turbo-windows-arm64@2.3.0: optional: true - turbo@2.6.3: + turbo@2.3.0: optionalDependencies: - turbo-darwin-64: 2.6.3 - turbo-darwin-arm64: 2.6.3 - turbo-linux-64: 2.6.3 - turbo-linux-arm64: 2.6.3 - turbo-windows-64: 2.6.3 - turbo-windows-arm64: 2.6.3 + turbo-darwin-64: 2.3.0 + turbo-darwin-arm64: 2.3.0 + turbo-linux-64: 2.3.0 + turbo-linux-arm64: 2.3.0 + turbo-windows-64: 2.3.0 + turbo-windows-arm64: 2.3.0 tweetnacl@0.14.5: {} @@ -31849,15 +31849,15 @@ snapshots: '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 chai: 5.2.0 - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3 expect-type: 1.2.1 magic-string: 0.30.17 pathe: 2.0.3 - picomatch: 4.0.2 + picomatch: 4.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 vite: 6.4.1(@types/node@24.7.2)(jiti@1.21.0)(less@4.2.0)(terser@5.30.2)(yaml@2.7.0) From 3c3910099e2607fb0aa9f2f0f46179f9d5f626c7 Mon Sep 17 00:00:00 2001 From: "Bhavya ." Date: Mon, 15 Dec 2025 15:40:02 +0530 Subject: [PATCH 3/5] Adding Unit Tests --- .../lib/base/__test__/search.spec.ts | 203 ++++++++++++++++++ .../__tests__/operationmanifest.spec.ts | 125 +++++++++++ 2 files changed, 328 insertions(+) create mode 100644 libs/logic-apps-shared/src/designer-client-services/lib/base/__test__/search.spec.ts create mode 100644 libs/logic-apps-shared/src/designer-client-services/lib/consumption/__tests__/operationmanifest.spec.ts diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/base/__test__/search.spec.ts b/libs/logic-apps-shared/src/designer-client-services/lib/base/__test__/search.spec.ts new file mode 100644 index 00000000000..d47aab2e9c1 --- /dev/null +++ b/libs/logic-apps-shared/src/designer-client-services/lib/base/__test__/search.spec.ts @@ -0,0 +1,203 @@ +import { describe, test, expect, beforeEach, vi } from 'vitest'; +import type { IHttpClient } from '../../httpClient'; + +// Create a concrete implementation for testing +class TestSearchService { + constructor(private options: any) {} + + private async getWorkflows(filter: string): Promise { + const { httpClient, apiHubServiceDetails } = this.options; + const uri = `/subscriptions/${apiHubServiceDetails.subscriptionId}/providers/Microsoft.Logic/workflows`; + const queryParameters = { + 'api-version': apiHubServiceDetails.apiVersion, + $filter: filter, + }; + const response = await httpClient.get({ uri, queryParameters }); + return response?.value ?? []; + } + + public async getAgentWorkflows(): Promise { + const requestWorkflows = await this.getWorkflows( + "contains(Trigger, 'Request') and (properties/integrationServiceEnvironmentResourceId eq null)" + ); + return requestWorkflows.filter((workflow: any) => { + const triggers = workflow.properties?.definition?.triggers ?? {}; + return Object.values(triggers).some((trigger: any) => trigger.kind?.toLowerCase() === 'agent'); + }); + } +} + +describe('BaseSearchService', () => { + let mockHttpClient: IHttpClient; + let searchService: TestSearchService; + let mockOptions: any; + + beforeEach(() => { + mockHttpClient = { + get: vi.fn(), + post: vi.fn(), + put: vi.fn(), + delete: vi.fn(), + patch: vi.fn(), + dispose: vi.fn(), + }; + + mockOptions = { + httpClient: mockHttpClient, + apiHubServiceDetails: { + subscriptionId: 'test-subscription', + location: 'westus', + apiVersion: '2016-06-01', + }, + }; + + searchService = new TestSearchService(mockOptions); + }); + + describe('getAgentWorkflows', () => { + test('should return only workflows with Agent triggers', async () => { + const mockWorkflows = { + value: [ + { + id: '/workflows/agent-workflow', + name: 'agent-workflow', + properties: { + definition: { + triggers: { + manual: { + type: 'Request', + kind: 'Agent', + }, + }, + }, + }, + }, + { + id: '/workflows/regular-workflow', + name: 'regular-workflow', + properties: { + definition: { + triggers: { + manual: { + type: 'Request', + kind: 'Http', + }, + }, + }, + }, + }, + ], + }; + + vi.mocked(mockHttpClient.get).mockResolvedValue(mockWorkflows); + + const result = await searchService.getAgentWorkflows(); + + expect(result).toHaveLength(1); + expect(result[0].name).toBe('agent-workflow'); + }); + + test('should handle case-insensitive Agent kind matching', async () => { + const mockWorkflows = { + value: [ + { + id: '/workflows/agent-uppercase', + name: 'agent-uppercase', + properties: { + definition: { + triggers: { + manual: { type: 'Request', kind: 'AGENT' }, + }, + }, + }, + }, + { + id: '/workflows/agent-mixedcase', + name: 'agent-mixedcase', + properties: { + definition: { + triggers: { + manual: { type: 'Request', kind: 'AgEnT' }, + }, + }, + }, + }, + ], + }; + + vi.mocked(mockHttpClient.get).mockResolvedValue(mockWorkflows); + + const result = await searchService.getAgentWorkflows(); + + expect(result).toHaveLength(2); + }); + + test('should return empty array when no Agent workflows exist', async () => { + const mockWorkflows = { + value: [ + { + id: '/workflows/regular', + name: 'regular', + properties: { + definition: { + triggers: { + manual: { type: 'Request', kind: 'Http' }, + }, + }, + }, + }, + ], + }; + + vi.mocked(mockHttpClient.get).mockResolvedValue(mockWorkflows); + + const result = await searchService.getAgentWorkflows(); + + expect(result).toHaveLength(0); + }); + + test('should handle workflows with no triggers defined', async () => { + const mockWorkflows = { + value: [ + { + id: '/workflows/no-triggers', + name: 'no-triggers', + properties: { + definition: {}, + }, + }, + ], + }; + + vi.mocked(mockHttpClient.get).mockResolvedValue(mockWorkflows); + + const result = await searchService.getAgentWorkflows(); + + expect(result).toHaveLength(0); + }); + + test('should handle workflows with undefined kind', async () => { + const mockWorkflows = { + value: [ + { + id: '/workflows/no-kind', + name: 'no-kind', + properties: { + definition: { + triggers: { + manual: { type: 'Request' }, + }, + }, + }, + }, + ], + }; + + vi.mocked(mockHttpClient.get).mockResolvedValue(mockWorkflows); + + const result = await searchService.getAgentWorkflows(); + + expect(result).toHaveLength(0); + }); + }); +}); diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/__tests__/operationmanifest.spec.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/__tests__/operationmanifest.spec.ts new file mode 100644 index 00000000000..4e25a2c1c30 --- /dev/null +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/__tests__/operationmanifest.spec.ts @@ -0,0 +1,125 @@ +import { describe, test, expect, beforeEach, vi } from 'vitest'; +import { ConsumptionOperationManifestService } from '../operationmanifest'; +import type { IHttpClient } from '../../httpClient'; + +describe('ConsumptionOperationManifestService', () => { + let operationManifestService: ConsumptionOperationManifestService; + let mockHttpClient: IHttpClient; + let mockOptions: any; + + beforeEach(() => { + mockHttpClient = { + get: vi.fn(), + post: vi.fn(), + put: vi.fn(), + delete: vi.fn(), + patch: vi.fn(), + dispose: vi.fn(), + }; + + mockOptions = { + apiVersion: '2016-06-01', + baseUrl: 'https://api.example.com', + httpClient: mockHttpClient, + subscriptionId: 'test-subscription', + location: 'westus', + }; + + operationManifestService = new ConsumptionOperationManifestService(mockOptions); + }); + + describe('getOperationInfo', () => { + test('should return correct operation info for workflow type', async () => { + const definition = { + type: 'workflow', + inputs: {}, + }; + + const result = await operationManifestService.getOperationInfo(definition, false); + + expect(result.connectorId).toBe('/connectionProviders/workflow'); + expect(result.operationId).toBe('invokeworkflow'); + }); + + test('should return correct operation info for nestedagent type', async () => { + const definition = { + type: 'nestedagent', + inputs: {}, + }; + + const result = await operationManifestService.getOperationInfo(definition, false); + + expect(result.connectorId).toBe('/connectionProviders/workflow'); + expect(result.operationId).toBe('invokenestedagent'); + }); + + test('should handle case-insensitive nestedagent type', async () => { + const definition = { + type: 'NestedAgent', + inputs: {}, + }; + + const result = await operationManifestService.getOperationInfo(definition, false); + + expect(result.connectorId).toBe('/connectionProviders/workflow'); + expect(result.operationId).toBe('invokenestedagent'); + }); + + test('should return correct operation info for function type without uri', async () => { + const definition = { + type: 'function', + inputs: {}, + }; + + const result = await operationManifestService.getOperationInfo(definition, false); + + expect(result.connectorId).toBe('/connectionProviders/azureFunctionOperation'); + expect(result.operationId).toBe('azureFunction'); + }); + + test('should return correct operation info for function type with uri', async () => { + const definition = { + type: 'function', + inputs: { uri: 'https://example.com/api' }, + }; + + const result = await operationManifestService.getOperationInfo(definition, false); + + expect(result.connectorId).toBe('/connectionProviders/azureFunctionOperation'); + expect(result.operationId).toBe('azureSwaggerFunction'); + }); + }); + + describe('isSupported', () => { + test('should return true for nestedagent operation type', () => { + const result = operationManifestService.isSupported('nestedagent'); + expect(result).toBe(true); + }); + + test('should return true for workflow operation type', () => { + const result = operationManifestService.isSupported('workflow'); + expect(result).toBe(true); + }); + + test('should handle case-insensitive operation types', () => { + const result = operationManifestService.isSupported('NestedAgent'); + expect(result).toBe(true); + }); + }); + + describe('getOperationManifest', () => { + test('should return manifest for invokenestedagent operation', async () => { + const result = await operationManifestService.getOperationManifest('/connectionProviders/workflow', 'invokenestedagent'); + + expect(result).toBeDefined(); + expect(result.properties).toBeDefined(); + }); + + test('should return manifest for invokeWorkflow operation', async () => { + const result = await operationManifestService.getOperationManifest('/connectionProviders/workflow', 'invokeWorkflow'); + + expect(result).toBeDefined(); + expect(result.properties).toBeDefined(); + }); + }); +}); From 5487000b3a86372a41d1948f7bd8d05ac09114c7 Mon Sep 17 00:00:00 2001 From: "Bhavya ." Date: Mon, 15 Dec 2025 15:56:31 +0530 Subject: [PATCH 4/5] Making task message mandatory --- .../lib/consumption/manifests/invokeNestedAgent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts index 746adcc8cef..05d8bb875ba 100644 --- a/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts +++ b/libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/invokeNestedAgent.ts @@ -13,7 +13,7 @@ export const invokeNestedAgentManifest = { inputs: { type: 'object', - required: ['host'], + required: ['host', 'taskMessage'], properties: { taskMessage: { title: 'Task Message', From 6ba8dd44ec1dfe776876e6b41b854e567d611089 Mon Sep 17 00:00:00 2001 From: "Bhavya ." Date: Mon, 5 Jan 2026 17:27:02 +0530 Subject: [PATCH 5/5] Filtering for nested agent operation --- libs/designer/src/lib/ui/panel/recommendation/searchView.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/designer/src/lib/ui/panel/recommendation/searchView.tsx b/libs/designer/src/lib/ui/panel/recommendation/searchView.tsx index e12a6080327..5f69ef7c607 100644 --- a/libs/designer/src/lib/ui/panel/recommendation/searchView.tsx +++ b/libs/designer/src/lib/ui/panel/recommendation/searchView.tsx @@ -125,7 +125,10 @@ export const SearchView: FC = ({ return false; } - if (equals(type, constants.NODE.TYPE.NESTED_AGENT) && id === 'invokeNestedAgent') { + if (equals(type, constants.NODE.TYPE.NESTED_AGENT) && equals(id, 'invokenestedagent')) { + if (!isA2AWorkflow) { + return false; + } if (!(isWithinAgenticLoop || isAgentTool)) { return false; }