diff --git a/cmd/memory/recall.go b/cmd/memory/recall.go index e37344f0..a003c851 100644 --- a/cmd/memory/recall.go +++ b/cmd/memory/recall.go @@ -101,8 +101,19 @@ func toCompact(resp search.RecallResponse) compactResponse { var recallCmd = &cobra.Command{ Use: "recall [keyword]", Short: "Retrieve insights by keyword", - Long: "Search for insights using intent-aware graph-enhanced retrieval. Use --basic for simple SQL LIKE matching.", - Args: cobra.MinimumNArgs(1), + Long: `Search for insights using intent-aware graph-enhanced retrieval. Use --basic for simple SQL LIKE matching. + +Automatic intent uses a limited set of question cues in English, Mandarin Chinese +(simplified/traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, +French, Bengali (Bengali script), Portuguese, Indonesian, Russian (Cyrillic), and +German. It does not infer meaning or recognize every phrasing or transliteration. +Unrecognized cues fall back to GENERAL. Conflicting cues involving the additional +languages also use GENERAL; English/Chinese-only queries retain legacy scoring. + +Use --intent WHY (reasons), WHEN (timing), ENTITY (what/who), or GENERAL to select +the strategy in any language while keeping the original query. --verbose reports +meta.intent and meta.intent_source (auto or override). --basic bypasses intent.`, + Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { keyword := strings.Join(args, " ") if err := requirePositiveLimit("--limit", recLimit); err != nil { diff --git a/docs/USAGE.md b/docs/USAGE.md index f7e7040d..d189a230 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -174,6 +174,65 @@ whitespace, caps each excerpt, emits unindented JSON, and includes one machine-readable interchange format; the opt-in projection avoids changing existing parsers or adopting a draft serialization format. +#### Recall intent detection + +Automatic intent selection uses a fixed set of lexical cues. It runs locally, +without an LLM or provider. Intent changes graph traversal and ranking; it does +not translate the query or the stored memories. The recognized question forms +include the following (examples use `PostgreSQL` as the subject): + +| Language / script | WHY | WHEN | ENTITY | +|---|---|---|---| +| English | Why PostgreSQL? | When did we choose PostgreSQL? | What is PostgreSQL? | +| Mandarin Chinese, simplified | 为什么选择 PostgreSQL? | 什么时候选择 PostgreSQL? | PostgreSQL 是什么? | +| Mandarin Chinese, traditional | 為什麼選擇 PostgreSQL? | 什麼時候選擇 PostgreSQL? | PostgreSQL 是什麼? | +| Hindi, Devanagari | PostgreSQL क्यों? | PostgreSQL कब? | PostgreSQL क्या है? | +| Spanish | ¿Por qué PostgreSQL? | ¿Cuándo elegimos PostgreSQL? | ¿Qué es PostgreSQL? | +| Modern Standard Arabic | لماذا PostgreSQL؟ | متى اخترنا PostgreSQL؟ | ما هو PostgreSQL؟ | +| French | Pourquoi PostgreSQL ? | Quand avons-nous choisi PostgreSQL ? | Qu'est-ce que PostgreSQL ? | +| Bengali, Bengali script | PostgreSQL কেন? | PostgreSQL কখন? | PostgreSQL কী? | +| Portuguese | Por que PostgreSQL? | Quando escolhemos PostgreSQL? | O que é PostgreSQL? | +| Indonesian, Latin script | Mengapa PostgreSQL? | Kapan memilih PostgreSQL? | Apa itu PostgreSQL? | +| Russian, Cyrillic | Почему PostgreSQL? | Когда выбрали PostgreSQL? | Что такое PostgreSQL? | +| German | Warum PostgreSQL? | Wann wurde PostgreSQL gewählt? | Was ist PostgreSQL? | + +Matching is case-insensitive and uses Unicode word boundaries for spaced scripts; +Chinese cues also match without spaces. The additional-language forms accept +Unicode whitespace, straight/curly French apostrophes, and composed/decomposed +accents in the listed Spanish/Portuguese cues. Accents are not generally removed. +Arabic accepts ordinary Arabic letters with or without common vowel marks +(harakat and superscript alif) and tatweel. A few explicit variants are included, +such as `為甚麼`, `क्यूँ`, `por quê`, `kenapa`, `зачем`, and `wieso`. Bengali +`কী`/`কি`/`কে` must end the question for ENTITY; bare Hindi `क्या` does not imply +ENTITY. Other dialects, spellings, Arabic presentation forms, and Latin +transliterations of non-Latin scripts are not covered systematically. + +Unrecognized queries use `GENERAL`. Additional-language cues that disagree with +one another or with an English/Chinese cue also use `GENERAL`, regardless of +keyword counts. Same-intent mixed-language cues can agree. For compatibility, +English/Chinese-only queries retain their keyword scoring and ENTITY tie-break; +for example, `what is the reason` selects ENTITY. Paired quoted/code spans are +ignored for additional-language cues, while legacy quoted keywords retain their +old behavior. This is a lexical heuristic: it does not resolve negation, +incidental word mentions, nested quotations, or the meaning of mixed questions. +These examples test intent selection, not retrieval accuracy across languages. + +The supervising agent can choose an intent from the user's meaning and retain +the original-language query and memories: + +```bash +mnemon recall '¿Por qué elegimos PostgreSQL?' --intent WHY --verbose +mnemon recall 'हमने PostgreSQL कब चुना?' --intent WHEN --verbose +mnemon recall 'Was ist PostgreSQL?' --intent ENTITY --verbose +mnemon recall 'PostgreSQL index tuning' --intent GENERAL --verbose +``` + +The override is language-independent: WHY selects reasons, WHEN timing, ENTITY +what/who, and GENERAL neutral traversal. It takes precedence over detection. +Verbose output reports `meta.intent` and `meta.intent_source` (`auto` or +`override`), including when there are no results. `--basic` bypasses intent +selection entirely. + ### Graph Operations ```bash diff --git a/docs/design/05-pipelines.md b/docs/design/05-pipelines.md index 996dec9f..96e71649 100644 --- a/docs/design/05-pipelines.md +++ b/docs/design/05-pipelines.md @@ -94,7 +94,8 @@ After receiving this output, the LLM can evaluate candidates and establish edges ### Step 1: Intent Detection -Query intent is automatically identified via regex matching: +Query intent is selected with a fixed set of local lexical patterns. The original +English/Chinese cues include: | Intent | Trigger Patterns | |--------|-----------------| @@ -103,7 +104,18 @@ Query intent is automatically identified via regex matching: | ENTITY | `what is`, `who is`, `tell me about`, `是什么`, `谁是`, `关于` | | GENERAL | None of the above match | -Supports the `--intent` flag to manually override automatic detection. +Question forms also cover Hindi, Spanish, Modern Standard Arabic, French, +Bengali, Portuguese, Indonesian, Russian, and German. See +[recall intent detection](../USAGE.md#recall-intent-detection) for supported +scripts, examples, and limits. Matching uses Unicode word boundaries for spaced +scripts. Conflicting cues involving an additional language fall back to GENERAL; +legacy English/Chinese-only queries retain keyword scoring and the ENTITY +tie-break. This is a bounded heuristic, not semantic language understanding. + +`--intent WHY|WHEN|ENTITY|GENERAL` overrides detection in any query language. +The host can supply intent from the user's meaning without translating the query +or invoking another provider. `--verbose` exposes `meta.intent` and +`meta.intent_source` (`auto` or `override`). ### Step 2: Multi-Signal Anchor Selection (RRF Fusion) diff --git a/docs/zh/USAGE.md b/docs/zh/USAGE.md index 83bd5f9d..3941f4ec 100644 --- a/docs/zh/USAGE.md +++ b/docs/zh/USAGE.md @@ -167,6 +167,38 @@ mnemon forget JSON 继续作为机器可读交换格式,因此既不破坏现有解析器,也无需绑定尚在演进的 序列化草案。 +#### Recall 意图检测 + +自动检测使用本地固定词语模式,无需 LLM 或服务提供商。覆盖英语、普通话 +(简体/繁体)、印地语(天城文)、西班牙语、现代标准阿拉伯语、法语、孟加拉语 +(孟加拉文)、葡萄牙语、印度尼西亚语(拉丁字母)、俄语(西里尔字母)和德语 +的部分疑问句形式;这不代表能理解这些语言的所有表达,也不是跨语言检索准确率承诺。 +完整例句及书写变体见[英文说明](../USAGE.md#recall-intent-detection)。 + +词边界识别 Unicode 字母、组合标记和数字;中文不要求空格。新增语言的模式兼容 +Unicode 空白、法语直/弯撇号、西班牙语和葡萄牙语已列词语的组合/分解重音, +以及阿拉伯语常用元音标记和 tatweel。其他方言、阿拉伯字母表现形式和非拉丁 +文字的拉丁转写不作系统支持。重音不会被普遍删除。 + +没有命中时返回 `GENERAL`。新增语言的意图线索互相冲突,或与英/中文线索冲突, +也返回 `GENERAL`;混合语言中一致的线索可正常识别。为保持兼容,仅含英/中文 +线索的查询沿用原有计数及 ENTITY 平分规则,例如 `what is the reason` 选择 +ENTITY。新增语言忽略成对引号/代码引用中的词语;英/中文引用词沿用原行为。 +该规则不理解否定、偶然提及、嵌套引号或复合问题的含义。 + +宿主 agent 可根据用户含义显式选择意图,同时保留查询和记忆的原语言: + +```bash +mnemon recall '¿Por qué elegimos PostgreSQL?' --intent WHY --verbose +mnemon recall 'हमने PostgreSQL कब चुना?' --intent WHEN --verbose +mnemon recall 'Was ist PostgreSQL?' --intent ENTITY --verbose +``` + +`--intent WHY|WHEN|ENTITY|GENERAL` 与语言无关,优先于自动检测:WHY 为原因、 +WHEN 为时间、ENTITY 为是什么/是谁、GENERAL 为中性遍历。意图会影响图遍历 +和排序。`--verbose` 输出 `meta.intent` 及 `meta.intent_source` +(`auto` 或 `override`),即使无结果也可查看;`--basic` 完全跳过意图检测。 + **Import 标志:** | 标志 | 默认值 | 说明 | diff --git a/docs/zh/design/05-pipelines.md b/docs/zh/design/05-pipelines.md index 06d591f1..9a26e92a 100644 --- a/docs/zh/design/05-pipelines.md +++ b/docs/zh/design/05-pipelines.md @@ -101,7 +101,15 @@ LLM 收到这个输出后,可以评估候选并通过 `mnemon link` 命令建 | ENTITY | `what is`, `who is`, `tell me about`, `是什么`, `谁是`, `关于` | | GENERAL | 以上都不匹配 | -支持 `--intent` 标志手动覆盖自动检测。 +另有印地语、西班牙语、现代标准阿拉伯语、法语、孟加拉语、葡萄牙语、 +印度尼西亚语、俄语和德语的部分疑问句模式,详见 +[Recall 意图检测](../USAGE.md#recall-意图检测)。词边界使用 Unicode 规则; +新增语言的线索互相冲突或与英/中文冲突时回退到 GENERAL。仅含英/中文线索 +时保留原有计数及 ENTITY 平分规则。这是有限的词语启发式,不是语义理解。 + +`--intent WHY|WHEN|ENTITY|GENERAL` 可对任意语言查询覆盖自动检测。宿主可从 +用户含义选择意图,无需翻译查询或调用另一个服务。`--verbose` 显示 +`meta.intent` 和 `meta.intent_source`(`auto` 或 `override`)。 ### Step 2:多信号锚点选择(RRF 融合) diff --git a/internal/memory/search/intent.go b/internal/memory/search/intent.go index 2ba56e21..5768d0f1 100644 --- a/internal/memory/search/intent.go +++ b/internal/memory/search/intent.go @@ -49,16 +49,16 @@ var intentWeightsMap = map[Intent]IntentWeights{ } var whyPatterns = regexp.MustCompile( - `(?i)\b(why|reason|because|cause|motivation|rationale)\b|` + - `(为什么|原因|理由)`) + `(?i)(why|reason|because|cause|motivation|rationale)|` + + `(为什么|為什麼|為甚麼|原因|理由)`) var whenPatterns = regexp.MustCompile( - `(?i)\b(when|time|date|before|after|during|timeline|history|sequence)\b|` + - `(什么时候|何时|时间|之前|之后)`) + `(?i)(when|timeline|time|date|before|after|during|history|sequence)|` + + `(什么时候|什麼時候|甚麼時候|何时|何時|时间|時間|之前|之后|之後)`) var entityPatterns = regexp.MustCompile( - `(?i)\b(what is|who is|tell me about|describe|about)\b|` + - `(是什么|谁是|关于|介绍)`) + `(?i)(what is|who is|tell me about|describe|about)|` + + `(是什么|是什麼|是甚麼|谁是|誰是|关于|關於|介绍|介紹)`) // IntentFromString parses a user-provided intent string into an Intent value. func IntentFromString(s string) (Intent, error) { @@ -76,12 +76,28 @@ func IntentFromString(s string) (Intent, error) { } } -// DetectIntent analyzes a query string and returns the detected intent. +// DetectIntent selects an intent using bounded, language-specific lexical cues. +// It preserves English/Chinese scoring; conflicting cues involving the additional +// languages fall back to GENERAL. This is not semantic language understanding. func DetectIntent(query string) Intent { - q := strings.ToLower(query) - whyScore := len(whyPatterns.FindAllString(q, -1)) - whenScore := len(whenPatterns.FindAllString(q, -1)) - entityScore := len(entityPatterns.FindAllString(q, -1)) + whyScore := legacyIntentScore(whyPatterns, query) + whenScore := legacyIntentScore(whenPatterns, query) + entityScore := legacyIntentScore(entityPatterns, query) + + questionIntent, conflict := multilingualQuestionIntent(query) + if conflict { + return IntentGeneral + } + if questionIntent != IntentGeneral { + // A strong cue in another language must not override conflicting legacy + // cues, even when one legacy intent has a higher keyword count. + if (whyScore > 0 && questionIntent != IntentWhy) || + (whenScore > 0 && questionIntent != IntentWhen) || + (entityScore > 0 && questionIntent != IntentEntity) { + return IntentGeneral + } + return questionIntent + } if whyScore > whenScore && whyScore > entityScore && whyScore > 0 { return IntentWhy diff --git a/internal/memory/search/intent_languages.go b/internal/memory/search/intent_languages.go new file mode 100644 index 00000000..d5b0709f --- /dev/null +++ b/internal/memory/search/intent_languages.go @@ -0,0 +1,124 @@ +package search + +import ( + "regexp" + "strings" + "unicode" + "unicode/utf8" +) + +// Keep this list small and explicit: question forms, not translated bags of +// generic words such as "time" or "about". No language identification is needed; +// all matching forms contribute, and contradictory intents fail to GENERAL. +var multilingualQuestionPatterns = []struct { + intent Intent + pattern *regexp.Regexp +}{ + // Hindi (Devanagari). Bare क्या also starts yes/no questions, so require a copula. + {IntentWhy, intentWords(`क्यों|क्यूँ|किसलिए`)}, + {IntentWhen, intentWords(`कब`)}, + {IntentEntity, intentWords(`(?:क्या|कौन) (?:है|हैं)`)}, + // Spanish. Accept both precomposed and decomposed accents, without removing them. + {IntentWhy, intentWords(`por qu(?:é|e\x{0301})`)}, + {IntentWhen, intentWords(`cu(?:á|a\x{0301})ndo`)}, + {IntentEntity, intentWords(`qu(?:é|e\x{0301}) es|qui(?:é|e\x{0301})n es`)}, + // Modern Standard Arabic. Common vowel marks and tatweel are removed below. + {IntentWhy, intentWords(`لماذا`)}, + {IntentWhen, intentWords(`متى`)}, + {IntentEntity, intentWords(`(?:ما|من) (?:هو|هي)`)}, + // French. Apostrophes within words are not quotation delimiters. + {IntentWhy, intentWords(`pourquoi`)}, + {IntentWhen, intentWords(`quand`)}, + {IntentEntity, intentWords(`qu['’]est(?:-| )ce que|qui est|c['’]est quoi`)}, + // Bengali. A final কী/কি/কে asks for an entity; mid-sentence কি can be yes/no. + {IntentWhy, intentWords(`কেন`)}, + {IntentWhen, intentWords(`কখন|কবে`)}, + {IntentEntity, intentWords(`(?:কী|কি|কে)[\s\p{Z}]*[??]?$`)}, + // Portuguese (European and Brazilian shared forms). + {IntentWhy, intentWords(`por qu(?:e|ê|e\x{0302})`)}, + {IntentWhen, intentWords(`quando`)}, + {IntentEntity, intentWords(`(?:o que|quem) (?:é|e\x{0301})`)}, + // Indonesian (Latin script). + {IntentWhy, intentWords(`mengapa|kenapa`)}, + {IntentWhen, intentWords(`kapan`)}, + {IntentEntity, intentWords(`(?:apa|siapa) itu`)}, + // Russian (Cyrillic). + {IntentWhy, intentWords(`почему|зачем`)}, + {IntentWhen, intentWords(`когда`)}, + {IntentEntity, intentWords(`что такое|кто (?:такой|такая|такие)`)}, + // German (Latin script). + {IntentWhy, intentWords(`warum|wieso|weshalb`)}, + {IntentWhen, intentWords(`wann`)}, + {IntentEntity, intentWords(`(?:was|wer) (?:ist|sind)`)}, +} + +// Go's \b only understands ASCII. Marks and joiners must stay attached to words +// in Indic/Arabic text; Unicode letters and numbers also prevent cross-script +// substring matches such as "почемуx", "ékapan", or "why中文". +const intentWordChars = `\p{L}\p{M}\p{N}_\x{200c}\x{200d}` + +func intentWords(pattern string) *regexp.Regexp { + pattern = strings.ReplaceAll(pattern, " ", `[\s\p{Z}]+`) + return regexp.MustCompile(`(?i)(^|[^` + intentWordChars + `])(?:` + pattern + `)($|[^` + intentWordChars + `])`) +} + +// Ignore paired quoted/code spans in the new cues. A single quote preceded by a +// letter is an apostrophe (qu'est-ce), not an opening quote. Legacy-only queries +// retain their historical handling of quotes and keyword counts. +var quotedIntentText = regexp.MustCompile(`(?s)"[^"]*"|“[^”]*”|«[^»]*»|` + "`[^`]*`" + `|(^|[^` + intentWordChars + `])'[^']*'`) + +func multilingualQuestionIntent(query string) (Intent, bool) { + query = strings.TrimSpace(quotedIntentText.ReplaceAllString(query, " ")) + query = strings.Map(func(r rune) rune { + if r == '\u0640' || (r >= '\u064b' && r <= '\u0652') || r == '\u0670' { + return -1 // Arabic tatweel, harakat, and superscript alif. + } + return r + }, query) + intent := IntentGeneral + for _, cue := range multilingualQuestionPatterns { + if !cue.pattern.MatchString(query) { + continue + } + if intent != IntentGeneral && intent != cue.intent { + return IntentGeneral, true + } + intent = cue.intent + } + return intent, false +} + +// Preserve legacy scoring, while checking Unicode boundaries for the English +// alternatives. Chinese cues intentionally match without spaces. Checking the +// surrounding runes does not consume separators between repeated keywords. +func legacyIntentScore(pattern *regexp.Regexp, query string) int { + score := 0 + for offset := 0; offset < len(query); { + span := pattern.FindStringIndex(query[offset:]) + if span == nil { + break + } + start, end := offset+span[0], offset+span[1] + first, size := utf8.DecodeRuneInString(query[start:end]) + offset = end + if unicode.Is(unicode.Han, first) { + score++ + continue + } + before, _ := utf8.DecodeLastRuneInString(query[:start]) + after, _ := utf8.DecodeRuneInString(query[end:]) + if !intentWordRune(before) && !intentWordRune(after) { + score++ + continue + } + // An invalid compound can contain a later valid cue: in "retell me + // about", rejecting "tell me about" must not consume the word "about". + offset = start + size + } + return score +} + +func intentWordRune(r rune) bool { + return unicode.IsLetter(r) || unicode.IsMark(r) || unicode.IsNumber(r) || + r == '_' || r == '\u200c' || r == '\u200d' +} diff --git a/internal/memory/search/intent_test.go b/internal/memory/search/intent_test.go index 0c416c1e..98b517cf 100644 --- a/internal/memory/search/intent_test.go +++ b/internal/memory/search/intent_test.go @@ -62,6 +62,147 @@ func TestDetectIntent_General(t *testing.T) { } } +// These are the 33 native-language queries from issue #132. They measure intent +// selection, not translation quality or end-to-end retrieval accuracy. +func TestDetectIntent_MultilingualQuestions(t *testing.T) { + tests := []struct { + language string + why, when, entity string + }{ + {"English", "Why did we choose PostgreSQL?", "When did we choose PostgreSQL?", "What is PostgreSQL?"}, + {"Mandarin Chinese", "我们为什么选择 PostgreSQL?", "我们什么时候选择了 PostgreSQL?", "PostgreSQL 是什么?"}, + {"Hindi", "हमने PostgreSQL क्यों चुना?", "हमने PostgreSQL कब चुना?", "PostgreSQL क्या है?"}, + {"Spanish", "¿Por qué elegimos PostgreSQL?", "¿Cuándo elegimos PostgreSQL?", "¿Qué es PostgreSQL?"}, + {"Modern Standard Arabic", "لماذا اخترنا PostgreSQL؟", "متى اخترنا PostgreSQL؟", "ما هو PostgreSQL؟"}, + {"French", "Pourquoi avons-nous choisi PostgreSQL ?", "Quand avons-nous choisi PostgreSQL ?", "Qu'est-ce que PostgreSQL ?"}, + {"Bengali", "আমরা PostgreSQL কেন বেছে নিয়েছি?", "আমরা কখন PostgreSQL বেছে নিয়েছি?", "PostgreSQL কী?"}, + {"Portuguese", "Por que escolhemos PostgreSQL?", "Quando escolhemos PostgreSQL?", "O que é PostgreSQL?"}, + {"Indonesian", "Mengapa kita memilih PostgreSQL?", "Kapan kita memilih PostgreSQL?", "Apa itu PostgreSQL?"}, + {"Russian", "Почему выбрали PostgreSQL?", "Когда выбрали PostgreSQL?", "Что такое PostgreSQL?"}, + {"German", "Warum haben wir PostgreSQL gewählt?", "Wann haben wir PostgreSQL gewählt?", "Was ist PostgreSQL?"}, + } + for _, tt := range tests { + t.Run(tt.language, func(t *testing.T) { + for _, question := range []struct { + query string + want Intent + }{{tt.why, IntentWhy}, {tt.when, IntentWhen}, {tt.entity, IntentEntity}} { + if got := DetectIntent(question.query); got != question.want { + t.Errorf("DetectIntent(%q) = %q, want %q", question.query, got, question.want) + } + } + }) + } +} + +func TestDetectIntent_ScriptVariants(t *testing.T) { + tests := []struct { + query string + want Intent + }{ + {"我們為什麼選擇 PostgreSQL?", IntentWhy}, + {"我們為甚麼選擇 PostgreSQL?", IntentWhy}, + {"我們什麼時候選擇 PostgreSQL?", IntentWhen}, + {"何時修改 PostgreSQL?", IntentWhen}, + {"PostgreSQL 是什麼?", IntentEntity}, + {"介紹 PostgreSQL", IntentEntity}, + {"हमने PostgreSQL क्यूँ चुना?", IntentWhy}, + {"PostgreSQL किसलिए?", IntentWhy}, + {"वह कौन हैं?", IntentEntity}, + {"¿POR QUÉ PostgreSQL?", IntentWhy}, + {"¿Por que\u0301 PostgreSQL?", IntentWhy}, + {"¿Cua\u0301ndo PostgreSQL?", IntentWhen}, + {"¿Quién es Ana?", IntentEntity}, + {"¿Que\u0301\u00a0es\tPostgreSQL?", IntentEntity}, + {"لِمَاذَا اخترنا PostgreSQL؟", IntentWhy}, + {"مَتَى اخترنا PostgreSQL؟", IntentWhen}, + {"ما هِيَ PostgreSQL؟", IntentEntity}, + {"لـماذا PostgreSQL؟", IntentWhy}, + {"Qu’est-ce que PostgreSQL ?", IntentEntity}, + {"Qu'est ce que PostgreSQL ?", IntentEntity}, + {"C’est quoi PostgreSQL ?", IntentEntity}, + {"Qui est Alice ?", IntentEntity}, + {"Qu'est-ce que 'quand' dans PostgreSQL ?", IntentEntity}, + {"PostgreSQL কবে?", IntentWhen}, + {"PostgreSQL কি? ", IntentEntity}, + {"রহিম কে?", IntentEntity}, + {"PostgreSQL por quê?", IntentWhy}, + {"PostgreSQL por que\u0302?", IntentWhy}, + {"O que e\u0301 PostgreSQL?", IntentEntity}, + {"Quem é Maria?", IntentEntity}, + {"Kenapa PostgreSQL?", IntentWhy}, + {"Siapa itu Alice?", IntentEntity}, + {"ПОЧЕМУ PostgreSQL?", IntentWhy}, + {"Зачем PostgreSQL?", IntentWhy}, + {"Кто такая Алиса?", IntentEntity}, + {"Wieso PostgreSQL?", IntentWhy}, + {"Weshalb PostgreSQL?", IntentWhy}, + {"Wer ist Alice?", IntentEntity}, + } + for _, tt := range tests { + if got := DetectIntent(tt.query); got != tt.want { + t.Errorf("DetectIntent(%q) = %q, want %q", tt.query, got, tt.want) + } + } +} + +func TestDetectIntent_MultilingualGeneralAndBoundaries(t *testing.T) { + for _, query := range []string{ + "", "PostgreSQL index tuning", "PostgreSQL 索引调优", "PostgreSQL इंडेक्स सुधार", + "Índices de PostgreSQL", "فهارس PostgreSQL", "Index PostgreSQL", "PostgreSQL সূচক", + "Índices do PostgreSQL", "Indeks PostgreSQL", "Индексы PostgreSQL", "PostgreSQL Indizes", + "क्या PostgreSQL तेज़ है?", "PostgreSQL কি ভালো?", // yes/no, not ENTITY + "PostgreSQL কীভাবে কাজ করে?", "PostgreSQL কেমন?", // how, outside the supported forms + "PostgreSQL いつ?", "PostgreSQL kyun?", "لم PostgreSQL", // unsupported forms/scripts + "екогда", "когдаx", "xकब", "कब्ज", "क्योंकि", "কেননা", "xকেন", "لماذات", "متىx", + "kapanpun", "bagaimana", "was istanbul", "ékapan", "pourquoix", "когдаé", + "_kapan", "kapan_", "kapan2", "2kapan", "kapan\u0301", "\u0301kapan", + "कब\u200d", "\u200cকেন", "why中文", "éwhy", "whyé", "timeé", "describé", + `The "pourquoi" option`, "The `wann` flag", "The “когда” command", "The «क्यों» token", + "The 'kapan' flag", + } { + if got := DetectIntent(query); got != IntentGeneral { + t.Errorf("DetectIntent(%q) = %q, want GENERAL", query, got) + } + } +} + +func TestDetectIntent_MixedAndAmbiguous(t *testing.T) { + tests := []struct { + query string + want Intent + }{ + {"Why PostgreSQL, pourquoi ce choix?", IntentWhy}, + {"PostgreSQL कब चुना, when?", IntentWhen}, + {"Was ist PostgreSQL, 是什么?", IntentEntity}, + {"Pourquoi PostgreSQL — why, 为什么?", IntentWhy}, + {"¿Por qué no elegimos PostgreSQL?", IntentWhy}, + {"Why PostgreSQL, cuándo migramos?", IntentGeneral}, + {"Pourquoi PostgreSQL, WHEN migrated?", IntentGeneral}, + {"¿Por qué y cuándo elegimos PostgreSQL?", IntentGeneral}, + {"No por qué, sino cuándo elegimos PostgreSQL", IntentGeneral}, + {"क्यों और कब PostgreSQL?", IntentGeneral}, + {"Почему PostgreSQL, was ist PostgreSQL?", IntentGeneral}, + {"Pourquoi PostgreSQL, what is its purpose?", IntentGeneral}, + {"when when when pourquoi PostgreSQL?", IntentGeneral}, + {"Was ist the history of PostgreSQL?", IntentGeneral}, + {"What is the reason for PostgreSQL?", IntentEntity}, // legacy ENTITY tie-break + {"why why when PostgreSQL", IntentWhy}, // legacy keyword counts + {"为什么为什么什么时候 PostgreSQL", IntentWhy}, + {"why when PostgreSQL", IntentGeneral}, + {"timeline of PostgreSQL", IntentWhen}, + {"Please retell me about PostgreSQL", IntentEntity}, + {"Retell me about why we chose PostgreSQL", IntentEntity}, + {"étell me about PostgreSQL", IntentEntity}, + {"why why tell me about PostgreSQL", IntentWhy}, // valid compound counts once + } + for _, tt := range tests { + if got := DetectIntent(tt.query); got != tt.want { + t.Errorf("DetectIntent(%q) = %q, want %q", tt.query, got, tt.want) + } + } +} + func TestIntentFromString_Valid(t *testing.T) { tests := []struct { input string diff --git a/internal/memory/setup/assets/claude/SKILL.md b/internal/memory/setup/assets/claude/SKILL.md index 7395758e..09303484 100644 --- a/internal/memory/setup/assets/claude/SKILL.md +++ b/internal/memory/setup/assets/claude/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for LLM agents. Store facts, recall past know - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/claude/guide.md b/internal/memory/setup/assets/claude/guide.md index 841f8d2e..073ee0a1 100644 --- a/internal/memory/setup/assets/claude/guide.md +++ b/internal/memory/setup/assets/claude/guide.md @@ -10,6 +10,13 @@ To recall: `mnemon recall "" --limit 5`. Craft a focused, keyword-rich query — do not pass the raw user prompt. +Keep the query and memories in their original language. If intent is clear from +meaning, pass `--intent WHY` (reasons), `WHEN` (timing), `ENTITY` (what/who), or +`GENERAL` (neutral). Automatic detection recognizes only bounded question forms; +unrecognized forms and conflicting additional-language cues use GENERAL. +English/Chinese-only scoring is preserved. `--verbose` reports the selected intent +and its source. See [supported languages, scripts, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ### Remember — after responding Run this decision tree after every substantive response. diff --git a/internal/memory/setup/assets/codebuddy/SKILL.md b/internal/memory/setup/assets/codebuddy/SKILL.md index def7eb51..4b1e15c8 100644 --- a/internal/memory/setup/assets/codebuddy/SKILL.md +++ b/internal/memory/setup/assets/codebuddy/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for CodeBuddy. Store facts, recall past knowl - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/codex/SKILL.md b/internal/memory/setup/assets/codex/SKILL.md index c6a0d03c..996d5c0e 100644 --- a/internal/memory/setup/assets/codex/SKILL.md +++ b/internal/memory/setup/assets/codex/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for LLM agents. Store facts, recall past know - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/cursor/SKILL.md b/internal/memory/setup/assets/cursor/SKILL.md index 6080caa4..57573cd6 100644 --- a/internal/memory/setup/assets/cursor/SKILL.md +++ b/internal/memory/setup/assets/cursor/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for LLM agents. Store facts, recall past know - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/hermes/SKILL.md b/internal/memory/setup/assets/hermes/SKILL.md index 5e1a48c7..0ca66940 100644 --- a/internal/memory/setup/assets/hermes/SKILL.md +++ b/internal/memory/setup/assets/hermes/SKILL.md @@ -18,6 +18,23 @@ agent decides what is worth storing. 3. Link related memories after reviewing candidates from `remember`: `mnemon link --type --weight <0-1>` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/kimi/SKILL.md b/internal/memory/setup/assets/kimi/SKILL.md index 00f756cb..ca37a1af 100644 --- a/internal/memory/setup/assets/kimi/SKILL.md +++ b/internal/memory/setup/assets/kimi/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for Kimi Code. Store facts, recall past knowl - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/minimax/SKILL.md b/internal/memory/setup/assets/minimax/SKILL.md index c3cf0a32..1e204f38 100644 --- a/internal/memory/setup/assets/minimax/SKILL.md +++ b/internal/memory/setup/assets/minimax/SKILL.md @@ -29,6 +29,23 @@ Use `mnemon` through MiniMax Code's shell tools when durable context would impro The optional behavioral guide is stored at `${MNEMON_DATA_DIR:-$HOME/.mnemon}/prompt/guide.md`. Read it when memory judgment is relevant; do not inject it into unrelated work. +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Other commands ```bash diff --git a/internal/memory/setup/assets/nanobot/SKILL.md b/internal/memory/setup/assets/nanobot/SKILL.md index d23cd90c..b8a61d60 100644 --- a/internal/memory/setup/assets/nanobot/SKILL.md +++ b/internal/memory/setup/assets/nanobot/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for LLM agents. Store facts, recall past know - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/nanoclaw/SKILL.md b/internal/memory/setup/assets/nanoclaw/SKILL.md index 38394c77..78567ad1 100644 --- a/internal/memory/setup/assets/nanoclaw/SKILL.md +++ b/internal/memory/setup/assets/nanoclaw/SKILL.md @@ -254,3 +254,20 @@ To remove mnemon from your NanoClaw installation: 5. Remove hooks registration from `src/container-runner.ts`: delete the mnemon hooks merge in settings.json 6. Rebuild: `./container/build.sh` 7. (Optional) Remove data: `rm -rf ~/.mnemon/data/` + +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). diff --git a/internal/memory/setup/assets/nanoclaw/container-skill.md b/internal/memory/setup/assets/nanoclaw/container-skill.md index 2f6b17ed..152f4cb6 100644 --- a/internal/memory/setup/assets/nanoclaw/container-skill.md +++ b/internal/memory/setup/assets/nanoclaw/container-skill.md @@ -61,6 +61,23 @@ Run this decision tree after every substantive response: - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/openclaw/SKILL.md b/internal/memory/setup/assets/openclaw/SKILL.md index 2913ba97..f8ad2ee4 100644 --- a/internal/memory/setup/assets/openclaw/SKILL.md +++ b/internal/memory/setup/assets/openclaw/SKILL.md @@ -92,6 +92,23 @@ mnemon setup --eject --target openclaw --yes - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/opencode/SKILL.md b/internal/memory/setup/assets/opencode/SKILL.md index f32ac2a9..015d447a 100644 --- a/internal/memory/setup/assets/opencode/SKILL.md +++ b/internal/memory/setup/assets/opencode/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for OpenCode. Store facts, recall past knowle - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/pi/SKILL.md b/internal/memory/setup/assets/pi/SKILL.md index c6a0d03c..996d5c0e 100644 --- a/internal/memory/setup/assets/pi/SKILL.md +++ b/internal/memory/setup/assets/pi/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for LLM agents. Store facts, recall past know - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/qoder/SKILL.md b/internal/memory/setup/assets/qoder/SKILL.md index 2dba308d..78e9e9f4 100644 --- a/internal/memory/setup/assets/qoder/SKILL.md +++ b/internal/memory/setup/assets/qoder/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for LLM agents. Store facts, recall past know - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/qoderwork/SKILL.md b/internal/memory/setup/assets/qoderwork/SKILL.md index d283a4c8..de15b28a 100644 --- a/internal/memory/setup/assets/qoderwork/SKILL.md +++ b/internal/memory/setup/assets/qoderwork/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for QoderWork. Store facts, recall past knowl - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/trae/SKILL.md b/internal/memory/setup/assets/trae/SKILL.md index 2dba308d..78e9e9f4 100644 --- a/internal/memory/setup/assets/trae/SKILL.md +++ b/internal/memory/setup/assets/trae/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for LLM agents. Store facts, recall past know - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/workbuddy/SKILL.md b/internal/memory/setup/assets/workbuddy/SKILL.md index e0988b4d..96838cd6 100644 --- a/internal/memory/setup/assets/workbuddy/SKILL.md +++ b/internal/memory/setup/assets/workbuddy/SKILL.md @@ -16,6 +16,23 @@ description: Persistent memory CLI for WorkBuddy. Store facts, recall past knowl - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/internal/memory/setup/assets/zcode/SKILL.md b/internal/memory/setup/assets/zcode/SKILL.md index b290e9c4..bfa40a57 100644 --- a/internal/memory/setup/assets/zcode/SKILL.md +++ b/internal/memory/setup/assets/zcode/SKILL.md @@ -16,6 +16,23 @@ description: Use persistent memory when prior preferences, decisions, constraint - Syntax: `mnemon link --type --weight <0-1> [--meta '']` 3. **Recall**: `mnemon recall "" --limit 10` +## Recall Intent + +Keep focused queries and memories in their original language. When the user's +meaning is clear, choose `--intent WHY` (reasons), `--intent WHEN` (timing), +`--intent ENTITY` (what/who), or `--intent GENERAL` (neutral retrieval). +For example: `mnemon recall "" --intent WHY`. The override works in any +language; `--verbose` reports +`meta.intent` and `meta.intent_source` (`auto` or `override`). + +Automatic cues cover some forms in English, Mandarin Chinese (simplified and +traditional), Hindi (Devanagari), Spanish, Modern Standard Arabic, French, +Bengali (Bengali script), Portuguese, Indonesian (Latin script), Russian +(Cyrillic), and German. Unrecognized forms use GENERAL; conflicting cues involving +additional languages also use GENERAL. English/Chinese-only scoring is preserved. +This is a lexical heuristic, not full language understanding. See +[the supported forms, script variants, and limits](https://github.com/mnemon-dev/mnemon/blob/master/docs/USAGE.md#recall-intent-detection). + ## Commands ```bash diff --git a/scripts/e2e_test.sh b/scripts/e2e_test.sh index a087c2aa..956e488c 100755 --- a/scripts/e2e_test.sh +++ b/scripts/e2e_test.sh @@ -860,6 +860,41 @@ step "smart recall — auto-detected intent source" OUT=$($M --data-dir "$TESTDIR3" recall "why Alpha service routing" --smart --verbose) assert_jq "intent_source is auto" "$OUT" '.meta.intent_source' 'auto' +step "smart recall — multilingual intent and language-independent override" +while IFS='|' read -r language expected query; do + OUT=$($M --data-dir "$TESTDIR3" recall "$query" --verbose) + assert_jq "$language automatic intent" "$OUT" '.meta.intent' "$expected" + assert_jq "$language automatic source" "$OUT" '.meta.intent_source' 'auto' + OUT=$($M --data-dir "$TESTDIR3" recall "$query" --intent GENERAL --verbose) + assert_jq "$language override wins" "$OUT" '.meta.intent' 'GENERAL' + assert_jq "$language override source" "$OUT" '.meta.intent_source' 'override' +done <<'INTENT_CASES' +Traditional Chinese|WHY|為什麼選擇 Alpha? +Hindi|WHY|हमने Alpha क्यों चुना? +Spanish|WHEN|¿Cuándo elegimos Alpha? +Arabic|ENTITY|ما هو Alpha؟ +French|ENTITY|Qu’est-ce que Alpha ? +Bengali|ENTITY|Alpha কী? +Portuguese|WHY|Alpha por quê? +Indonesian|WHEN|Kapan memilih Alpha? +Russian|WHY|Почему выбрали Alpha? +German|ENTITY|Was ist Alpha? +General|GENERAL|Alpha index tuning +Unicode boundary|GENERAL|Alpha কখনো कब्ज যখন +Ambiguous|GENERAL|¿Por qué y cuándo elegimos Alpha? +Mixed conflict|GENERAL|Why Alpha, wann gewählt? +Mixed agreement|WHY|Pourquoi Alpha, why? +INTENT_CASES + +step "smart recall — multilingual intent is reported even with no results" +OUT=$($M --data-dir "$TESTDATA/intent-empty" recall "हमने PostgreSQL कब चुना?" --verbose) +assert_jq "empty store temporal intent" "$OUT" '.meta.intent' 'WHEN' +assert_jq "empty store automatic source" "$OUT" '.meta.intent_source' 'auto' +assert_jq "empty store results" "$OUT" '.results | length' '0' +OUT=$($M --data-dir "$TESTDATA/intent-empty" recall "PostgreSQL いつ?" --intent WHEN --verbose) +assert_jq "unsupported form override" "$OUT" '.meta.intent' 'WHEN' +assert_jq "unsupported form override source" "$OUT" '.meta.intent_source' 'override' + step "smart recall — signals metadata present" OUT=$($M --data-dir "$TESTDIR3" recall "Alpha service routing" --smart --verbose) FIRST=$(echo "$OUT" | jq '.results[0]')