Packages
langchain
0.9.2
0.9.2
0.9.1
0.9.0
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.4.0-rc.3
0.4.0-rc.2
0.4.0-rc.1
0.4.0-rc.0
0.3.3
0.3.2
0.3.1
0.3.0
0.3.0-rc.2
0.3.0-rc.1
0.3.0-rc.0
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Elixir implementation of a LangChain style framework that lets Elixir projects integrate with and leverage LLMs.
Current section
Files
Jump to
Current section
Files
lib/chains/llm_chain/modes/until_tool_used.ex
defmodule LangChain.Chains.LLMChain.Modes.UntilToolUsed do
@moduledoc """
Execution mode that loops until a specific tool is called.
Repeatedly calls the LLM and executes tools until a tool result
matching one of the target tool names is found.
## Options
- `:tool_names` — (required) List of tool name strings to watch for.
- `:max_runs` — Maximum LLM calls before error. Default: 25.
## Usage
LLMChain.run(chain,
mode: LangChain.Chains.LLMChain.Modes.UntilToolUsed,
tool_names: ["submit"],
max_runs: 25
)
# => {:ok, chain, %ToolResult{name: "submit", ...}}
"""
@behaviour LangChain.Chains.LLMChain.Mode
import LangChain.Chains.LLMChain.Mode.Steps
alias LangChain.Chains.LLMChain
alias LangChain.LangChainError
@impl true
def run(%LLMChain{} = chain, opts) do
tool_names = Keyword.fetch!(opts, :tool_names)
# Validate tools exist
missing = Enum.filter(tool_names, fn name -> !Map.has_key?(chain._tool_map, name) end)
if missing != [] do
message =
if length(missing) > 1 do
"Tool names '#{Enum.join(missing, ", ")}' not found in available tools"
else
"Tool name '#{List.first(missing)}' not found in available tools"
end
{:error, chain,
LangChainError.exception(
type: "invalid_tool_name",
message: message
)}
else
chain = ensure_mode_state(chain)
do_run(chain, opts)
end
end
defp do_run(chain, opts) do
# Order matters: `check_max_runs` must come AFTER `check_until_tool`,
# otherwise the very LLM call that successfully invokes the target
# tool can have its result discarded — `call_llm` increments the run
# counter, the check fires and short-circuits the pipeline before
# `execute_tools`/`check_until_tool` get to see the result. With this
# order, a successful run terminates first; `check_max_runs` is a
# no-op on terminal pipeline states.
{:continue, chain}
|> call_llm()
|> execute_tools()
|> check_until_tool(opts)
|> check_max_runs(opts)
|> continue_or_done(&do_run/2, opts)
end
end