-
Notifications
You must be signed in to change notification settings - Fork 1
Fix find_code integration: restore implementation and resolve SearchResult→CodeMatch type mismatch #40
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
Fix find_code integration: restore implementation and resolve SearchResult→CodeMatch type mismatch #40
Conversation
Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
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.
Pull Request Overview
This PR re-enables the find_code tool implementation after it was temporarily disabled. The changes restore real search functionality by replacing stub responses with actual vector search operations and add proper type conversion between internal SearchResult objects and the public CodeMatch API response model.
Key changes:
- Restored the
find_code_toolentrypoint to call the real implementation instead of returning stub data - Added type conversion from
SearchResulttoCodeMatchto fix structural incompatibilities - Extended
SearchResultmodel to support dynamic score attributes for hybrid search workflows - Added
serialize_for_cli()method toCodeMatchfor CLI output formatting
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/codeweaver/server/app_bindings.py | Re-enabled find_code implementation by replacing stub with real search call and updated error handling |
| src/codeweaver/core/chunks.py | Extended SearchResult with mutable config, dynamic score fields, and file property for compatibility |
| src/codeweaver/agent_api/models.py | Added serialize_for_cli method to CodeMatch for CLI display formatting |
| src/codeweaver/agent_api/find_code.py | Added SearchResult-to-CodeMatch conversion function and updated response building logic |
| TRIAGE_FINDINGS.md | Documentation of integration test issues and fixes applied |
| NEXT_STEPS.md | Comprehensive documentation of problems, solutions, and remaining work |
Comments suppressed due to low confidence (1)
src/codeweaver/agent_api/find_code.py:170
- Variable query_intent_obj is not used.
query_intent_obj = None
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| class _FileInfo: | ||
| def __init__(self, path): | ||
| self.path = path | ||
| return _FileInfo(self.file_path) if self.file_path else None |
Copilot
AI
Oct 30, 2025
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.
The inner class _FileInfo is defined inside a property method, which means a new class is created on every property access. Consider defining this as a module-level helper class or using a simpler approach like types.SimpleNamespace(path=self.file_path) for better performance and clarity.
| # Step 7: Sort and limit | ||
| candidates.sort(key=lambda x: x.relevance_score, reverse=True) | ||
| results = candidates[:max_results] | ||
| candidates.sort(key=lambda x: x.relevance_score if hasattr(x, 'relevance_score') and x.relevance_score is not None else x.score, reverse=True) |
Copilot
AI
Oct 30, 2025
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.
The sorting key lambda is complex and difficult to read. Consider extracting it into a helper function like get_sort_score(candidate) that returns the relevance_score or falls back to score. This would improve readability and make the logic easier to test.
| candidates.sort(key=lambda x: x.relevance_score if hasattr(x, 'relevance_score') and x.relevance_score is not None else x.score, reverse=True) | |
| def get_sort_score(candidate): | |
| if hasattr(candidate, 'relevance_score') and candidate.relevance_score is not None: | |
| return candidate.relevance_score | |
| return candidate.score | |
| candidates.sort(key=get_sort_score, reverse=True) |
| if results: | ||
| top_files = list({r.file.path.name for r in results[:3]}) | ||
| if code_matches: | ||
| top_files = list({m.file.path.name for m in code_matches[:3] if m.file and m.file.path}) |
Copilot
AI
Oct 30, 2025
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.
Using a set comprehension {...} then converting to list() loses the ordering of the top 3 files. Since the matches are already sorted by relevance, this should preserve order. Use a list comprehension with deduplication instead: seen = set(); [m.file.path.name for m in code_matches[:3] if m.file and m.file.path and m.file.path.name not in seen and not seen.add(m.file.path.name)] or use dict.fromkeys() to preserve order while removing duplicates.
| top_files = list({m.file.path.name for m in code_matches[:3] if m.file and m.file.path}) | |
| # Deduplicate while preserving order | |
| top_files = [] | |
| seen = set() | |
| for m in code_matches[:3]: | |
| if m.file and m.file.path: | |
| name = m.file.path.name | |
| if name not in seen: | |
| top_files.append(name) | |
| seen.add(name) |
| def serialize_for_cli(self) -> dict: | ||
| """Serialize code match for CLI display. | ||
| Returns a dict suitable for rendering in CLI output formats. | ||
| """ | ||
| return { | ||
| "file_path": str(self.file.path), | ||
| "span": self.span, | ||
| "relevance_score": self.relevance_score, | ||
| "match_type": self.match_type.value, | ||
| "content_preview": self.content.content[:200] + "..." if len(self.content.content) > 200 else self.content.content, |
Copilot
AI
Oct 30, 2025
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.
[nitpick] The content preview truncation logic is embedded in the serialization method. Consider adding a max_preview_length parameter (defaulting to 200) to make this configurable and improve testability.
| def serialize_for_cli(self) -> dict: | |
| """Serialize code match for CLI display. | |
| Returns a dict suitable for rendering in CLI output formats. | |
| """ | |
| return { | |
| "file_path": str(self.file.path), | |
| "span": self.span, | |
| "relevance_score": self.relevance_score, | |
| "match_type": self.match_type.value, | |
| "content_preview": self.content.content[:200] + "..." if len(self.content.content) > 200 else self.content.content, | |
| def serialize_for_cli(self, max_preview_length: int = 200) -> dict: | |
| """Serialize code match for CLI display. | |
| Returns a dict suitable for rendering in CLI output formats. | |
| """ | |
| content = self.content.content | |
| preview = content[:max_preview_length] + "..." if len(content) > max_preview_length else content | |
| return { | |
| "file_path": str(self.file.path), | |
| "span": self.span, | |
| "relevance_score": self.relevance_score, | |
| "match_type": self.match_type.value, | |
| "content_preview": preview, |
|
|
||
| # Track successful request in statistics | ||
| if context and context.request_context: | ||
| request_id = getattr(context.request_context, "request_id", "unknown") |
Copilot
AI
Oct 30, 2025
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.
[nitpick] Using getattr() with a default value makes the code more defensive, but if request_id is expected to always exist on request_context, this might silently hide missing attributes. Consider whether 'unknown' is an appropriate fallback or if this should raise an error to catch configuration issues early.
| request_id = getattr(context.request_context, "request_id", "unknown") | |
| request_id = context.request_context.request_id |
Integration tests failing due to find_code_tool returning stub data and fundamental type incompatibility between vector store output (SearchResult) and API response (CodeMatch).
Changes
Restored find_code implementation in app_bindings.py
Fixed SearchResult→CodeMatch type mismatch
Problem: find_code expected SearchResult to support CodeMatch interface, but they're incompatible types.
Extended
SearchResult(chunks.py):extra="allow",validate_assignment=False)dense_score,sparse_score,rerank_score,relevance_scorefileproperty for chunk.file compatibilityUpdated find_code pipeline (find_code.py):
_convert_search_result_to_code_match()to transform vector store output → API responseAdded CLI serialization
CodeMatch.serialize_for_cli()(models.py) for CLI output formattingExample
Test Infrastructure Gap (Not Addressed)
Integration tests create test projects but don't index them before searching, resulting in empty vector stores. Tests need indexing fixtures added separately (detailed in NEXT_STEPS.md).
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
astral.shcurl -LsSf REDACTED(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.