refactor: replace langchain_core with native PotpieTool — closes #222#699
Conversation
…ie-ai#222 Remove the langchain / langchain-core dependency from the project and replace it with a lightweight, stdlib-only implementation: - Add app/modules/intelligence/tools/tool_types.py • PotpieTool — drop-in replacement for langchain_core.tools.StructuredTool, exposing the same .name / .description / .func / .args_schema / .coroutine attributes plus a from_function() classmethod and invoke() method • HumanMessage / AIMessage / BaseMessage — replace langchain_core.messages.* in ChatHistoryService - Update all 55 tool/agent files to import PotpieTool (via alias `PotpieTool as StructuredTool` so call-sites remain unchanged) - Replace langchain_core.messages import in chat_history_service.py with the new local types - Remove "langchain>=...", "langchain-core>=...", "langgraph>=..." from pyproject.toml (langgraph had no actual imports in app/) - Regenerate requirements.txt via `uv pip compile pyproject.toml` (removes all langchain*/langgraph* transitive packages) LangChain chat clients were already migrated to LiteLLM/pydantic-ai in prior work. This PR completes the full removal of langchain_core from the runtime dependency tree.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
💤 Files with no reviewable changes (1)
WalkthroughReplaces LangChain message and StructuredTool imports with a new local implementation (PotpieTool, BaseMessage/AIMessage/HumanMessage) across agents and many tool modules, and removes LangChain-related dependencies from manifest files. Adds app/modules/intelligence/tools/tool_types.py defining PotpieTool and minimal message types. Changes
Sequence Diagram(s)(Skipped — changes are primarily import/type substitutions and a local tool/message implementation; no multi-component sequential flow to visualize.) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
app/modules/intelligence/tools/kg_based_tools/get_nodes_from_tags_tool.py (1)
52-52:⚠️ Potential issue | 🟡 MinorReturn type annotation is incorrect.
The method is annotated to return
str, but it actually returns a list (lines 116 and 131 both return lists). This is a pre-existing issue, not introduced by this PR.Proposed fix
- def run(self, tags: List[str], project_id: str) -> str: + def run(self, tags: List[str], project_id: str) -> List[Dict[str, Any]]:Note: You'll also need to add
Dict, Anyto the imports fromtyping.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/kg_based_tools/get_nodes_from_tags_tool.py` at line 52, The run method is annotated to return str but actually returns lists; update the signature of run(self, tags: List[str], project_id: str) -> List[Dict[str, Any]] (or List[Any] if the element shape is unknown) and add Dict and Any to the typing imports so the annotation is valid; ensure any usages of run that rely on a str are adjusted accordingly.app/modules/intelligence/tools/kg_based_tools/ask_knowledge_graph_queries_tool.py (1)
22-28:⚠️ Potential issue | 🟡 MinorSchema is missing
node_idsfield.The
run()andarun()methods accept anode_idsparameter (lines 103, 108), and the tool description (line 155) documents it as an input. However,MultipleKnowledgeGraphQueriesInputdoesn't include this field, sonode_idswill never be passed when the tool is invoked through the schema. This is a pre-existing issue.Proposed fix
class MultipleKnowledgeGraphQueriesInput(BaseModel): queries: List[str] = Field( description="A list of natural language questions to ask the knowledge graph" ) project_id: str = Field( description="The project id metadata for the project being evaluated" ) + node_ids: List[str] = Field( + default=[], + description="Optional list of node IDs to query when the answer relates to specific nodes" + )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/kg_based_tools/ask_knowledge_graph_queries_tool.py` around lines 22 - 28, MultipleKnowledgeGraphQueriesInput is missing the node_ids field used by run() and arun() and described in the tool; add a new optional field node_ids: Optional[List[str]] (or List[str] with default []) to the Pydantic model so the tool invocation can pass node IDs through the schema; update the Field(...) description to match the tool description and ensure the field name exactly matches the parameter used in run/arun so validation will populate node_ids when the tool is invoked.app/modules/intelligence/tools/change_detection/change_detection_tool.py (1)
601-601:⚠️ Potential issue | 🔴 CriticalUse
loggerinstead oflogging.This line uses
logging.infobut the module defineslogger = setup_logger(__name__)at line 5 and usesloggereverywhere else. Theloggingmodule is not imported, so this will raise aNameErrorat runtime.🐛 Proposed fix
- logging.info( + logger.info(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/change_detection/change_detection_tool.py` at line 601, The call uses logging.info but this module defines logger = setup_logger(__name__) (and does not import the logging module), causing a NameError; replace the logging.info invocation with logger.info so the module uses the existing logger instance (locate the call around the change_detection_tool.py block where logging.info is used and update it to logger.info), keeping the message and arguments unchanged.app/modules/intelligence/tools/jira_tools/get_jira_issue_tool.py (1)
55-59:⚠️ Potential issue | 🟠 MajorInconsistent Jira client usage pattern — fix resource leak across multiple files.
The
JiraClientimplements an async context manager with aclose()method that properly closes the underlyinghttpx.AsyncClient. This file and several others (link_jira_issues_tool.py,search_jira_issues_tool.py,get_jira_projects_tool.py,get_jira_project_users_tool.py,create_jira_issue_tool.py) use direct assignment instead ofasync with, which leaves HTTP connections unclosed. Other files liketransition_jira_issue_tool.py,update_jira_issue_tool.py, andadd_jira_comment_tool.pycorrectly useasync with await get_jira_client_for_user(...) as client:. Wrap the client instantiation in an async context manager to prevent connection exhaustion.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/jira_tools/get_jira_issue_tool.py` around lines 55 - 59, The code currently assigns the Jira client directly (client = await get_jira_client_for_user(self.user_id, self.db)) which bypasses the JiraClient async context manager and can leak httpx connections; change the instantiation to use the async context manager pattern: "async with await get_jira_client_for_user(self.user_id, self.db) as client:" in the function/method that calls client.get_issue(issue_key) (look for get_jira_issue_tool.py usage of get_jira_client_for_user and the call to client.get_issue), ensuring the JiraClient.close() path is exercised so the underlying httpx.AsyncClient is properly closed.
🧹 Nitpick comments (6)
app/modules/intelligence/tools/registry/discovery_tools.py (1)
1-6: Update docstring to reflect PotpieTool migration.The module docstring still references "LangChain StructuredTools" (line 3), but the implementation now uses
PotpieTool. Consider updating for accuracy.📝 Suggested documentation update
-"""Phase 3: Discovery meta-tools (search_tools, describe_tool, execute_tool) for deferred tool loading. +"""Phase 3: Discovery meta-tools (search_tools, describe_tool, execute_tool) for deferred tool loading. -Builds three LangChain StructuredTools scoped to an allow-list. The agent receives +Builds three PotpieTool-based StructuredTools scoped to an allow-list. The agent receives these instead of the full tool list when use_tool_search_flow=True, then discovers tools via search_tools, gets full schema via describe_tool, and runs via execute_tool. """🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/registry/discovery_tools.py` around lines 1 - 6, Update the module docstring to reflect that the discovery meta-tools now build and return PotpieTool instances (not LangChain StructuredTools); mention the three tools by name (search_tools, describe_tool, execute_tool) and note they are scoped to an allow-list and used when use_tool_search_flow=True, and remove or replace the "LangChain StructuredTools" phrase with "PotpieTool" to accurately describe the implementation.app/modules/intelligence/tools/code_query_tools/get_node_neighbours_from_node_id_tool.py (1)
141-142: Minor typo in description: "Pythoon" → "Python".Pre-existing typo, but worth fixing while touching this file.
📝 Fix typo
- description="Retrieves inbound and outbound neighbors of a specific node in a repository given its node ID. This is helpful to find which functions are called by a specific function and which functions are calling the specific function. Works best with Pythoon, JS and TS code.", + description="Retrieves inbound and outbound neighbors of a specific node in a repository given its node ID. This is helpful to find which functions are called by a specific function and which functions are calling the specific function. Works best with Python, JS and TS code.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/code_query_tools/get_node_neighbours_from_node_id_tool.py` around lines 141 - 142, The tool description string for the GetNodeNeighbours tool contains a typo ("Pythoon"); update the description passed where args_schema=GetNodeNeighboursInput is set so it reads "Python" instead of "Pythoon" (i.e., edit the description value associated with GetNodeNeighboursInput to correct the spelling).app/modules/intelligence/tools/code_query_tools/code_analysis.py (1)
581-586: Consider moving the import to the module level for consistency.The import is placed inside the factory function, which differs from all other tool files in this PR where the import is at the module level. Unless there's a specific reason (e.g., circular import avoidance), consider moving it to line 18 with the other imports for consistency.
♻️ Suggested refactor
At line 18 (with other imports):
from tree_sitter_language_pack import get_language, get_parser +from app.modules.intelligence.tools.tool_types import PotpieTool as StructuredTool from app.modules.code_provider.code_provider_service import CodeProviderServiceThen at line 583, remove the local import:
def universal_analyze_code_tool(sql_db: Session, user_id: str): """Factory function to create the universal code analysis tool.""" - from app.modules.intelligence.tools.tool_types import PotpieTool as StructuredTool tool_instance = UniversalAnalyzeCodeTool(sql_db, user_id)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/code_query_tools/code_analysis.py` around lines 581 - 586, The local import of PotpieTool (alias StructuredTool) inside universal_analyze_code_tool differs from other files; move the import to the module level with the other imports (so PotpieTool is imported near line 18) and then remove the in-function import inside universal_analyze_code_tool; update any aliasing (StructuredTool) where used and ensure UniversalAnalyzeCodeTool and universal_analyze_code_tool continue to reference the now-module-level PotpieTool/StructuredTool.app/modules/intelligence/tools/registry/annotation_logging.py (1)
94-94: Update stale comment referencing LangChain.This comment references "LangChain StructuredTool" but the codebase now uses
PotpieTool. Consider updating for accuracy.📝 Proposed fix
- # LangChain StructuredTool accepts only BaseModel subclass or JSON schema dict + # PotpieTool accepts only BaseModel subclass or JSON schema dict🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/registry/annotation_logging.py` at line 94, The existing inline comment "LangChain StructuredTool accepts only BaseModel subclass or JSON schema dict" is stale; update it to accurately reference the current tool implementation (e.g., "PotpieTool accepts only BaseModel subclass or JSON schema dict") or replace with a neutral description like "Tool accepts only BaseModel subclass or JSON schema dict" in annotation_logging.py so the comment matches the current codebase and won't mislead future readers.app/modules/intelligence/tools/change_detection/change_detection_tool.py (2)
878-881: Update stale docstring reference to LangChain.The docstring still references "LangChain Tool objects" but this PR removes LangChain. Consider updating the documentation to reflect the new
PotpieToolimplementation.📝 Proposed fix
def get_change_detection_tool(user_id: str) -> StructuredTool: """ - Get a list of LangChain Tool objects for use in agents. + Get a StructuredTool for change detection for use in agents. """🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/change_detection/change_detection_tool.py` around lines 878 - 881, The docstring for get_change_detection_tool incorrectly mentions "LangChain Tool objects"; update it to accurately describe the current return type and purpose (e.g., returns a list of PotpieTool or StructuredTool-compatible Potpie tools usable by agents for change detection). Edit the docstring at the get_change_detection_tool function to remove the LangChain reference, state the new tool type (PotpieTool) and what the tools do, and ensure any parameter/return descriptions match the function signature.
630-631: Avoid bareexcept:clause.Bare except clauses catch all exceptions including
KeyboardInterruptandSystemExit, which can mask issues and make debugging difficult. Consider catching a specific exception type.♻️ Proposed fix
- except: + except Exception: pass🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/modules/intelligence/tools/change_detection/change_detection_tool.py` around lines 630 - 631, The bare "except: pass" in the change detection code should be replaced with a narrower catch to avoid swallowing SystemExit/KeyboardInterrupt; change it to "except Exception as e:" (or another specific exception type if known), log the error (e.g., using logger.exception(...) or self.logger.warning(..., exc_info=True)) to preserve context, and then continue or handle recovery as appropriate instead of silently passing; ensure you do not catch BaseException so KeyboardInterrupt/SystemExit still propagate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/modules/intelligence/tools/tool_types.py`:
- Around line 80-84: The invoke method drops caller-supplied kwargs; update
invoke (in tool_types.py) so both branches forward kwargs: call
self._call(**input_data, **kwargs) when input_data is a dict, and call
self.func(input_data, **kwargs) otherwise, ensuring kwargs are preserved and
passed to the referenced functions (_call and func).
- Around line 88-102: The code currently only adapts when the single parameter
is annotated as a BaseModel subclass, causing func(**kwargs) to fail for
unannotated single-parameter model tools; update the branch in the args_schema
handling (the block using inspect.signature, params, and annotation) to also
detect when there is exactly one parameter and annotation is
inspect.Parameter.empty, and in that case instantiate the provided args_schema
(which is a BaseModel subclass) with kwargs and call self.func(instance) instead
of self.func(**kwargs); keep the existing try/except around inspect.signature
and preserve the fallback return self.func(**kwargs) for other cases.
---
Outside diff comments:
In `@app/modules/intelligence/tools/change_detection/change_detection_tool.py`:
- Line 601: The call uses logging.info but this module defines logger =
setup_logger(__name__) (and does not import the logging module), causing a
NameError; replace the logging.info invocation with logger.info so the module
uses the existing logger instance (locate the call around the
change_detection_tool.py block where logging.info is used and update it to
logger.info), keeping the message and arguments unchanged.
In `@app/modules/intelligence/tools/jira_tools/get_jira_issue_tool.py`:
- Around line 55-59: The code currently assigns the Jira client directly (client
= await get_jira_client_for_user(self.user_id, self.db)) which bypasses the
JiraClient async context manager and can leak httpx connections; change the
instantiation to use the async context manager pattern: "async with await
get_jira_client_for_user(self.user_id, self.db) as client:" in the
function/method that calls client.get_issue(issue_key) (look for
get_jira_issue_tool.py usage of get_jira_client_for_user and the call to
client.get_issue), ensuring the JiraClient.close() path is exercised so the
underlying httpx.AsyncClient is properly closed.
In
`@app/modules/intelligence/tools/kg_based_tools/ask_knowledge_graph_queries_tool.py`:
- Around line 22-28: MultipleKnowledgeGraphQueriesInput is missing the node_ids
field used by run() and arun() and described in the tool; add a new optional
field node_ids: Optional[List[str]] (or List[str] with default []) to the
Pydantic model so the tool invocation can pass node IDs through the schema;
update the Field(...) description to match the tool description and ensure the
field name exactly matches the parameter used in run/arun so validation will
populate node_ids when the tool is invoked.
In `@app/modules/intelligence/tools/kg_based_tools/get_nodes_from_tags_tool.py`:
- Line 52: The run method is annotated to return str but actually returns lists;
update the signature of run(self, tags: List[str], project_id: str) ->
List[Dict[str, Any]] (or List[Any] if the element shape is unknown) and add Dict
and Any to the typing imports so the annotation is valid; ensure any usages of
run that rely on a str are adjusted accordingly.
---
Nitpick comments:
In `@app/modules/intelligence/tools/change_detection/change_detection_tool.py`:
- Around line 878-881: The docstring for get_change_detection_tool incorrectly
mentions "LangChain Tool objects"; update it to accurately describe the current
return type and purpose (e.g., returns a list of PotpieTool or
StructuredTool-compatible Potpie tools usable by agents for change detection).
Edit the docstring at the get_change_detection_tool function to remove the
LangChain reference, state the new tool type (PotpieTool) and what the tools do,
and ensure any parameter/return descriptions match the function signature.
- Around line 630-631: The bare "except: pass" in the change detection code
should be replaced with a narrower catch to avoid swallowing
SystemExit/KeyboardInterrupt; change it to "except Exception as e:" (or another
specific exception type if known), log the error (e.g., using
logger.exception(...) or self.logger.warning(..., exc_info=True)) to preserve
context, and then continue or handle recovery as appropriate instead of silently
passing; ensure you do not catch BaseException so KeyboardInterrupt/SystemExit
still propagate.
In `@app/modules/intelligence/tools/code_query_tools/code_analysis.py`:
- Around line 581-586: The local import of PotpieTool (alias StructuredTool)
inside universal_analyze_code_tool differs from other files; move the import to
the module level with the other imports (so PotpieTool is imported near line 18)
and then remove the in-function import inside universal_analyze_code_tool;
update any aliasing (StructuredTool) where used and ensure
UniversalAnalyzeCodeTool and universal_analyze_code_tool continue to reference
the now-module-level PotpieTool/StructuredTool.
In
`@app/modules/intelligence/tools/code_query_tools/get_node_neighbours_from_node_id_tool.py`:
- Around line 141-142: The tool description string for the GetNodeNeighbours
tool contains a typo ("Pythoon"); update the description passed where
args_schema=GetNodeNeighboursInput is set so it reads "Python" instead of
"Pythoon" (i.e., edit the description value associated with
GetNodeNeighboursInput to correct the spelling).
In `@app/modules/intelligence/tools/registry/annotation_logging.py`:
- Line 94: The existing inline comment "LangChain StructuredTool accepts only
BaseModel subclass or JSON schema dict" is stale; update it to accurately
reference the current tool implementation (e.g., "PotpieTool accepts only
BaseModel subclass or JSON schema dict") or replace with a neutral description
like "Tool accepts only BaseModel subclass or JSON schema dict" in
annotation_logging.py so the comment matches the current codebase and won't
mislead future readers.
In `@app/modules/intelligence/tools/registry/discovery_tools.py`:
- Around line 1-6: Update the module docstring to reflect that the discovery
meta-tools now build and return PotpieTool instances (not LangChain
StructuredTools); mention the three tools by name (search_tools, describe_tool,
execute_tool) and note they are scoped to an allow-list and used when
use_tool_search_flow=True, and remove or replace the "LangChain StructuredTools"
phrase with "PotpieTool" to accurately describe the implementation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4104f6c6-7459-4284-ba28-cf9444b2dfbf
📒 Files selected for processing (58)
app/modules/intelligence/agents/chat_agents/multi_agent/agent_factory.pyapp/modules/intelligence/agents/chat_agents/pydantic_agent.pyapp/modules/intelligence/agents/chat_agents/pydantic_multi_agent.pyapp/modules/intelligence/memory/chat_history_service.pyapp/modules/intelligence/tools/change_detection/change_detection_tool.pyapp/modules/intelligence/tools/code_query_tools/apply_changes_tool.pyapp/modules/intelligence/tools/code_query_tools/bash_command_tool.pyapp/modules/intelligence/tools/code_query_tools/checkout_worktree_branch_tool.pyapp/modules/intelligence/tools/code_query_tools/code_analysis.pyapp/modules/intelligence/tools/code_query_tools/create_pr_workflow_tool.pyapp/modules/intelligence/tools/code_query_tools/get_code_file_structure.pyapp/modules/intelligence/tools/code_query_tools/get_code_graph_from_node_id_tool.pyapp/modules/intelligence/tools/code_query_tools/get_file_content_by_path.pyapp/modules/intelligence/tools/code_query_tools/get_node_neighbours_from_node_id_tool.pyapp/modules/intelligence/tools/code_query_tools/git_commit_tool.pyapp/modules/intelligence/tools/code_query_tools/git_push_tool.pyapp/modules/intelligence/tools/code_query_tools/intelligent_code_graph_tool.pyapp/modules/intelligence/tools/confluence_tools/__init__.pyapp/modules/intelligence/tools/confluence_tools/add_confluence_comment_tool.pyapp/modules/intelligence/tools/confluence_tools/create_confluence_page_tool.pyapp/modules/intelligence/tools/confluence_tools/get_confluence_page_tool.pyapp/modules/intelligence/tools/confluence_tools/get_confluence_space_pages_tool.pyapp/modules/intelligence/tools/confluence_tools/get_confluence_spaces_tool.pyapp/modules/intelligence/tools/confluence_tools/search_confluence_pages_tool.pyapp/modules/intelligence/tools/confluence_tools/update_confluence_page_tool.pyapp/modules/intelligence/tools/jira_tools/add_jira_comment_tool.pyapp/modules/intelligence/tools/jira_tools/create_jira_issue_tool.pyapp/modules/intelligence/tools/jira_tools/get_jira_issue_tool.pyapp/modules/intelligence/tools/jira_tools/get_jira_project_details_tool.pyapp/modules/intelligence/tools/jira_tools/get_jira_project_users_tool.pyapp/modules/intelligence/tools/jira_tools/get_jira_projects_tool.pyapp/modules/intelligence/tools/jira_tools/link_jira_issues_tool.pyapp/modules/intelligence/tools/jira_tools/search_jira_issues_tool.pyapp/modules/intelligence/tools/jira_tools/transition_jira_issue_tool.pyapp/modules/intelligence/tools/jira_tools/update_jira_issue_tool.pyapp/modules/intelligence/tools/kg_based_tools/ask_knowledge_graph_queries_tool.pyapp/modules/intelligence/tools/kg_based_tools/get_code_from_multiple_node_ids_tool.pyapp/modules/intelligence/tools/kg_based_tools/get_code_from_node_id_tool.pyapp/modules/intelligence/tools/kg_based_tools/get_code_from_probable_node_name_tool.pyapp/modules/intelligence/tools/kg_based_tools/get_nodes_from_tags_tool.pyapp/modules/intelligence/tools/linear_tools/get_linear_issue_tool.pyapp/modules/intelligence/tools/linear_tools/update_linear_issue_tool.pyapp/modules/intelligence/tools/registry/annotation_logging.pyapp/modules/intelligence/tools/registry/discovery_tools.pyapp/modules/intelligence/tools/registry/resolver.pyapp/modules/intelligence/tools/think_tool.pyapp/modules/intelligence/tools/tool_service.pyapp/modules/intelligence/tools/tool_types.pyapp/modules/intelligence/tools/web_tools/code_provider_add_pr_comment.pyapp/modules/intelligence/tools/web_tools/code_provider_create_branch.pyapp/modules/intelligence/tools/web_tools/code_provider_create_pr.pyapp/modules/intelligence/tools/web_tools/code_provider_tool.pyapp/modules/intelligence/tools/web_tools/code_provider_update_file.pyapp/modules/intelligence/tools/web_tools/github_tool.pyapp/modules/intelligence/tools/web_tools/web_search_tool.pyapp/modules/intelligence/tools/web_tools/webpage_extractor_tool.pypyproject.tomlrequirements.txt
💤 Files with no reviewable changes (1)
- pyproject.toml
| def invoke(self, input_data: Union[dict, Any], **kwargs: Any) -> Any: | ||
| """Invoke the tool synchronously with dict input.""" | ||
| if isinstance(input_data, dict): | ||
| return self._call(**input_data) | ||
| return self.func(input_data) |
There was a problem hiding this comment.
Forward kwargs in invoke(); they are currently dropped.
invoke(..., **kwargs) ignores kwargs in both branches, so caller-supplied arguments are lost.
Proposed fix
def invoke(self, input_data: Union[dict, Any], **kwargs: Any) -> Any:
"""Invoke the tool synchronously with dict input."""
if isinstance(input_data, dict):
- return self._call(**input_data)
- return self.func(input_data)
+ return self._call(**{**input_data, **kwargs})
+ return self.func(input_data, **kwargs)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def invoke(self, input_data: Union[dict, Any], **kwargs: Any) -> Any: | |
| """Invoke the tool synchronously with dict input.""" | |
| if isinstance(input_data, dict): | |
| return self._call(**input_data) | |
| return self.func(input_data) | |
| def invoke(self, input_data: Union[dict, Any], **kwargs: Any) -> Any: | |
| """Invoke the tool synchronously with dict input.""" | |
| if isinstance(input_data, dict): | |
| return self._call(**{**input_data, **kwargs}) | |
| return self.func(input_data, **kwargs) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/modules/intelligence/tools/tool_types.py` around lines 80 - 84, The
invoke method drops caller-supplied kwargs; update invoke (in tool_types.py) so
both branches forward kwargs: call self._call(**input_data, **kwargs) when
input_data is a dict, and call self.func(input_data, **kwargs) otherwise,
ensuring kwargs are preserved and passed to the referenced functions (_call and
func).
…sues - Move asyncio and concurrent.futures imports to module top level (no more imports inside function body → fixes maintainability code smell) - Remove unused 'loop' variable in _sync_wrapper; capture the running loop into 'running_loop' which is then referenced in the if-guard (fixes dead-assignment reliability bug that caused D rating) - Specify max_workers=1 for ThreadPoolExecutor (one coroutine, one thread) - Extract long compound condition in _call into a named boolean 'is_basemodel_schema' to stay well under the 120-char line limit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename **kwargs -> **_kwargs in from_function and invoke to make explicit that these params are accepted only for API compatibility with the LangChain Runnable interface and are not forwarded to the tool function (avoids polluting call-sites that do not expect them) - Extend _call to handle unannotated single-parameter functions when args_schema is a BaseModel: build the model from kwargs even when the parameter carries no annotation (covers tools typed as `def run(input_data)`) - Remove unnecessary pass statements from HumanMessage/AIMessage class bodies (docstring is a valid class body on its own) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hain removal The previous uv pip compile was run on a GPU server, which introduced CUDA/Triton/nvidia-* packages, secretstorage, and jeepney that are not part of the project's declared dependencies in pyproject.toml. This commit re-generates requirements.txt from the base branch, removing only the langchain-core/langchain/langgraph/langsmith transitive tree while leaving all other packages intact. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|




Summary
Closes #222 — removes
langchain/langchain-core/langgraphfrom the runtime dependency tree, completing the LiteLLM migration.What was done
New file:
app/modules/intelligence/tools/tool_types.pyIntroduces two lightweight, stdlib-only types:
PotpieTool— drop-in replacement forlangchain_core.tools.StructuredTool.Exposes the same public surface:
.name,.description,.func,.args_schema,.coroutine,from_function()classmethod, andinvoke()method.Zero external dependencies — uses only
inspectandpydantic(already a hard dep).HumanMessage/AIMessage/BaseMessage— minimal message containers that replacelangchain_core.messages.*used inChatHistoryService.55 tool / agent files updated
All
from langchain_core.tools import StructuredToolimports replaced with:The alias keeps every call-site unchanged — no further edits needed in tool bodies.
chat_history_service.pyupdatedfrom langchain_core.messages import AIMessage, BaseMessage, HumanMessagenow points to the new local types.pyproject.toml&requirements.txtlangchain>=…,langchain-core>=…,langgraph>=…(langgraph had no actualimportstatements inapp/).requirements.txtregenerated viauv pip compile pyproject.toml— alllangchain*/langgraph*transitive packages removed.Context
The LangChain chat clients were already replaced with LiteLLM / pydantic-ai in prior work. The only remaining LangChain footprint was
StructuredTool(used purely as a type/factory for tool objects) and the three message classes. This PR removes that last footprint.Test plan
ast.parse)PotpieTool.from_function()/.invoke()/.args_schema.schema()verified with inline teststests/unit/core,tests/unit/utils,tests/unit/search)grep -r "langchain_core" app/returns only comments intool_types.py— no live imports🤖 Generated with Claude Code
Summary by CodeRabbit