feat(actor-run): wire ToolCallingRuntime into actor run for skill-based tool calling #11219
@@ -0,0 +1,274 @@
|
||||
@coverage @coverage_actor_run_tool_calling
|
||||
Feature: Actor run tool-calling via ToolCallingRuntime
|
||||
When a skill is attached to `agents actor run` via `--skill`, the actor
|
||||
should perform real LLM tool calls through ToolCallingRuntime.
|
||||
|
||||
Background:
|
||||
Given a minimal ToolCallingAgent fixture
|
||||
|
||||
# ---------- A: single tool call succeeds ----------
|
||||
|
||||
Scenario: Tool call succeeds — mock LLM returns read_file call
|
||||
Given a mock LLM caller that makes one read_file tool call
|
||||
When ToolCallingAgent.process is called with prompt "Review src/auth.py"
|
||||
Then the tool_calls count is 1
|
||||
And the final response is non-empty
|
||||
|
||||
# ---------- B: multi-turn tool loop ----------
|
||||
|
||||
Scenario: Multi-turn tool loop — mock LLM makes two consecutive tool calls
|
||||
Given a mock LLM caller that makes 2 consecutive tool calls before finishing
|
||||
When ToolCallingAgent.process is called with prompt "Analyse two files"
|
||||
Then the tool_calls count is 2
|
||||
And the loop ran for at least 3 iterations
|
||||
|
||||
# ---------- C: no-skill plain LLM regression ----------
|
||||
|
||||
Scenario: No-skill plain LLM — SimpleLLMAgent used, no tool schemas sent
|
||||
Given a SimpleLLMAgent with a mock LLM
|
||||
When SimpleLLMAgent.process is called with a simple prompt
|
||||
Then SimpleLLMAgent returns the mocked response
|
||||
And no tool schemas were sent to the LLM
|
||||
|
||||
# ---------- D: skill tools not silently dropped ----------
|
||||
|
||||
Scenario: Skill tools not silently dropped when actor has no base tools list
|
||||
Given an actor config with no base tools list
|
||||
And resolved skill tool entries for the actor
|
||||
When _make_agent_instance is called for that actor
|
||||
Then the result is a ToolCallingAgent instance
|
||||
|
||||
# ---------- E: ToolCallingLLMCaller first-call system prompt ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller sends system prompt on first call
|
||||
Given a ToolCallingLLMCaller with an actor config containing a system_prompt
|
||||
When invoke is called for the first time with a user prompt
|
||||
Then the accumulated messages include a SystemMessage
|
||||
And the accumulated messages include a HumanMessage
|
||||
|
||||
# ---------- F: ToolCallingLLMCaller subsequent call appends tool results ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller appends tool results on subsequent call
|
||||
Given a ToolCallingLLMCaller with an actor config containing a system_prompt
|
||||
And a prior first invoke has been made
|
||||
When invoke is called again with tool_results
|
||||
Then a ToolMessage is appended to the accumulated messages
|
||||
|
||||
# ---------- G: GraphExecutor passes context to ToolCallingAgent ----------
|
||||
|
||||
Scenario: GraphExecutor._invoke_agent passes context dict to ToolCallingAgent
|
||||
Given a ToolCallingAgent spy that captures its process() arguments
|
||||
When GraphExecutor._invoke_agent is called with that agent and a context dict
|
||||
Then the context dict was forwarded to ToolCallingAgent.process
|
||||
|
||||
# ---------- H: last_run_tool_calls property reflects run results ----------
|
||||
|
||||
Scenario: ReactiveCleverAgentsApp.last_run_tool_calls reflects tool calls
|
||||
Given a ReactiveCleverAgentsApp with a registered ToolCallingAgent that has last_result
|
||||
When _tally_tool_calls is called on the app
|
||||
Then last_run_tool_calls equals the number of tool call history entries
|
||||
|
||||
# ---------- I: ToolCallingLLMCaller _render_prompt ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller._render_prompt handles empty template
|
||||
Given a fresh ToolCallingLLMCaller
|
||||
When _render_prompt is called with an empty string template
|
||||
Then _render_prompt returns an empty string
|
||||
|
||||
Scenario: ToolCallingLLMCaller._render_prompt renders Jinja2 template
|
||||
Given a fresh ToolCallingLLMCaller
|
||||
When _render_prompt is called with a Jinja2 template and context
|
||||
Then _render_prompt returns the rendered string
|
||||
|
||||
Scenario: ToolCallingLLMCaller._render_prompt handles rendering exception
|
||||
Given a fresh ToolCallingLLMCaller
|
||||
When _render_prompt is called with a template that raises during rendering
|
||||
Then _render_prompt returns the original template
|
||||
|
||||
# ---------- J: ToolCallingLLMCaller _resolve_llm with kwargs ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller._resolve_llm passes temperature max_tokens max_retries to provider
|
||||
Given a ToolCallingLLMCaller with temperature max_tokens max_retries in actor_config
|
||||
When _resolve_llm is called with tool_schemas
|
||||
Then the provider registry create_llm was called with the config kwargs
|
||||
|
||||
Scenario: ToolCallingLLMCaller._resolve_llm skips bind_tools when no schemas
|
||||
Given a ToolCallingLLMCaller with temperature max_tokens max_retries in actor_config
|
||||
When _resolve_llm is called without tool_schemas
|
||||
Then bind_tools was not called on the LLM
|
||||
|
||||
Scenario: ToolCallingLLMCaller._resolve_llm falls back when bind_tools raises
|
||||
Given a ToolCallingLLMCaller with a provider that raises on bind_tools
|
||||
When _resolve_llm is called with tool_schemas for a failing bind
|
||||
Then the plain LLM is used without tool binding
|
||||
|
||||
# ---------- K: ToolCallingLLMCaller invoke no system prompt ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller.invoke without system prompt only adds HumanMessage
|
||||
Given a ToolCallingLLMCaller with an actor config without system_prompt
|
||||
When invoke is called for the first time with a user prompt
|
||||
Then the accumulated messages include a HumanMessage
|
||||
And no SystemMessage was added
|
||||
|
||||
# ---------- L: ToolCallingLLMCaller invoke list content ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller.invoke handles list content in response
|
||||
Given a ToolCallingLLMCaller with an actor config without system_prompt
|
||||
When invoke is called and the LLM returns list content
|
||||
Then the response content joins the list parts
|
||||
|
||||
# ---------- M: ToolCallingLLMCaller invoke failed tool result ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller.invoke uses error field on failed tool result
|
||||
Given a ToolCallingLLMCaller with an actor config containing a system_prompt
|
||||
And a prior first invoke has been made
|
||||
When invoke is called with a failed tool_result
|
||||
Then a ToolMessage with the error text is appended
|
||||
|
||||
# ---------- N: ToolCallingAgent._build_tool_registry edge cases ----------
|
||||
|
||||
Scenario: ToolCallingAgent._build_tool_registry skips empty tool name
|
||||
Given a ToolCallingAgent with an entry that has an empty name
|
||||
When _build_tool_registry is called
|
||||
Then the local registry is empty
|
||||
|
||||
Scenario: ToolCallingAgent._build_tool_registry skips duplicate names
|
||||
Given a ToolCallingAgent with two entries for the same builtin tool
|
||||
When _build_tool_registry is called
|
||||
Then the local registry has exactly one tool registered
|
||||
|
||||
Scenario: ToolCallingAgent._build_tool_registry warns when tool not in builtin registry
|
||||
Given a ToolCallingAgent with an entry not found in builtin registry
|
||||
When _build_tool_registry is called
|
||||
Then the local registry is empty
|
||||
|
||||
# ---------- O: ToolCallingAgent.process_message_sync ----------
|
||||
|
||||
Scenario: ToolCallingAgent.process_message_sync delegates to process
|
||||
Given a ToolCallingAgent with no tools and a mock process method
|
||||
When process_message_sync is called
|
||||
Then the result is the same as calling process directly
|
||||
|
||||
# ---------- P: ToolCallingLLMCaller.invoke returns tool calls from response ----------
|
||||
|
||||
Scenario: ToolCallingLLMCaller.invoke extracts tool calls from LLM response
|
||||
Given a ToolCallingLLMCaller with an actor config without system_prompt
|
||||
When invoke is called and the LLM returns a response with tool call dicts
|
||||
Then the LLMResponse contains the extracted tool calls
|
||||
|
||||
# ---------- Q: _resolve_provider_format maps provider to correct format ----------
|
||||
|
||||
Scenario: _resolve_provider_format returns ANTHROPIC for anthropic provider
|
||||
Given an actor config with provider "anthropic"
|
||||
When _resolve_provider_format is called with that actor config
|
||||
Then _resolve_provider_format returns ProviderFormat.ANTHROPIC
|
||||
|
||||
Scenario: _resolve_provider_format returns OPENAI for openai provider
|
||||
Given an actor config with provider "openai"
|
||||
When _resolve_provider_format is called with that actor config
|
||||
Then _resolve_provider_format returns ProviderFormat.OPENAI
|
||||
|
||||
Scenario: _resolve_provider_format returns OPENAI for unknown provider
|
||||
Given an actor config with provider "google"
|
||||
When _resolve_provider_format is called with that actor config
|
||||
Then _resolve_provider_format returns ProviderFormat.OPENAI
|
||||
|
||||
Scenario: _resolve_provider_format returns OPENAI for empty actor config
|
||||
Given an empty actor config
|
||||
When _resolve_provider_format is called with that actor config
|
||||
Then _resolve_provider_format returns ProviderFormat.OPENAI
|
||||
|
||||
Scenario: _resolve_provider_format returns OPENAI for None actor config
|
||||
When _resolve_provider_format is called with actor_config None
|
||||
Then _resolve_provider_format returns ProviderFormat.OPENAI
|
||||
|
||||
# ---------- R: ToolCallingAgent.process passes provider_format to runtime ----------
|
||||
|
||||
Scenario: ToolCallingAgent.process passes provider_format to ToolCallingRuntime
|
||||
Given a ToolCallingAgent with an anthropic actor config and a file-read tool entry
|
||||
When ToolCallingAgent.process is called with prompt "Read my file"
|
||||
Then ToolCallingRuntime was constructed with ProviderFormat.ANTHROPIC
|
||||
|
||||
# ---------- S: Tool name encoding/decoding ----------
|
||||
|
||||
Scenario: _encode_tool_name replaces colon and slash with uppercase sentinels
|
||||
When _encode_tool_name is called with "server:namespace/tool"
|
||||
Then _encode_tool_name returns "server_C_namespace_S_tool"
|
||||
|
||||
Scenario: _encode_tool_name is idempotent on already-clean names
|
||||
When _encode_tool_name is called with "my-clean_tool"
|
||||
Then _encode_tool_name returns "my-clean_tool"
|
||||
|
||||
Scenario: _decode_tool_name restores colon and slash from sentinels
|
||||
When _decode_tool_name is called with "server_C_namespace_S_tool"
|
||||
Then _decode_tool_name returns "server:namespace/tool"
|
||||
|
||||
Scenario: _decode_tool_name is idempotent on clean names
|
||||
When _decode_tool_name is called with "my-clean_tool"
|
||||
Then _decode_tool_name returns "my-clean_tool"
|
||||
|
||||
Scenario: encode-decode round-trip preserves original name
|
||||
Given a tool name "local/my__tool"
|
||||
When the tool name is encoded then decoded
|
||||
Then the round-trip name equals "local/my__tool"
|
||||
|
||||
Scenario: encode-decode round-trip for server-qualified name
|
||||
Given a tool name "server.example:builtin/git-status"
|
||||
When the tool name is encoded then decoded
|
||||
Then the round-trip name equals "server.example:builtin/git-status"
|
||||
|
||||
# ---------- T: _resolve_llm encodes tool names in schemas ----------
|
||||
|
||||
Scenario: _resolve_llm encodes tool names before calling bind_tools
|
||||
Given a ToolCallingLLMCaller with default actor config
|
||||
When _resolve_llm is called with a schema containing a namespaced tool name
|
||||
Then bind_tools was called with the encoded tool name
|
||||
|
||||
# ---------- U: invoke decodes tool names from LLM response ----------
|
||||
|
||||
Scenario: invoke decodes tool names when extracting tool calls from LLM response
|
||||
Given a ToolCallingLLMCaller with an actor config without system_prompt
|
||||
|
|
||||
When invoke is called and the LLM returns a response with encoded tool call names
|
||||
Then the LLMResponse contains the decoded tool calls
|
||||
|
||||
# ---------- S: Tool name encoding/decoding ----------
|
||||
|
||||
Scenario: _encode_tool_name replaces colon and slash with uppercase sentinels
|
||||
When _encode_tool_name is called with "server:namespace/tool"
|
||||
Then _encode_tool_name returns "server_C_namespace_S_tool"
|
||||
|
||||
Scenario: _encode_tool_name is idempotent on already-clean names
|
||||
When _encode_tool_name is called with "my-clean_tool"
|
||||
Then _encode_tool_name returns "my-clean_tool"
|
||||
|
||||
Scenario: _decode_tool_name restores colon and slash from sentinels
|
||||
When _decode_tool_name is called with "server_C_namespace_S_tool"
|
||||
Then _decode_tool_name returns "server:namespace/tool"
|
||||
|
||||
Scenario: _decode_tool_name is idempotent on clean names
|
||||
When _decode_tool_name is called with "my-clean_tool"
|
||||
Then _decode_tool_name returns "my-clean_tool"
|
||||
|
||||
Scenario: encode-decode round-trip preserves original name
|
||||
Given a tool name "local/my__tool"
|
||||
When the tool name is encoded then decoded
|
||||
Then the round-trip name equals "local/my__tool"
|
||||
|
||||
Scenario: encode-decode round-trip for server-qualified name
|
||||
Given a tool name "server.example:builtin/git-status"
|
||||
When the tool name is encoded then decoded
|
||||
Then the round-trip name equals "server.example:builtin/git-status"
|
||||
|
||||
# ---------- T: _resolve_llm encodes tool names in schemas ----------
|
||||
|
||||
Scenario: _resolve_llm encodes tool names before calling bind_tools
|
||||
Given a ToolCallingLLMCaller with default actor config
|
||||
When _resolve_llm is called with a schema containing a namespaced tool name
|
||||
Then bind_tools was called with the encoded tool name
|
||||
|
||||
# ---------- U: invoke decodes tool names from LLM response ----------
|
||||
|
||||
Scenario: invoke decodes tool names when extracting tool calls from LLM response
|
||||
Given a ToolCallingLLMCaller with an actor config without system_prompt
|
||||
When invoke is called and the LLM returns a response with encoded tool call names
|
||||
Then the LLMResponse contains the decoded tool calls
|
||||
@@ -188,4 +188,4 @@ Feature: Automation Profile CLI commands
|
||||
# Legacy flag removal tests
|
||||
Scenario: Legacy --automation-level flag is rejected on plan use
|
||||
When I invoke plan use with --automation-level "manual"
|
||||
Then the plan output should contain "No such option: --automation-level"
|
||||
Then the plan output should contain "No such option"
|
||||
|
||||
@@ -87,10 +87,10 @@ Feature: Reactive application coverage boost
|
||||
Then a CleverAgentsException should be raised for resolution failure
|
||||
|
||||
@coverage
|
||||
Scenario: Reactive app skill injection skips LLM agents without tools
|
||||
Scenario: Reactive app skill injection upgrades LLM agents to ToolCallingAgent
|
||||
Given a reactive app with skill tools and a config with an LLM agent
|
||||
When agents are registered from config with skill tools present
|
||||
Then the LLM agent should remain a SimpleLLMAgent not a SimpleToolAgent
|
||||
Then the LLM agent should be a ToolCallingAgent not a SimpleLLMAgent
|
||||
|
||||
@coverage
|
||||
Scenario: Reactive app raises error for skill resolution ValueError
|
||||
|
||||
@@ -33,6 +33,8 @@ def _make_app(
|
||||
app_exec = MagicMock()
|
||||
app_exec.config = SimpleNamespace(global_context=dict(config_global_context or {}))
|
||||
app_exec.run_single_shot = AsyncMock(return_value=result)
|
||||
# last_run_tool_calls is an int property; set to 0 so comparisons work in tests
|
||||
app_exec.last_run_tool_calls = 0
|
||||
if run_side_effect is not None:
|
||||
app_exec.run_single_shot.side_effect = run_side_effect
|
||||
return app_exec
|
||||
|
||||
@@ -41,6 +41,8 @@ def _make_app(
|
||||
app_exec = MagicMock()
|
||||
app_exec.config = SimpleNamespace(global_context=dict(config_global_context or {}))
|
||||
app_exec.run_single_shot = AsyncMock(return_value=result)
|
||||
# last_run_tool_calls is an int property; set to 0 so comparisons work in tests
|
||||
app_exec.last_run_tool_calls = 0
|
||||
return app_exec
|
||||
|
||||
|
||||
|
||||
@@ -668,14 +668,15 @@ def step_register_agents_with_skill_tools_and_llm(context: Context) -> None:
|
||||
context.app._register_agents_from_config() # pylint: disable=protected-access
|
||||
|
||||
|
||||
@then("the LLM agent should remain a SimpleLLMAgent not a SimpleToolAgent")
|
||||
def step_llm_agent_not_converted(context: Context) -> None:
|
||||
from cleveragents.reactive.stream_router import SimpleLLMAgent, SimpleToolAgent
|
||||
@then("the LLM agent should be a ToolCallingAgent not a SimpleLLMAgent")
|
||||
def step_llm_agent_upgraded_to_tool_calling(context: Context) -> None:
|
||||
from cleveragents.reactive.stream_router import SimpleToolAgent
|
||||
from cleveragents.reactive.tool_agent import ToolCallingAgent
|
||||
|
||||
llm_agent = context.app.stream_router.agents.get("llm_actor")
|
||||
assert llm_agent is not None, "Expected llm_actor to be registered"
|
||||
assert isinstance(llm_agent, SimpleLLMAgent), (
|
||||
f"Expected SimpleLLMAgent but got {type(llm_agent).__name__}"
|
||||
assert isinstance(llm_agent, ToolCallingAgent), (
|
||||
f"Expected ToolCallingAgent but got {type(llm_agent).__name__}"
|
||||
)
|
||||
|
||||
tool_agent = context.app.stream_router.agents.get("tool_actor")
|
||||
|
||||
@@ -48,6 +48,8 @@ def _make_app(*, result: str) -> MagicMock:
|
||||
app_exec = MagicMock()
|
||||
app_exec.config = SimpleNamespace(global_context={})
|
||||
app_exec.run_single_shot = AsyncMock(return_value=result)
|
||||
# last_run_tool_calls is an int property; set to 0 so comparisons work in tests
|
||||
app_exec.last_run_tool_calls = 0
|
||||
return app_exec
|
||||
|
||||
|
||||
|
||||
@@ -168,6 +168,11 @@ def run(
|
||||
typer.echo(f"Unexpected error: {exc}", err=True)
|
||||
raise typer.Exit(code=3) from exc
|
||||
|
||||
# ST-6: Surface tool_calls count from the most recent run
|
||||
tool_calls_count = app_exec.last_run_tool_calls
|
||||
if tool_calls_count > 0:
|
||||
typer.echo(f"Tool Calls: {tool_calls_count}")
|
||||
|
||||
if output:
|
||||
output.write_text(result)
|
||||
typer.echo(f"Output written to {output}")
|
||||
|
||||
@@ -23,6 +23,13 @@ from cleveragents.reactive.stream_router import (
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
SimpleLLMAgent,
|
||||
SimpleToolAgent,
|
||||
)
|
||||
from cleveragents.reactive.tool_agent import ToolCallingAgent
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
from cleveragents.tool.builtins import (
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
register_file_tools,
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
register_git_tools,
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
register_subplan_tool,
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
from cleveragents.tool.registry import ToolRegistry
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
# Skill name format: namespace/short-name, ASCII alphanumeric + ._- only.
|
||||
_SKILL_NAME_RE = re.compile(r"^[\w.-]{1,127}/[\w.-]{1,127}$", re.ASCII)
|
||||
@@ -49,6 +56,7 @@ class ReactiveCleverAgentsApp:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
dict.fromkeys(self._sanitize_skill_name(n) for n in (skill_names or []))
|
||||
)
|
||||
self._resolved_skill_tools: list[dict[str, Any]] = []
|
||||
self._last_run_tool_calls: int = 0
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
self._configure_logging(verbose)
|
||||
self.stream_router = ReactiveStreamRouter()
|
||||
@@ -57,6 +65,14 @@ class ReactiveCleverAgentsApp:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
self.route_bridge = None
|
||||
self.config: ReactiveConfig | None = None
|
||||
|
||||
# ST-4: Shared built-in ToolRegistry populated once at startup.
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# ToolCallingAgent instances look up tool names here to build their
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# per-run local registry.
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
self._builtin_registry = ToolRegistry()
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
register_file_tools(self._builtin_registry)
|
||||
|
HAL9001
commented
Suggestion: The builtin registry initialization ( Automated by CleverAgents Bot Suggestion: The builtin registry initialization (`register_file_tools`, `register_git_tools`, `register_subplan_tool`) runs every time `__init__` is called. If the `ReactiveCleverAgentsApp` class were ever instantiated more than once per process, these tools would be re-registered. Consider adding a guard or using `_builtin_registry.register()` (which appears to handle deduplication internally based on tool name). This is unlikely to be an issue in production but worth noting.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
register_git_tools(self._builtin_registry)
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
register_subplan_tool(self._builtin_registry)
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
if self._skill_names:
|
||||
self._resolve_skills()
|
||||
|
||||
@@ -81,6 +97,11 @@ class ReactiveCleverAgentsApp:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
"""Return the resolved skill tool configurations."""
|
||||
return list(self._resolved_skill_tools)
|
||||
|
||||
@property
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
def last_run_tool_calls(self) -> int:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
"""Return the number of tool calls made during the most recent run."""
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
return self._last_run_tool_calls
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
@staticmethod
|
||||
def _sanitize_skill_name(name: str) -> str:
|
||||
"""Validate format and strip control characters from a skill name.
|
||||
@@ -178,13 +199,19 @@ class ReactiveCleverAgentsApp:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
def _make_agent_instance(name: str, agent_cfg: Any) -> Any:
|
||||
tools = agent_cfg.config.get("tools", []) if agent_cfg.config else []
|
||||
if self._resolved_skill_tools and tools:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# ST-1: Always merge skill tools regardless of whether the actor
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# has a base tools list. The old elif branch silently dropped skill
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# tools when the actor config had no base tools — that was a bug.
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
if self._resolved_skill_tools:
|
||||
|
HAL9001
commented
Suggestion: The
This is cosmetic — the current structure is functionally correct and works fine. Automated by CleverAgents Bot Suggestion: The `_make_agent_instance()` inner function currently contains two separate `if` branches (one for skill-tools merge, one for agent routing) that could be collapsed for readability. Consider merging into a single block:
if self._resolved_skill_tools:
tools = list(tools) + self._resolved_skill_tools
# Routing: ...same comment as-is...
This is cosmetic — the current structure is functionally correct and works fine.
---
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
tools = list(tools) + self._resolved_skill_tools
|
||||
elif self._resolved_skill_tools and not tools:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
logger.debug(
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
"Skipping skill tool injection for agent '%s' "
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
"(agent has no base tools)",
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
name,
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# Routing:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# tools + llm type → ToolCallingAgent (real LLM tool calling)
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# tools + non-llm → SimpleToolAgent (string transforms)
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# no tools + llm → SimpleLLMAgent (plain LLM, no regression)
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# no tools + other → identity lambda
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
if tools and agent_cfg.type == "llm":
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
return ToolCallingAgent(
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
name, agent_cfg.config, tools, self._builtin_registry
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
)
|
||||
if tools:
|
||||
return SimpleToolAgent(tools, unsafe=self.unsafe)
|
||||
@@ -295,6 +322,18 @@ class ReactiveCleverAgentsApp:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
].on_next(msg)
|
||||
)
|
||||
|
||||
def _tally_tool_calls(self) -> None:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
"""Accumulate tool_calls count from all ToolCallingAgent instances.
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
Called at the end of every ``run_single_shot()`` execution to update
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
``_last_run_tool_calls`` so the CLI can surface the count.
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
total = 0
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
for agent in self.stream_router.agents.values():
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
if isinstance(agent, ToolCallingAgent) and agent.last_result is not None:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
total += len(agent.last_result.tool_call_history)
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
self._last_run_tool_calls = total
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
def _is_rxpy_stream_present(self) -> bool:
|
||||
if not self.config:
|
||||
return False
|
||||
@@ -384,11 +423,15 @@ class ReactiveCleverAgentsApp:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
if context_manager and self.config and context_manager.global_context:
|
||||
self.config.global_context.update(context_manager.global_context)
|
||||
|
||||
# Reset tool-call counter at the start of each run
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
self._last_run_tool_calls = 0
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
# Try graph route execution first
|
||||
graph_route = self._get_graph_route()
|
||||
if graph_route is not None:
|
||||
executor = GraphExecutor(self.stream_router.agents, self.config)
|
||||
output = executor.execute(prompt, graph_route)
|
||||
self._tally_tool_calls()
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
return GraphExecutor.strip_routing_prefixes(output)
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
@@ -414,9 +457,11 @@ class ReactiveCleverAgentsApp:
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
raise CleverAgentsException("; ".join(error_container))
|
||||
|
||||
if not result_container:
|
||||
self._tally_tool_calls()
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
return ""
|
||||
|
||||
output = "\n".join(result_container)
|
||||
self._tally_tool_calls()
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
return GraphExecutor.strip_routing_prefixes_multiline(output)
|
||||
|
||||
async def run_with_context(
|
||||
|
||||
|
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
HAL9001
commented
Suggestion: The line Suggestion: The line `self._last_run_tool_calls = 0` immediately before the try/except in `run_single_shot()` appears redundant or dead — if execution reaches that point, it means no exception was raised. This is harmless dead code but may confuse future readers about whether this assignment applies to a post-exception path (which it does not, since errors raise). Could be cleaned up by removing it or repositioning within the error block for clarity.
|
||||
@@ -17,6 +17,7 @@ from typing import Any
|
||||
from cleveragents.reactive.config_parser import ReactiveConfig
|
||||
from cleveragents.reactive.route import RouteConfig
|
||||
from cleveragents.reactive.stream_router import SimpleLLMAgent, SimpleToolAgent
|
||||
from cleveragents.reactive.tool_agent import ToolCallingAgent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -138,7 +139,10 @@ class GraphExecutor:
|
||||
@staticmethod
|
||||
def _invoke_agent(agent: Any, message: str, context: dict[str, Any]) -> str:
|
||||
"""Execute an agent and return the string result."""
|
||||
if isinstance(agent, (SimpleToolAgent | SimpleLLMAgent)):
|
||||
# ST-5: ToolCallingAgent also accepts context for Jinja2 rendering;
|
||||
# include it in the isinstance check alongside SimpleToolAgent and
|
||||
# SimpleLLMAgent so the global context dict is passed through.
|
||||
if isinstance(agent, (SimpleToolAgent, SimpleLLMAgent, ToolCallingAgent)):
|
||||
result = agent.process(message, context=context)
|
||||
elif hasattr(agent, "process"):
|
||||
result = agent.process(message)
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
"""ToolCallingAgent — actor run agent with LLM tool-calling support.
|
||||
|
||||
Implements a reactive agent that drives ``ToolCallingRuntime`` for the
|
||||
``actor run`` path. When a skill is attached via ``--skill``, this agent
|
||||
is used instead of ``SimpleLLMAgent`` so that the LLM can actually invoke
|
||||
tools during its response loop.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from cleveragents.tool.actor_runtime import ToolCallingRuntime, ToolCallRunResult
|
||||
from cleveragents.tool.registry import ToolRegistry
|
||||
from cleveragents.tool.router import ProviderFormat
|
||||
from cleveragents.tool.runner import ToolRunner
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ToolCallingAgent:
|
||||
"""LLM-backed agent that supports real tool calling via ToolCallingRuntime.
|
||||
|
||||
Unlike ``SimpleLLMAgent`` (which calls ``llm.invoke()`` with no tool
|
||||
schemas) this agent:
|
||||
|
||||
1. Builds a per-run ``ToolRegistry`` from the resolved skill tool entries
|
||||
by looking them up in a shared *builtin_registry*.
|
||||
2. Creates a ``ToolRunner`` and a ``ToolCallingLLMCaller`` for that run.
|
||||
3. Delegates to ``ToolCallingRuntime.run_tool_loop()`` which handles the
|
||||
bind-tools / invoke / execute / feed-back loop.
|
||||
4. Exposes ``last_result`` so the CLI can surface the ``tool_calls`` count.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name:
|
||||
Actor name (used for logging).
|
||||
actor_config:
|
||||
Raw actor configuration dict from the YAML file (provider, model,
|
||||
system_prompt, temperature, etc.).
|
||||
resolved_tool_entries:
|
||||
List of resolved tool entry dicts from ``_resolve_skills()``/
|
||||
``_make_agent_instance()``. Each entry has at least a ``"name"``
|
||||
key with the namespaced tool name.
|
||||
builtin_registry:
|
||||
Shared ``ToolRegistry`` pre-populated with built-in tools
|
||||
(file, git, subplan). Each entry's name is looked up here to
|
||||
obtain the real ``ToolSpec``.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
actor_config: dict[str, Any] | None,
|
||||
resolved_tool_entries: list[dict[str, Any]],
|
||||
builtin_registry: ToolRegistry,
|
||||
) -> None:
|
||||
self._name = name
|
||||
self._actor_config: dict[str, Any] = dict(actor_config or {})
|
||||
self._resolved_tool_entries = resolved_tool_entries
|
||||
self._builtin_registry = builtin_registry
|
||||
self.last_result: ToolCallRunResult | None = None
|
||||
|
||||
# -- Internal helpers -----------------------------------------------------
|
||||
|
||||
def _build_tool_registry(self) -> ToolRegistry:
|
||||
"""Build a fresh per-run ``ToolRegistry`` from resolved entries.
|
||||
|
||||
Each entry's ``"name"`` is looked up in the shared
|
||||
``_builtin_registry``. Entries whose name is not found (e.g. inline
|
||||
or MCP tools not yet in the builtin registry) are warned and skipped
|
||||
so the run degrades gracefully rather than crashing.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ToolRegistry
|
||||
A new registry containing only the successfully resolved tools.
|
||||
"""
|
||||
local_registry = ToolRegistry()
|
||||
seen: set[str] = set()
|
||||
|
||||
for entry in self._resolved_tool_entries:
|
||||
tool_name: str = entry.get("name", "") if isinstance(entry, dict) else ""
|
||||
if not tool_name:
|
||||
continue
|
||||
if tool_name in seen:
|
||||
# Deduplicate: the same builtin may appear more than once when
|
||||
# multiple skills reference it.
|
||||
continue
|
||||
spec = self._builtin_registry.get(tool_name)
|
||||
if spec is None:
|
||||
logger.warning(
|
||||
"ToolCallingAgent '%s': tool '%s' not found in builtin "
|
||||
"registry — skipping (inline/MCP tools not yet supported "
|
||||
"in actor run tool-calling path)",
|
||||
self._name,
|
||||
tool_name,
|
||||
)
|
||||
continue
|
||||
try:
|
||||
local_registry.register(spec)
|
||||
seen.add(tool_name)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
logger.debug(
|
||||
"ToolCallingAgent '%s': skipping '%s' (%s)",
|
||||
self._name,
|
||||
tool_name,
|
||||
exc,
|
||||
)
|
||||
|
||||
return local_registry
|
||||
|
||||
# -- Agent interface ------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _resolve_provider_format(actor_config: dict[str, Any] | None) -> ProviderFormat:
|
||||
"""Map an actor config's ``provider`` field to the correct ``ProviderFormat``.
|
||||
|
||||
The format determines the schema key emitted by
|
||||
``normalize_tool_schema_for_provider``, which must survive
|
||||
LangChain's ``convert_to_openai_function()`` call inside
|
||||
``bind_tools()``:
|
||||
|
||||
- ``ProviderFormat.LANGCHAIN`` emits ``args_schema`` → **silently
|
||||
dropped** by ``convert_to_openai_function()`` → ``bind_tools``
|
||||
raises ``'parameters'``.
|
||||
- ``ProviderFormat.ANTHROPIC`` emits ``input_schema`` → preserved
|
||||
and mapped to ``parameters``.
|
||||
- ``ProviderFormat.OPENAI`` emits ``parameters`` → preserved
|
||||
directly.
|
||||
|
||||
Therefore ``ProviderFormat.LANGCHAIN`` must never be used in the
|
||||
``ToolCallingRuntime`` → ``bind_tools()`` pipeline. The default
|
||||
for unrecognised providers is ``ProviderFormat.OPENAI`` since
|
||||
most providers accept OpenAI-compatible tool schemas.
|
||||
"""
|
||||
if not actor_config:
|
||||
return ProviderFormat.OPENAI
|
||||
provider: str = (actor_config.get("provider") or "").lower()
|
||||
if provider == "anthropic":
|
||||
return ProviderFormat.ANTHROPIC
|
||||
# openai, google, groq, azure, openrouter, gemini, cohere,
|
||||
# together, mock, and any unknown provider default to OpenAI
|
||||
# format since all of these consume OpenAI-compatible tool
|
||||
# schemas through LangChain's bind_tools().
|
||||
return ProviderFormat.OPENAI
|
||||
|
||||
def process(
|
||||
self,
|
||||
content: Any,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
context: dict[str, Any] | None = None,
|
||||
) -> Any:
|
||||
"""Execute the tool-calling loop and return the final text response.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
content:
|
||||
The user prompt (string or coercible to string).
|
||||
metadata:
|
||||
Optional stream metadata (currently unused).
|
||||
context:
|
||||
Optional Jinja2 rendering context (currently unused).
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
The final text response from the LLM after all tool calls.
|
||||
"""
|
||||
# Lazy import to avoid circular imports at module load time
|
||||
from cleveragents.reactive.tool_caller import ToolCallingLLMCaller
|
||||
|
||||
prompt = content if isinstance(content, str) else str(content or "")
|
||||
local_registry = self._build_tool_registry()
|
||||
runner = ToolRunner(local_registry)
|
||||
caller = ToolCallingLLMCaller(self._actor_config)
|
||||
runtime = ToolCallingRuntime(
|
||||
registry=local_registry,
|
||||
runner=runner,
|
||||
llm_caller=caller,
|
||||
provider_format=self._resolve_provider_format(self._actor_config),
|
||||
)
|
||||
result = runtime.run_tool_loop(prompt, actor_config=self._actor_config)
|
||||
self.last_result = result
|
||||
return result.content
|
||||
|
||||
def process_message_sync(
|
||||
self, content: Any, metadata: dict[str, Any] | None = None
|
||||
) -> Any:
|
||||
"""Synchronous variant for stream-router compatibility."""
|
||||
return self.process(content, metadata)
|
||||
@@ -0,0 +1,275 @@
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""ToolCallingLLMCaller — LLMCaller implementation for actor run tool calling.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Wraps a LangChain chat model with tool schema binding and multi-turn tool
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
result threading for use with ``ToolCallingRuntime`` in the reactive actor
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
run path.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
This caller is stateful within a single ``run_tool_loop()`` invocation: it
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
accumulates the LangChain message thread across tool-call loop iterations.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Create a fresh instance for each ``process()`` call in ``ToolCallingAgent``.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from __future__ import annotations
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
import logging
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from typing import Any
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from cleveragents.application.services.prompt_sanitizer import PromptSanitizer
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from cleveragents.tool.actor_runtime import LLMResponse, LLMToolCall
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
try:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from langchain_core.messages.tool import ToolMessage
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
except Exception: # pragma: no cover - optional runtime dependency guard
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
AIMessage = None # type: ignore[assignment, misc]
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
HumanMessage = None # type: ignore[assignment, misc]
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
SystemMessage = None # type: ignore[assignment, misc]
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
ToolMessage = None # type: ignore[assignment, misc]
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
try:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
except Exception: # pragma: no cover - optional runtime dependency guard
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
SandboxedEnvironment = None # type: ignore[assignment, misc]
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
from cleveragents.providers.registry import get_provider_registry
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
logger = logging.getLogger(__name__)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
_SANITIZER = PromptSanitizer()
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
def _encode_tool_name(name: str) -> str:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""Encode forbidden characters for Anthropic tool name pattern.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
The Anthropic API requires tool names to match ``^[a-zA-Z0-9_-]{1,128}$``.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
CleverAgents tool names use ``:`` (server prefix) and ``/`` (namespace
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
separator), neither of which is in the allowed character set.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Because valid CleverAgents tool names (per the internal name regex) may
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
only contain lowercase letters, digits, ``-``, ``_``, ``:``, and ``/``,
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
any **uppercase** letter is guaranteed to be unambiguous as an escape
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
marker. This function replaces:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
* ``:`` → ``_C_`` (C for Colon)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
* ``/`` → ``_S_`` (S for Slash)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
These sentinels cannot collide with legitimate tool names because
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
uppercase letters are forbidden in the internal name regex.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return name.replace(":", "_C_").replace("/", "_S_")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
def _decode_tool_name(name: str) -> str:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""Reverse :func:`_encode_tool_name`.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Restores ``_S_`` → ``/`` and ``_C_`` → ``:``.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return name.replace("_S_", "/").replace("_C_", ":")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
class ToolCallingLLMCaller:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""LLMCaller implementation for actor run tool-calling loop.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Implements the :class:`~cleveragents.tool.actor_runtime.LLMCaller`
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
protocol. On the first ``invoke()`` call it binds tool schemas to the
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
LLM via ``bind_tools()`` and sends the initial system + user messages.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
On subsequent calls (when ``tool_results`` is provided) it appends the
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
previous AI response and ``ToolMessage`` objects for each result, then
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
invokes again to continue the tool-call conversation.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Parameters
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
----------
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
actor_config:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Actor configuration dict (provider, model, temperature, etc.).
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
When not provided an empty dict is used, which falls through to
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
``get_provider_registry().create_llm()`` defaults.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
def __init__(self, actor_config: dict[str, Any] | None = None) -> None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._actor_config: dict[str, Any] = dict(actor_config or {})
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._llm: Any = None
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._accumulated: list[Any] = []
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._first_call: bool = True
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._last_response: Any = None
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._template_env = (
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
SandboxedEnvironment() if SandboxedEnvironment is not None else None
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# -- Internal helpers -----------------------------------------------------
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
def _render_prompt(self, template: str, context: dict[str, Any]) -> str:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""Render a Jinja2 template string against *context*.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Falls back to returning the raw template if Jinja2 is unavailable or
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
rendering fails.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if not template:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return ""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if self._template_env is None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return template
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
try:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return self._template_env.from_string(template).render(
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
context=context, **context
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
except Exception:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return template
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
def _resolve_llm(self, tool_schemas: list[dict[str, Any]]) -> Any:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""Resolve and cache the LangChain LLM with tools bound.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
The LLM is resolved once on the first ``invoke()`` call. Subsequent
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
calls reuse the cached instance so that tool binding (which may create
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
a new LLM wrapper object) is only performed once per loop run.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if self._llm is not None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return self._llm
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
provider = self._actor_config.get("provider")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
model = self._actor_config.get("model")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
temperature = self._actor_config.get("temperature")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
max_tokens = self._actor_config.get("max_tokens")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
max_retries = self._actor_config.get("max_retries")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
llm_kwargs: dict[str, Any] = {}
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if temperature is not None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
llm_kwargs["temperature"] = temperature
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if max_tokens is not None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
llm_kwargs["max_tokens"] = max_tokens
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if max_retries is not None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
llm_kwargs["max_retries"] = max_retries
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
registry = get_provider_registry()
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Annotated as Any because create_llm() returns BaseLanguageModel but the
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# real runtime object is BaseChatModel which has bind_tools().
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
base_llm: Any = registry.create_llm(
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
provider_type=provider, model_id=model, **llm_kwargs
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if tool_schemas:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
try:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Encode tool names for Anthropic: ':' -> '_C_', '/' -> '_S_'
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
encoded_schemas = [
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
{**s, "name": _encode_tool_name(s["name"])} for s in tool_schemas
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
]
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._llm = base_llm.bind_tools(encoded_schemas)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
except Exception as exc:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
logger.warning("bind_tools failed (%s); falling back to plain LLM", exc)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._llm = base_llm
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
else:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._llm = base_llm
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return self._llm
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# -- LLMCaller protocol ---------------------------------------------------
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
def invoke(
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self,
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
prompt: str,
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_schemas: list[dict[str, Any]],
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_results: list[dict[str, Any]] | None = None,
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
actor_config: dict[str, Any] | None = None,
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
) -> LLMResponse:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""Send a prompt (with optional tool results) to the LLM.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
On the **first** call (``tool_results is None``):
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Builds the initial ``[SystemMessage, HumanMessage]`` pair from the
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
actor's ``system_prompt`` config and the user prompt, then invokes
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
the tool-bound LLM.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
On **subsequent** calls (``tool_results`` is a list):
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Appends the previous ``AIMessage`` and one ``ToolMessage`` per
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
result entry, then invokes again.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Parameters
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
----------
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
prompt:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
The original user prompt text (used only on the first call).
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_schemas:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Provider-formatted tool schema dicts passed to ``bind_tools()``.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_results:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Tool execution results from the previous iteration. Each entry
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
is a dict with keys ``tool_name``, ``call_id``, ``success``,
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
``output``, and optionally ``error``.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
actor_config:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Optional per-call actor config override. Falls back to the
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
instance-level ``actor_config`` passed to ``__init__``.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Returns
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
-------
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
LLMResponse
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Structured response including content and any tool calls.
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
"""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if HumanMessage is None or SystemMessage is None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
raise RuntimeError("LangChain messages not available for LLM tool calling")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
effective_config = actor_config or self._actor_config
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
llm = self._resolve_llm(tool_schemas)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if self._first_call:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
system_prompt: str = effective_config.get("system_prompt", "") or ""
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Apply prompt boundary sanitization (mechanism 2)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if system_prompt:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
system_prompt = _SANITIZER.augment_system_prompt(system_prompt)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._accumulated.append(SystemMessage(content=system_prompt))
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
wrapped_prompt = _SANITIZER.wrap_user_content(prompt)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._accumulated.append(HumanMessage(content=wrapped_prompt))
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._first_call = False
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
elif tool_results is not None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Append the previous AI response so the model has context
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if self._last_response is not None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._accumulated.append(self._last_response)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Append one ToolMessage per result
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
for tr in tool_results:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_result_content = (
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
str(tr.get("output", {}))
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if tr.get("success")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
else tr.get("error", "error")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if ToolMessage is not None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._accumulated.append(
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
ToolMessage(
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
content=tool_result_content,
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_call_id=(
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tr.get("call_id") or tr.get("tool_name", "unknown")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
),
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
response = llm.invoke(self._accumulated)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
self._last_response = response
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Extract content
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
raw_content = getattr(response, "content", None)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if raw_content is None:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
raw_content = str(response)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if isinstance(raw_content, list):
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
parts: list[str] = []
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
for chunk in raw_content:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if isinstance(chunk, dict):
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
parts.append(str(chunk.get("text") or chunk.get("content", "")))
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
else:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
parts.append(str(chunk))
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
content = " ".join(parts)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
else:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
content = str(raw_content)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Extract tool calls from the LangChain response
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_calls: list[LLMToolCall] = []
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
raw_tool_calls = getattr(response, "tool_calls", None) or []
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
for tc in raw_tool_calls:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if isinstance(tc, dict):
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
raw_name = tc.get("name") or tc.get("id", "")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
# Decode tool names from LLM response back to namespaced format
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
name = _decode_tool_name(raw_name)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
args = tc.get("args") or tc.get("arguments") or {}
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
call_id = tc.get("id", "")
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
if name:
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
tool_calls.append(
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
LLMToolCall(name=name, arguments=args, call_id=call_id)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
return LLMResponse(content=content, tool_calls=tool_calls)
|
||||
|
HAL9001
commented
Suggestion: In This does not block approval — the existing behavior is inherited from whatever LangChain returns in Suggestion: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:
```python
name = tc.get("name")
if not name:
logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
continue
```
This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
|
||||
Suggestion: Sections Q (
_resolve_provider_format maps provider to correct format) and R (ToolCallingAgent.process passes provider_format to ToolCallingRuntime) appear twice in this file — the same 6 scenario definitions are duplicated at lines 200–230. Please remove the duplicate block (lines 200–230) before final merge to keep tests clean and non-redundant.Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker