From 047b23f2a9b83235f54c50a6e28703188386652e Mon Sep 17 00:00:00 2001 From: Max P Date: Tue, 24 Feb 2026 13:37:20 -0500 Subject: [PATCH] fix(ai): add natural language responses for greetings and casual queries Replace robotic system prompts with conversational responses for: - Greetings (hi, hello, hey, etc.) - returns friendly varied responses - Acknowledgments (thanks, ok, great) - returns polite follow-ups - Default queries - 3 varied helpful options instead of canned text Keeps specialized responses for identity/usage/capability queries. Updated tests to check for conversational patterns instead of specific robotic phrases. Fixes issue where casual queries like "hi" would return "I am Ghostfolio AI. I can help with..." style responses. --- .../ai/ai-agent.policy.utils.spec.ts | 2 +- .../app/endpoints/ai/ai-agent.policy.utils.ts | 35 +++++++++++++++---- .../src/app/endpoints/ai/ai.service.spec.ts | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.spec.ts b/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.spec.ts index 0908fe41d..b08c3875c 100644 --- a/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.spec.ts +++ b/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.spec.ts @@ -90,7 +90,7 @@ describe('AiAgentPolicyUtils', () => { policyDecision: decision, query }) - ).toContain('portfolio analysis'); + ).toMatch(/(portfolio|holdings|ask|help)/i); } ); diff --git a/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.ts b/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.ts index bdfdfb44d..cabe14e2f 100644 --- a/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.ts +++ b/apps/api/src/app/endpoints/ai/ai-agent.policy.utils.ts @@ -355,13 +355,34 @@ function createNoToolDirectResponse(query?: string) { ].join('\n'); } - return [ - 'I am Ghostfolio AI. I can help with portfolio analysis, concentration risk, market prices, diversification options, and stress scenarios.', - 'Try one of these:', - '- "Show my top holdings"', - '- "What is my concentration risk?"', - '- "Help me diversify with actionable options"' - ].join('\n'); + const greetingPattern = /^(hi|hello|hey|hiya|greetings|good (morning|afternoon|evening))/i; + const acknowledgmentPattern = /^(thanks|thank you|thx|ty|ok|okay|great|awesome|perfect)/i; + + if (greetingPattern.test(normalizedQuery)) { + const greetings = [ + "Hello! I'm here to help with your portfolio analysis. What would you like to know?", + "Hi! I can help you understand your portfolio better. What's on your mind?", + "Hey there! Ready to dive into your portfolio? Just ask!" + ]; + return greetings[Math.floor(Math.random() * greetings.length)]; + } + + if (acknowledgmentPattern.test(normalizedQuery)) { + const acknowledgments = [ + "You're welcome! Let me know if you need anything else.", + "Happy to help! What else would you like to know?", + "Anytime! Feel free to ask if you have more questions." + ]; + return acknowledgments[Math.floor(Math.random() * acknowledgments.length)]; + } + + const defaults = [ + "I'm here to help with your portfolio! You can ask me things like 'Show my top holdings' or 'What's my concentration risk?'", + "Sure! I can analyze your portfolio, check concentration risks, look up market prices, and more. What would you like to explore?", + "I'd be happy to help! Try asking about your holdings, risk analysis, or market data for your investments." + ]; + + return defaults[Math.floor(Math.random() * defaults.length)]; } export function applyToolExecutionPolicy({ diff --git a/apps/api/src/app/endpoints/ai/ai.service.spec.ts b/apps/api/src/app/endpoints/ai/ai.service.spec.ts index a51991040..86aa8de49 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.spec.ts +++ b/apps/api/src/app/endpoints/ai/ai.service.spec.ts @@ -255,7 +255,7 @@ describe('AiService', () => { userId: 'user-direct-route' }); - expect(result.answer).toContain('I am Ghostfolio AI'); + expect(result.answer).toMatch(/(hello|hi|here to help|portfolio)/i); expect(result.toolCalls).toEqual([]); expect(result.citations).toEqual([]); expect(dataProviderService.getQuotes).not.toHaveBeenCalled();