-
Notifications
You must be signed in to change notification settings - Fork 1
feat(tools): 이메일 주소 추출기 도구 추가 #1512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/url-extractor-tool-13801754247534544736
Are you sure you want to change the base?
Changes from 15 commits
5307b72
310fea6
ee34fb7
029b619
671ebdc
6a66a9b
7bf1db2
42c3f30
d77a256
96cad29
e9365ce
2628291
d9bafb6
ecf40d8
c5582d6
6b33c36
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -638,6 +638,38 @@ async def email_phone_masker_handler(params: Dict[str, Any]) -> Dict[str, str]: | |
| ) | ||
|
|
||
|
|
||
| async def email_address_extractor_handler(params: Dict[str, Any]) -> Dict[str, Any]: | ||
| """Extract valid ASCII email addresses in first-occurrence order.""" | ||
| text = params.get("text", "") | ||
| if len(text) > ANALYSIS_TEXT_MAX_CHARS: | ||
| raise ValueError( | ||
| f"Analysis text must not exceed {ANALYSIS_TEXT_MAX_CHARS} characters" | ||
| ) | ||
|
|
||
| unique_emails: list[str] = [] | ||
| seen_addresses: set[str] = set() | ||
| for match in _EMAIL_PATTERN.finditer(text): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the input contains a malformed token such as Useful? React with 👍 / 👎. |
||
| email_address = match.group(0) | ||
| normalized_address = email_address.casefold() | ||
| if normalized_address not in seen_addresses: | ||
| seen_addresses.add(normalized_address) | ||
| unique_emails.append(email_address) | ||
|
|
||
| return {"emails": unique_emails, "count": len(unique_emails)} | ||
|
|
||
|
|
||
| registry.register( | ||
| ToolInfo( | ||
| code="email_address_extractor", | ||
| name="이메일 주소 추출기 (Email Address Extractor)", | ||
| description="텍스트 본문에서 유효한 ASCII 이메일 주소를 찾아 중복을 제거하여 추출합니다.", | ||
| category="이메일 분석", | ||
| parameters={"text": "string"}, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Registering this parameterized tool automatically exposes it in the existing Useful? React with 👍 / 👎. |
||
| ), | ||
| email_address_extractor_handler, | ||
| ) | ||
|
|
||
|
|
||
| async def uuid_v4_generator_handler(params: Dict[str, Any]) -> Dict[str, str]: | ||
| """Generate one RFC 9562 UUID version 4 for the retained built-in utility.""" | ||
| return {"uuid": str(uuid.uuid4())} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Email address extractor contract | ||
|
|
||
| ## Problem | ||
|
|
||
| The first extractor used a second permissive regular expression. It accepted | ||
| empty domain labels such as `a@b..com` and then tried to repair sentence | ||
| punctuation after matching. That disagreed with the email masker and allowed | ||
| the two tools to classify the same address differently. | ||
|
|
||
| ## Boundary | ||
|
|
||
| The extractor and masker now share `_EMAIL_PATTERN` in `backend/api/tools.py`. | ||
| It accepts a bounded ASCII dot-atom local part and DNS-style domain labels, | ||
| preserves the first spelling encountered, and deduplicates case-insensitively. | ||
| Quoted local parts, comments, internationalized addresses, domain literals, | ||
| and full mailbox parsing remain outside this utility tool's claim. | ||
|
|
||
| This is an extraction aid, not an RFC-complete mailbox validator. Sending and | ||
| identity boundaries must still use their protocol-specific validation. | ||
|
|
||
| ## Verification | ||
|
|
||
| `backend/tests/test_tools_api.py` covers mixed-case duplicate addresses, | ||
| subdomains, sentence punctuation, ellipses, malformed empty domain labels, | ||
| the signed API envelope, empty input, and the shared input-size limit. | ||
|
|
||
| ## Reference | ||
|
|
||
| Resnick, P. (2008). *Internet message format* (RFC 5322). Internet Engineering | ||
| Task Force. https://doi.org/10.17487/RFC5322 | ||
|
|
||
| RFC 5322 sections 3.2.3 and 3.4.1 define dot-atoms and address syntax. The | ||
| bounded matcher deliberately implements only the common ASCII dot-atom and | ||
| DNS-label subset described above, avoiding claims of complete RFC parsing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 Info: Registry enforces text input
The execution path requires
textand validates its string type before invoking the handler. The empty fallback only affects direct internal calls.Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인했습니다. public registry path가
text존재와 문자열 형식을 검증하므로 handler의 빈 fallback은 direct internal call에서만 작동합니다. 이 informational finding은 trust-boundary 변경을 요구하지 않으며 현재 signed API envelope test가 public 경로를 검증합니다.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Acknowledged.