Repository navigation
Conversation
codegraph_context returned an empty context for non-ASCII task
descriptions (e.g. "로그인") even though codegraph_query found the
symbols. The two keyword extractors that feed context —
extractSymbolsFromQuery (src/context) and extractSearchTerms
(src/search/query-utils) — were built solely from ASCII patterns
([a-zA-Z] + the ASCII \b word boundary), so they yielded zero keywords
for a non-Latin query and searched for nothing.
Both extractors now also pick up runs of Unicode letters/digits and pass
them to the existing FTS path, which already tokenizes non-ASCII text via
unicode61. The change is additive: ASCII extraction is byte-identical
([a-zA-Z0-9] ⊂ [\p{L}\p{N}] and every ASCII separator stays a separator),
and only the FTS keyword-extraction preprocessing is touched — FTS index
columns are unchanged.
Adds Korean unit coverage for extractSearchTerms and an end-to-end
context.test.ts case proving Korean symbols now surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
colbymchenry
added a commit
that referenced
this pull request
Oct 30, 2026
…low and context The index stores a name in any script as one full-text token, and `codegraph query 로그인` found it, but every tokenizer between a question and the index knew only ASCII: extractSearchTerms split on [^a-zA-Z0-9] and kept 3+ characters, context's extractSymbolsFromQuery matched ASCII patterns only, and explore's exploreQueryTokens and the Flow's flowTokens required a leading [A-Za-z_$] and 3+ characters. So `explore 寻路服务` answered "No relevant code found", `context 로그인` printed only its header and `explore 入口 末端` had no Flow, while their ASCII twins worked. Shared helpers in search/query-utils now read words in any script whole: letters, digits and combining marks, cut where Han, kana or Hangul meets another script (NavMeshAgent类型 is NavMeshAgent and 类型, never agent类型), at least 2 characters in Han, kana or Hangul and 3 elsewhere, so Russian на and из stay out. extractSearchTerms and the explore and Flow tokens use them. Context adds names with a non-ASCII letter as whole runs, and a mixed name like get用户信息 as written, with no n-grams, so a partial Chinese word still never becomes a search of its own (PR #2005). The ASCII-only patterns see a word with accented or other non-ASCII letters blanked out, so état is no longer read as tat. A Han, kana or Hangul token counts as a deliberately named identifier, as such a name has no case or underscore to show it, so a query of such names is neither damped as prose nor flagged low-confidence. Validation: new cjk-query-tokens tests (12) cover CJK, mixed, Cyrillic and accented words, reference copies of the old tokenizers over an ASCII corpus, and explore and context end to end on Korean, Chinese and Japanese fixtures; 9 fail on main's source. Explore and context A/B with 214 ASCII queries (gin 76, Alamofire 79, express 59; 49 lead with a Flow): all byte-identical. Of 12 non-ASCII queries, 6 changed on gin and 4 on express, as intended: état, Señal and naïve are read whole, and handleHTTPRequest处理 now names handleHTTPRequest. Tokenizing a 10,000-character query takes at most 1.8 ms, against 0.1-0.3 ms before. Reimplements PR #516 by @andy-sg and PR #1262 by @yimingll. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
colbymchenry
added a commit
that referenced
this pull request
Oct 30, 2026
…low and context (#3031) The index stores a name in any script as one full-text token, and `codegraph query 로그인` found it, but every tokenizer between a question and the index knew only ASCII: extractSearchTerms split on [^a-zA-Z0-9] and kept 3+ characters, context's extractSymbolsFromQuery matched ASCII patterns only, and explore's exploreQueryTokens and the Flow's flowTokens required a leading [A-Za-z_$] and 3+ characters. So `explore 寻路服务` answered "No relevant code found", `context 로그인` printed only its header and `explore 入口 末端` had no Flow, while their ASCII twins worked. Shared helpers in search/query-utils now read words in any script whole: letters, digits and combining marks, cut where Han, kana or Hangul meets another script (NavMeshAgent类型 is NavMeshAgent and 类型, never agent类型), at least 2 characters in Han, kana or Hangul and 3 elsewhere, so Russian на and из stay out. extractSearchTerms and the explore and Flow tokens use them. Context adds names with a non-ASCII letter as whole runs, and a mixed name like get用户信息 as written, with no n-grams, so a partial Chinese word still never becomes a search of its own (PR #2005). The ASCII-only patterns see a word with accented or other non-ASCII letters blanked out, so état is no longer read as tat. A Han, kana or Hangul token counts as a deliberately named identifier, as such a name has no case or underscore to show it, so a query of such names is neither damped as prose nor flagged low-confidence. Validation: new cjk-query-tokens tests (12) cover CJK, mixed, Cyrillic and accented words, reference copies of the old tokenizers over an ASCII corpus, and explore and context end to end on Korean, Chinese and Japanese fixtures; 9 fail on main's source. Explore and context A/B with 214 ASCII queries (gin 76, Alamofire 79, express 59; 49 lead with a Flow): all byte-identical. Of 12 non-ASCII queries, 6 changed on gin and 4 on express, as intended: état, Señal and naïve are read whole, and handleHTTPRequest处理 now names handleHTTPRequest. Tokenizing a 10,000-character query takes at most 1.8 ms, against 0.1-0.3 ms before. Reimplements PR #516 by @andy-sg and PR #1262 by @yimingll. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Thanks @andy-sg for tracking this down to the ASCII-only keyword extraction! We reimplemented the fix in #3031, together with #1262: context, explore and explore's call-path Flow now read Korean, Chinese and Japanese names as whole words (two characters are enough in those scripts), and a name written right against another script, like |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
codegraph context <task>(and thecodegraph_contextMCP tool) returns an empty context for non-ASCII task descriptions — Korean, Japanese, Chinese, etc. — even though symbol search works fine for the same input.Reproduction (before this PR):
Root cause
Symbol search already handles non-ASCII (FTS5's default
unicode61tokenizer + prefix/LIKE matching, andname COLLATE NOCASE =exact lookup). The break is purely in the keyword-extraction preprocessing that feedscontext.Both extractors are built entirely from ASCII patterns —
[a-zA-Z]character classes plus JS's ASCII\bword boundary:extractSymbolsFromQuery(src/context/index.ts) — camelCase / snake_case / SCREAMING / acronym / dot-notation / lowercase, all[a-zA-Z]-anchored.extractSearchTerms(src/search/query-utils.ts) — final tokenization splits on/[^a-zA-Z0-9]+/, which treats every Hangul/CJK character as a separator, so a non-ASCII query tokenizes to nothing.Result: a non-Latin description yields zero keywords, so the search/traversal pipeline receives nothing and the context comes back empty.
Fix (additive only)
extractSymbolsFromQuery: after the existing ASCII patterns, also pull runs of Unicode letters/digits (/[\p{L}\p{N}_]+/gu) and keep only tokens that actually contain a non-ASCII character. ASCII-only tokens stay owned by the existing patterns, so nothing about ASCII behavior changes.extractSearchTerms: change the final word split from/[^a-zA-Z0-9]+/to/[^\p{L}\p{N}]+/u. This is byte-identical for ASCII ([a-zA-Z0-9] ⊂ [\p{L}\p{N}], and every ASCII separator — space, punctuation,_,.— remains a separator) while keeping Unicode letter runs intact. Non-ASCII tokens use a 2-char floor (Hangul/CJK pack a morpheme per character); ASCII keeps its 3-char floor.Extracted non-ASCII tokens flow straight into the existing search path, which already tokenizes them via
unicode61.Out of scope (deliberately): indexing comments/string-literal bodies into FTS. The FTS index still covers only
name/qualified_name/docstring/signature— unchanged. This PR fixes only the context keyword-extraction step.After this PR,
codegraph context "로그인"surfaces the로그인entry point, the인증확인related symbol, and their code blocks.Tests
__tests__/query-utils.test.ts(new): unit coverage forextractSearchTerms— ASCII behavior unchanged (camelCase/snake_case/dot-notation split, stop-word + <3-char drop) plus Korean extraction (single token, multi-word split, 2-char floor, mixed ASCII+Korean).__tests__/context.test.ts(added): end-to-end — index a Korean source file and assertfindRelevantContext/buildContextnow surface로그인/인증확인/사용자관리자(a regression guard for the reported empty-context bug).