From 59779727debe6c819c66dc3810c3712532d78b02 Mon Sep 17 00:00:00 2001 From: konard Date: Fri, 17 Oct 2025 19:46:57 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #15 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: undefined --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e42fbaa --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: undefined +Your prepared branch: issue-15-0debf3e4 +Your prepared working directory: /tmp/gh-issue-solver-1760719614707 + +Proceed. \ No newline at end of file From a5e969dd1a09859919ba1c8c8a2df5c0982a8062 Mon Sep 17 00:00:00 2001 From: konard Date: Fri, 17 Oct 2025 19:53:57 +0300 Subject: [PATCH 2/3] Add trigger for combined greeting and acquaintance messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements detection and response for messages that contain both a greeting and an acquaintance question (e.g., "Привет! Мы знакомы?"). - Created GreetingAndAcquaintanceTrigger that uses partial regex matching to detect both greeting and acquaintance patterns within a single message - Uses greeting emojis/words and stickers combined with "знакомы?" patterns - Responds with contextually appropriate combined responses - Added comprehensive tests covering various message combinations - Exported acquaintedRegex from acquaintance trigger for reuse 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../triggers/greeting-and-acquaintance.js | 65 +++++++++++++++++++ triggers/acquaintance.js | 3 +- triggers/greeting-and-acquaintance.js | 63 ++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 __tests__/triggers/greeting-and-acquaintance.js create mode 100644 triggers/greeting-and-acquaintance.js diff --git a/__tests__/triggers/greeting-and-acquaintance.js b/__tests__/triggers/greeting-and-acquaintance.js new file mode 100644 index 0000000..c28b0b5 --- /dev/null +++ b/__tests__/triggers/greeting-and-acquaintance.js @@ -0,0 +1,65 @@ +const { trigger: greetingAndAcquaintanceTrigger, combinedResponses, containsGreetingAndAcquaintance } = require('../../triggers/greeting-and-acquaintance'); +const { enqueueMessage } = require('../../outgoing-messages'); +jest.mock('../../outgoing-messages'); + +const triggerDescription = 'greeting and acquaintance trigger'; + +describe(triggerDescription, () => { + beforeEach(() => { + enqueueMessage.mockClear(); + }); + + test.each([ + ['Привет! Мы знакомы?'], + ['Привет. Мы знакомы?'], + ['Привет, мы знакомы с тобой?'], + ['Приветик! Мы знакомы?'], + ['Здравствуйте! Мы знакомы?'], + ['🖐 Мы знакомы?'], + ['👋 Мы знакомы с тобой?'], + ['Мы знакомы? Привет!'], + ['Знакомы мы? Привет'], + ['Привет, знакомы мы?'], + ['Салют! Мы знакомы?'], + ['Хай! Мы знакомы с тобой?'], + ])(`"%s" message matches ${triggerDescription} and gives expected response`, (incomingMessage) => { + const context = { request: { isFromUser: true, isOutbox: false, text: incomingMessage, attachments: [] } }; + expect(greetingAndAcquaintanceTrigger.condition(context)).toBe(true); + if (greetingAndAcquaintanceTrigger.condition(context)) { + greetingAndAcquaintanceTrigger.action(context); + } + expect(enqueueMessage).toHaveBeenCalled(); + const callArg = enqueueMessage.mock.calls[0][0]; + expect(callArg).toEqual(expect.objectContaining(context)); + expect(combinedResponses).toContain(callArg.response.message); + }); + + test.each([ + ['Привет'], + ['Мы знакомы?'], + ['Как дела?'], + ['Здравствуйте, как у вас дела?'], + ])(`"%s" message does not match ${triggerDescription} (missing greeting or acquaintance)`, (incomingMessage) => { + const context = { request: { isFromUser: true, isOutbox: false, text: incomingMessage, attachments: [] } }; + expect(greetingAndAcquaintanceTrigger.condition(context)).toBe(false); + }); + + test('greeting sticker + acquaintance text matches trigger', () => { + const context = { + request: { + isFromUser: true, + isOutbox: false, + text: 'Мы знакомы?', + attachments: [{ id: 72789 }] // greeting sticker + } + }; + expect(greetingAndAcquaintanceTrigger.condition(context)).toBe(true); + }); + + test('containsGreetingAndAcquaintance function works correctly', () => { + expect(containsGreetingAndAcquaintance('Привет! Мы знакомы?', [])).toBe(true); + expect(containsGreetingAndAcquaintance('Привет', [])).toBe(false); + expect(containsGreetingAndAcquaintance('Мы знакомы?', [])).toBe(false); + expect(containsGreetingAndAcquaintance('Мы знакомы?', [{ id: 72789 }])).toBe(true); + }); +}); diff --git a/triggers/acquaintance.js b/triggers/acquaintance.js index e72483e..ca2bd82 100644 --- a/triggers/acquaintance.js +++ b/triggers/acquaintance.js @@ -50,5 +50,6 @@ const trigger = { module.exports = { trigger, - acquaintanceSuggestions + acquaintanceSuggestions, + acquaintedRegex }; \ No newline at end of file diff --git a/triggers/greeting-and-acquaintance.js b/triggers/greeting-and-acquaintance.js new file mode 100644 index 0000000..1d34f9a --- /dev/null +++ b/triggers/greeting-and-acquaintance.js @@ -0,0 +1,63 @@ +const { getRandomElement, hasSticker } = require('../utils'); +const { enqueueMessage } = require('../outgoing-messages'); +const { DateTime } = require('luxon'); +const { incomingGreetingStickersIds } = require('./greeting'); + +// Combined responses for greeting + acquaintance question +const combinedResponses = [ + "Привет! Ещё нет, но давай исправим. Я программист. А ты? (можно на ты?)", + "Привет! Мы не знакомы, но можем познакомиться. Я программист, а ты? (можем на ты?)", + "Привет! Нет, ещё не знакомы. Я программист :)", + "Привет! Нет, мы не знакомы. Я программист, а ты? (не против, что на ты?)", + "Привет! Ещё нет, я программист, предлагаю дружбу :)", + "Привет! Ещё нет, я программист, а ты? (можем перейти на ты?)", + "Привет! Не встречались ранее. Давай познакомимся. Я программист, а ты? (переходим на ты?)", + "Привет! Пока не знакомы, но можно это исправить. Я программист. А ты? (можно на ты?)", + "Привет! Ещё нет, но я всегда рад новым знакомствам. Я программист, а ты? (продолжим на ты?)", + "Привет! Пока что нет. Давай познакомимся? Я программист, а ты чем занимаешься? (мы на ты?)", + "Привет! Пока еще не знакомы. Исправим это? Я программист. А ты? (можно на ты?)", + "Привет! Мы еще не знакомы. Давай это исправим? Я программист. А ты? (перейдем на ты?)", +]; + +// Partial regex patterns to match within a message (not requiring full message match) +const greetingPartialRegex = /(трям|🖖|👋|🖐|мо[иё] приветстви[ея]|салам|салют|з?д[ао]ров[ао]?|ку|q+|шалом|хай|хэллоу|йоу?|привет(ствую|ики?)?|здрав?с(твуй|ь)?(те)?|дд|((день|вечер)[^\p{L}]+)?добр(ый([^\p{L}]*(день|вечер))?|ое[^\p{L}]*утро|ой[^\p{L}]*ночи|ого[^\p{L}]*времени[^\p{L}]*суток))/ui; +// Match acquaintance question - look for "знакомы" followed by "?" anywhere in the text +const acquaintancePartialRegex = /знакомы[^\?]*\?/ui; + +// Check if message contains both greeting and acquaintance question +function containsGreetingAndAcquaintance(text, attachments) { + const hasGreeting = greetingPartialRegex.test(text) || hasSticker({ attachments }, incomingGreetingStickersIds); + const hasAcquaintance = acquaintancePartialRegex.test(text); + return hasGreeting && hasAcquaintance; +} + +const trigger = { + name: "GreetingAndAcquaintanceTrigger", + condition: (context) => { + if (!context?.request?.isFromUser) { + return false; + } + + const now = DateTime.now(); + const lastTriggered = context?.state?.triggers?.[trigger.name]?.lastTriggered; + const lastTriggeredDiff = lastTriggered ? now.diff(lastTriggered, 'days').days : Number.MAX_SAFE_INTEGER; + + return lastTriggeredDiff >= 1 + && !context?.request?.isOutbox + && containsGreetingAndAcquaintance(context.request.text || '', context.request.attachments); + }, + action: (context) => { + enqueueMessage({ + ...context, + response: { + message: getRandomElement(combinedResponses) + } + }); + } +}; + +module.exports = { + trigger, + combinedResponses, + containsGreetingAndAcquaintance +}; From 8b6a5d5d07ce665c42dafcebd4ae99776e71e480 Mon Sep 17 00:00:00 2001 From: konard Date: Fri, 17 Oct 2025 19:55:23 +0300 Subject: [PATCH 3/3] Revert "Initial commit with task details for issue #15" This reverts commit 59779727debe6c819c66dc3810c3712532d78b02. --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index e42fbaa..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: undefined -Your prepared branch: issue-15-0debf3e4 -Your prepared working directory: /tmp/gh-issue-solver-1760719614707 - -Proceed. \ No newline at end of file