From 44349688a4629081172b35c12c5d1a7cb301f390 Mon Sep 17 00:00:00 2001 From: Esteban Romero Date: Thu, 4 Jun 2026 12:13:21 -0300 Subject: [PATCH] fix: handle sub-agents with one action --- src/commands/agent/generate/test-spec.ts | 4 +- .../commands/agent/generate/test-spec.test.ts | 88 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/commands/agent/generate/test-spec.ts b/src/commands/agent/generate/test-spec.ts index dfac863b..e7ea3746 100644 --- a/src/commands/agent/generate/test-spec.ts +++ b/src/commands/agent/generate/test-spec.ts @@ -358,7 +358,7 @@ export async function getPluginsAndFunctions( localDeveloperName: string; masterLabel: string; pluginType: string; - localActionLinks?: Array<{ functionName: string }>; + localActionLinks?: Array<{ functionName: string }> | { functionName: string }; genAiPluginInstructions: { description: string; developerName: string; @@ -371,7 +371,7 @@ export async function getPluginsAndFunctions( }; genAiFunctions = ensureArray( parsedPlannerBundle.GenAiPlannerBundle.localTopics - .flatMap((topic) => topic.localActionLinks?.map((lal) => lal.functionName)) + .flatMap((topic) => ensureArray(topic.localActionLinks)?.map((lal) => lal.functionName)) .filter((f) => typeof f === 'string') ); diff --git a/test/commands/agent/generate/test-spec.test.ts b/test/commands/agent/generate/test-spec.test.ts index f399115b..9df3fbd6 100644 --- a/test/commands/agent/generate/test-spec.test.ts +++ b/test/commands/agent/generate/test-spec.test.ts @@ -186,6 +186,94 @@ describe('AgentGenerateTestSpec Helper Methods', () => { }); }); + it('should not fail when a topic has a single localActionLinks (fast-xml-parser returns object, not array)', async () => { + const name = 'myAgent'; + const cs = new ComponentSet([ + { fullName: name, type: { name: 'Bot', id: 'bot', directoryName: 'bot' } }, + { + fullName: 'myGenAiPlannerBundle', + type: { name: 'GenAiPlannerBundle', id: 'genaiplannerbundle', directoryName: 'genaiplannerbundle' }, + }, + { + fullName: 'local_weather_16jDU000000Gmm5', + type: { name: 'GenAiPlugin', id: 'genaiplugin', directoryName: 'genaiplugin' }, + }, + ]); + + // Call sequence for getComponentFilenamesByNameAndType: + // 1. Bot (getMetadataFilePaths) + // 2. GenAiPlannerBundle (getMetadataFilePaths) — no GenAiPlanner in CS so no call for it + // 3. GenAiPlugin for local_weather (reduce over localTopicLinks) + $$.stub(cs, 'getComponentFilenamesByNameAndType') + .onFirstCall() + .returns(['myBot.bot-meta.xml']) + .onSecondCall() + .returns(['myGenAiPlannerBundle.genAiPlannerBundle-meta.xml']) + .onThirdCall() + .returns(['local_weather.genAiPlugin-meta.xml']); + + // Call sequence for readFile: + // 1. BotVersion XML + // 2. GenAiPlanner attempt — readFile(undefined) because {} has no key → rejects (caught silently) + // 3. GenAiPlannerBundle XML + $$.stub(fs.promises, 'readFile') + .onFirstCall() + .resolves( + ` + + + myGenAiPlannerBundle + + +` + ) + .onSecondCall() + .rejects() // readFile(undefined) from empty genAiPlanners map + .onThirdCall() + .resolves( + ` + + A resort agent. + + local_weather_16jDU000000Gmm5 + + + off_topic_16jDU000000Gmm5 + false + Redirect off-topic requests + off_topic_16jDU000000Gmm5 + en_US + off_topic + Off Topic + Topic + + + local_weather_16jDU000000Gmm5 + false + Provides weather info. + local_weather_16jDU000000Gmm5 + en_US + + check_weather_179DU000000Gn0s + + local_weather + Local Weather + Topic + + Local Info Agent + Atlas__ConcurrentMultiAgentOrchestration + +` + ); + + const result = await getPluginsAndFunctions(name, cs); + expect(result.genAiFunctions).to.deep.equal(['check_weather_179DU000000Gn0s']); + expect(result.genAiPlugins).to.deep.equal({ + // eslint-disable-next-line camelcase + local_weather_16jDU000000Gmm5: 'local_weather.genAiPlugin-meta.xml', + }); + }); + it('should not fail when theres no actions', async () => { const name = 'myAgent'; const cs = new ComponentSet([