feat(actor-run): wire ToolCallingRuntime into actor run for skill-based tool calling #11219

Merged
hurui200320 merged 1 commits from feature/m3-actor-run-tool-calling into master 2026-05-18 06:25:40 +00:00
13 changed files with 1908 additions and 15 deletions
+274
View File
@@ -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
Outdated
Review

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

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
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
+1 -1
View File
@@ -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
+2
View File
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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")
+2
View File
@@ -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}")
+51 -6
View File
@@ -23,6 +23,13 @@ from cleveragents.reactive.stream_router import (
Review

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.

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.
Review

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.

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
Review

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.

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 (
Review

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.

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,
Review

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.

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,
Review

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.

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,
Review

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.

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.
)
Review

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.

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
Review

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.

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:
Review

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.

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.
Review

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.

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
Review

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.

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:
Review

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.

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.
Review

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.

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.
Review

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.

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
Review

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.

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.
Review

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.

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()
Review

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.

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)
Outdated
Review

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

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
Review

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.

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)
Review

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.

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)
Review

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.

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.
Review

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.

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:
Review

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.

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.
Review

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.

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
Review

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.

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:
Review

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.

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."""
Review

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.

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
Review

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.

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.
Review

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.

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:
Review

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.

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.
Review

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.

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:
Review

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.

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
Review

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.

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
Review

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.

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.
Review

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.

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:
Outdated
Review

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

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
Review

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.

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:
Review

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.

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(
Review

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.

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' "
Review

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.

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)",
Review

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.

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,
Review

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.

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:
Review

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.

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)
Review

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.

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)
Review

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.

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)
Review

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.

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
Review

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.

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":
Review

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.

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(
Review

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.

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
Review

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.

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:
Review

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.

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.
Review

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.

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:
Review

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.

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.
Review

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.

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.
Review

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.

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
Review

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.

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.
Review

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.

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.
"""
Review

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.

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
Review

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.

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():
Review

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.

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:
Review

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.

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)
Review

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.

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
Review

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.

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.
Review

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.

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:
Review

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.

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.
Review

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.

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
Review

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.

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
Review

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.

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.
Review

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.

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()
Review

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.

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:
Review

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.

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.
Review

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.

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()
Review

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.

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()
Review

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.

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(
Review

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.

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.
Review

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.

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.
+5 -1
View File
@@ -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)
+192
View File
@@ -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)
+275
View File
@@ -0,0 +1,275 @@
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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``.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
"""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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]
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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]
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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]
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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]
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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]
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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__)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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()
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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}$``.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 ``/``,
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
"""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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_")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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`.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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_`` ``:``.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
"""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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_", ":")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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`
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
----------
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.).
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
"""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 {})
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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] = []
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 = (
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 -----------------------------------------------------
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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*.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
"""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 ""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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(
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
"""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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] = {}
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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()
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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().
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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(
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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_'
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 = [
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
]
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 ---------------------------------------------------
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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(
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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,
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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,
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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]],
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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,
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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,
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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``):
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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):
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
----------
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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).
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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()``.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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``,
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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``.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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__``.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
-------
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
"""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 ""
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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))
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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))
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 = (
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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", {}))
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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(
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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(
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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,
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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=(
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
),
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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):
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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] = []
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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):
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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", "")))
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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))
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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] = []
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 []
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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):
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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", "")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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 {}
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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", "")
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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:
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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(
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does 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)
Outdated
Review

Suggestion: In invoke() at the tool call extraction loop (~line 1875), when tc.get("name") returns None, the fallback is "". An empty-named LLMToolCall will be created, and downstream in ToolCallingRuntime this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning:

name = tc.get("name")
if not name:
    logger.debug("Skipping LLM tool call entry with no name field: %s", tc)
    continue

This does 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: In `invoke()` at the tool call extraction loop (~line 1875), when `tc.get("name")` returns `None`, the fallback is `""`. An empty-named `LLMToolCall` will be created, and downstream in `ToolCallingRuntime` this could fail when attempting to look up a tool by empty string. Consider skipping such entries or logging a warning: ```python name = tc.get("name") if not name: logger.debug("Skipping LLM tool call entry with no name field: %s", tc) continue ``` This does not block approval — the existing behavior is inherited from whatever LangChain returns in `response.tool_calls`, but a guard here would be more robust.