Skip to content

refactor: replace langchain_core with native PotpieTool — closes #222#699

Open
brutusworker-arch wants to merge 4 commits intopotpie-ai:mainfrom
brutusworker-arch:feature/litellm-refactor-remove-langchain-structured-tool
Open

refactor: replace langchain_core with native PotpieTool — closes #222#699
brutusworker-arch wants to merge 4 commits intopotpie-ai:mainfrom
brutusworker-arch:feature/litellm-refactor-remove-langchain-structured-tool

Conversation

@brutusworker-arch
Copy link
Copy Markdown

@brutusworker-arch brutusworker-arch commented Mar 18, 2026

Summary

Closes #222 — removes langchain / langchain-core / langgraph from the runtime dependency tree, completing the LiteLLM migration.

What was done

New file: app/modules/intelligence/tools/tool_types.py

Introduces two lightweight, stdlib-only types:

  • PotpieTool — drop-in replacement for langchain_core.tools.StructuredTool.
    Exposes the same public surface: .name, .description, .func, .args_schema, .coroutine, from_function() classmethod, and invoke() method.
    Zero external dependencies — uses only inspect and pydantic (already a hard dep).

  • HumanMessage / AIMessage / BaseMessage — minimal message containers that replace langchain_core.messages.* used in ChatHistoryService.

55 tool / agent files updated

All from langchain_core.tools import StructuredTool imports replaced with:

from app.modules.intelligence.tools.tool_types import PotpieTool as StructuredTool

The alias keeps every call-site unchanged — no further edits needed in tool bodies.

chat_history_service.py updated

from langchain_core.messages import AIMessage, BaseMessage, HumanMessage now points to the new local types.

pyproject.toml & requirements.txt

  • Removed langchain>=…, langchain-core>=…, langgraph>=… (langgraph had no actual import statements in app/).
  • requirements.txt regenerated via uv pip compile pyproject.toml — all langchain* / 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

  • All 55 modified files parse without syntax errors (ast.parse)
  • PotpieTool.from_function() / .invoke() / .args_schema.schema() verified with inline tests
  • 51 unit tests pass (tests/unit/core, tests/unit/utils, tests/unit/search)
  • grep -r "langchain_core" app/ returns only comments in tool_types.py — no live imports
  • Full integration test suite (requires running Postgres + Neo4j infra)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Replaced external tool and message implementations with an internal, lightweight implementation while preserving existing public behavior and APIs.
  • Chores
    • Removed several external AI-framework dependencies from project manifests.

…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.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: da9c65e2-d205-41c9-8b48-7cb79a4185cc

📥 Commits

Reviewing files that changed from the base of the PR and between 68c574a and 6eb5e3a.

📒 Files selected for processing (1)
  • requirements.txt
💤 Files with no reviewable changes (1)
  • requirements.txt

Walkthrough

Replaces 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

Cohort / File(s) Summary
New Tool Types
app/modules/intelligence/tools/tool_types.py
Adds PotpieTool (from_function, invoke, _call) and minimal message classes BaseMessage, HumanMessage, AIMessage.
Agents & Memory
app/modules/intelligence/agents/.../pydantic_agent.py, app/modules/intelligence/agents/.../pydantic_multi_agent.py, app/modules/intelligence/agents/.../agent_factory.py, app/modules/intelligence/memory/chat_history_service.py
Rebinds message and tool type imports to local tool_types (messages and PotpieTool aliased as StructuredTool).
Tool Families (many)
app/modules/intelligence/tools/code_query_tools/..., app/modules/intelligence/tools/confluence_tools/..., app/modules/intelligence/tools/jira_tools/..., app/modules/intelligence/tools/kg_based_tools/..., app/modules/intelligence/tools/linear_tools/..., app/modules/intelligence/tools/web_tools/...
Replace from langchain_core.tools import StructuredTool with from app.modules.intelligence.tools.tool_types import PotpieTool as StructuredTool across numerous tool modules; no other logic changes.
Registry & Core Services
app/modules/intelligence/tools/registry/..., app/modules/intelligence/tools/change_detection/change_detection_tool.py, app/modules/intelligence/tools/think_tool.py, app/modules/intelligence/tools/tool_service.py
Tool-type imports and return/type annotations now reference PotpieTool (aliased as StructuredTool).
Manifests
pyproject.toml, requirements.txt
Removed LangChain/related dependencies from pyproject.toml and pruned many LangChain/LangGraph provenance entries in requirements.txt.

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

  • nndn
  • ASCE-D
  • dhirenmathur

Poem

🐇 I hopped through imports in the night,
Swapped giants for a lightfoot sprite,
PotpieTool now wears StructuredTool's name,
Tiny messages hum the same,
A rabbit's cheer — small code, new flame.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title clearly summarizes the main change: replacing langchain_core with a native PotpieTool implementation, with specific reference to the closure of issue #222.
Linked Issues check ✅ Passed The PR accomplishes the primary coding objective of #222 by removing LangChain dependencies and providing local tool/message type replacements, enabling the LiteLLM migration path.
Out of Scope Changes check ✅ Passed All changes are scoped to removing LangChain dependencies and creating local replacements (PotpieTool, message types). No unrelated refactoring or features are introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟡 Minor

Return 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, Any to the imports from typing.

🤖 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 | 🟡 Minor

Schema is missing node_ids field.

The run() and arun() methods accept a node_ids parameter (lines 103, 108), and the tool description (line 155) documents it as an input. However, MultipleKnowledgeGraphQueriesInput doesn't include this field, so node_ids will 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 | 🔴 Critical

Use logger instead of logging.

This line uses logging.info but the module defines logger = setup_logger(__name__) at line 5 and uses logger everywhere else. The logging module is not imported, so this will raise a NameError at 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 | 🟠 Major

Inconsistent Jira client usage pattern — fix resource leak across multiple files.

The JiraClient implements an async context manager with a close() method that properly closes the underlying httpx.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 of async with, which leaves HTTP connections unclosed. Other files like transition_jira_issue_tool.py, update_jira_issue_tool.py, and add_jira_comment_tool.py correctly use async 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 CodeProviderService

Then 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 PotpieTool implementation.

📝 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 bare except: clause.

Bare except clauses catch all exceptions including KeyboardInterrupt and SystemExit, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 71b61bd and 2315bd3.

📒 Files selected for processing (58)
  • app/modules/intelligence/agents/chat_agents/multi_agent/agent_factory.py
  • app/modules/intelligence/agents/chat_agents/pydantic_agent.py
  • app/modules/intelligence/agents/chat_agents/pydantic_multi_agent.py
  • app/modules/intelligence/memory/chat_history_service.py
  • app/modules/intelligence/tools/change_detection/change_detection_tool.py
  • app/modules/intelligence/tools/code_query_tools/apply_changes_tool.py
  • app/modules/intelligence/tools/code_query_tools/bash_command_tool.py
  • app/modules/intelligence/tools/code_query_tools/checkout_worktree_branch_tool.py
  • app/modules/intelligence/tools/code_query_tools/code_analysis.py
  • app/modules/intelligence/tools/code_query_tools/create_pr_workflow_tool.py
  • app/modules/intelligence/tools/code_query_tools/get_code_file_structure.py
  • app/modules/intelligence/tools/code_query_tools/get_code_graph_from_node_id_tool.py
  • app/modules/intelligence/tools/code_query_tools/get_file_content_by_path.py
  • app/modules/intelligence/tools/code_query_tools/get_node_neighbours_from_node_id_tool.py
  • app/modules/intelligence/tools/code_query_tools/git_commit_tool.py
  • app/modules/intelligence/tools/code_query_tools/git_push_tool.py
  • app/modules/intelligence/tools/code_query_tools/intelligent_code_graph_tool.py
  • app/modules/intelligence/tools/confluence_tools/__init__.py
  • app/modules/intelligence/tools/confluence_tools/add_confluence_comment_tool.py
  • app/modules/intelligence/tools/confluence_tools/create_confluence_page_tool.py
  • app/modules/intelligence/tools/confluence_tools/get_confluence_page_tool.py
  • app/modules/intelligence/tools/confluence_tools/get_confluence_space_pages_tool.py
  • app/modules/intelligence/tools/confluence_tools/get_confluence_spaces_tool.py
  • app/modules/intelligence/tools/confluence_tools/search_confluence_pages_tool.py
  • app/modules/intelligence/tools/confluence_tools/update_confluence_page_tool.py
  • app/modules/intelligence/tools/jira_tools/add_jira_comment_tool.py
  • app/modules/intelligence/tools/jira_tools/create_jira_issue_tool.py
  • app/modules/intelligence/tools/jira_tools/get_jira_issue_tool.py
  • app/modules/intelligence/tools/jira_tools/get_jira_project_details_tool.py
  • app/modules/intelligence/tools/jira_tools/get_jira_project_users_tool.py
  • app/modules/intelligence/tools/jira_tools/get_jira_projects_tool.py
  • app/modules/intelligence/tools/jira_tools/link_jira_issues_tool.py
  • app/modules/intelligence/tools/jira_tools/search_jira_issues_tool.py
  • app/modules/intelligence/tools/jira_tools/transition_jira_issue_tool.py
  • app/modules/intelligence/tools/jira_tools/update_jira_issue_tool.py
  • app/modules/intelligence/tools/kg_based_tools/ask_knowledge_graph_queries_tool.py
  • app/modules/intelligence/tools/kg_based_tools/get_code_from_multiple_node_ids_tool.py
  • app/modules/intelligence/tools/kg_based_tools/get_code_from_node_id_tool.py
  • app/modules/intelligence/tools/kg_based_tools/get_code_from_probable_node_name_tool.py
  • app/modules/intelligence/tools/kg_based_tools/get_nodes_from_tags_tool.py
  • app/modules/intelligence/tools/linear_tools/get_linear_issue_tool.py
  • app/modules/intelligence/tools/linear_tools/update_linear_issue_tool.py
  • app/modules/intelligence/tools/registry/annotation_logging.py
  • app/modules/intelligence/tools/registry/discovery_tools.py
  • app/modules/intelligence/tools/registry/resolver.py
  • app/modules/intelligence/tools/think_tool.py
  • app/modules/intelligence/tools/tool_service.py
  • app/modules/intelligence/tools/tool_types.py
  • app/modules/intelligence/tools/web_tools/code_provider_add_pr_comment.py
  • app/modules/intelligence/tools/web_tools/code_provider_create_branch.py
  • app/modules/intelligence/tools/web_tools/code_provider_create_pr.py
  • app/modules/intelligence/tools/web_tools/code_provider_tool.py
  • app/modules/intelligence/tools/web_tools/code_provider_update_file.py
  • app/modules/intelligence/tools/web_tools/github_tool.py
  • app/modules/intelligence/tools/web_tools/web_search_tool.py
  • app/modules/intelligence/tools/web_tools/webpage_extractor_tool.py
  • pyproject.toml
  • requirements.txt
💤 Files with no reviewable changes (1)
  • pyproject.toml

Comment on lines +80 to +84
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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Suggested change
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).

Comment thread app/modules/intelligence/tools/tool_types.py Outdated
brutusworker-arch and others added 3 commits March 18, 2026 07:13
…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>
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
2 Security Hotspots
C Maintainability Rating on New Code (required ≥ A)
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support multiple LLMs through Litellm

1 participant