diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle new file mode 100644 index 00000000..2e4c4f3c Binary files /dev/null and b/docs/_build/doctrees/environment.pickle differ diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree new file mode 100644 index 00000000..9b054163 Binary files /dev/null and b/docs/_build/doctrees/index.doctree differ diff --git a/docs/_build/doctrees/ldp.agent.doctree b/docs/_build/doctrees/ldp.agent.doctree new file mode 100644 index 00000000..fee8228e Binary files /dev/null and b/docs/_build/doctrees/ldp.agent.doctree differ diff --git a/docs/_build/doctrees/ldp.alg.doctree b/docs/_build/doctrees/ldp.alg.doctree new file mode 100644 index 00000000..9a1e9de1 Binary files /dev/null and b/docs/_build/doctrees/ldp.alg.doctree differ diff --git a/docs/_build/doctrees/ldp.alg.optimizer.doctree b/docs/_build/doctrees/ldp.alg.optimizer.doctree new file mode 100644 index 00000000..a877c56c Binary files /dev/null and b/docs/_build/doctrees/ldp.alg.optimizer.doctree differ diff --git a/docs/_build/doctrees/ldp.doctree b/docs/_build/doctrees/ldp.doctree new file mode 100644 index 00000000..76d22c94 Binary files /dev/null and b/docs/_build/doctrees/ldp.doctree differ diff --git a/docs/_build/doctrees/ldp.graph.doctree b/docs/_build/doctrees/ldp.graph.doctree new file mode 100644 index 00000000..022fc740 Binary files /dev/null and b/docs/_build/doctrees/ldp.graph.doctree differ diff --git a/docs/_build/doctrees/ldp.graph.modules.doctree b/docs/_build/doctrees/ldp.graph.modules.doctree new file mode 100644 index 00000000..c9c9db57 Binary files /dev/null and b/docs/_build/doctrees/ldp.graph.modules.doctree differ diff --git a/docs/_build/doctrees/ldp.llms.doctree b/docs/_build/doctrees/ldp.llms.doctree new file mode 100644 index 00000000..fcdbe429 Binary files /dev/null and b/docs/_build/doctrees/ldp.llms.doctree differ diff --git a/docs/_build/doctrees/modules.doctree b/docs/_build/doctrees/modules.doctree new file mode 100644 index 00000000..ea80a823 Binary files /dev/null and b/docs/_build/doctrees/modules.doctree differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo new file mode 100644 index 00000000..6967a943 --- /dev/null +++ b/docs/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: e40320371eeccd574e176c1e4efc6498 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/_modules/index.html b/docs/_build/html/_modules/index.html new file mode 100644 index 00000000..7a6eef90 --- /dev/null +++ b/docs/_build/html/_modules/index.html @@ -0,0 +1,137 @@ + + + + + + + Overview: module code — ldp documentation + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent.html b/docs/_build/html/_modules/ldp/agent.html new file mode 100644 index 00000000..e5806a0e --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent.html @@ -0,0 +1,133 @@ + + + + + + + ldp.agent — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent

+from enum import StrEnum
+
+
+
+[docs] +class DefaultLLMModelNames(StrEnum): + """Defaults for LLM models, pin exact versions for performance stability.""" + + OPENAI = "gpt-4o-2024-08-06" # Cheap, fast, and decent
+ + + +# ruff: noqa: E402 # Avoid circular imports + +from .agent import Agent, AgentConfig +from .agent_client import HTTPAgentClient, make_simple_agent_server +from .memory_agent import MemoryAgent +from .react_agent import ReActAgent +from .simple_agent import SimpleAgent, SimpleAgentState +from .tree_of_thoughts_agent import TreeofThoughtsAgent + +__all__ = [ + "Agent", + "AgentConfig", + "DefaultLLMModelNames", + "HTTPAgentClient", + "MemoryAgent", + "ReActAgent", + "SimpleAgent", + "SimpleAgentState", + "TreeofThoughtsAgent", + "make_simple_agent_server", +] +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent/agent.html b/docs/_build/html/_modules/ldp/agent/agent.html new file mode 100644 index 00000000..fe722289 --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent/agent.html @@ -0,0 +1,295 @@ + + + + + + + ldp.agent.agent — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent.agent

+from __future__ import annotations
+
+import json
+from abc import ABC, abstractmethod
+from collections.abc import Collection, Iterable, Mapping, Sequence
+from typing import Any, Generic, TypeVar
+
+import numpy as np
+from aviary.message import Message
+from aviary.tools import Tool, ToolRequestMessage
+from pydantic import BaseModel, ConfigDict, Field, JsonValue
+
+from ldp.graph import Op, OpResult
+
+try:
+    # So we can skip torch objects when looking for Ops
+    import torch
+except ImportError:
+    # If torch is not available, then it won't be used in an Agent anyway
+    torch = None  # type: ignore[assignment]
+
+TAgentState = TypeVar("TAgentState")
+
+
+# A global registry of all Agent subclasses, so we can look them up by name
+_AGENT_REGISTRY: dict[str, type[Agent]] = {}
+
+
+
+[docs] +class Agent(ABC, Generic[TAgentState]): + def __init_subclass__(cls, **kwargs): + """Ensure Ops have unique names and subclasses are in _AGENT_REGISTRY.""" + super().__init_subclass__(**kwargs) + + original_init = cls.__init__ + + def init_with_op_naming(self, *args, **kwargs): + original_init(self, *args, **kwargs) + + # loop through Ops and give them proper names + for name, op in _find_ops(self): + op.set_name(name) + + cls.__init__ = init_with_op_naming # type: ignore[method-assign] + + # Register the Agent subclass. + _AGENT_REGISTRY[cls.__name__] = cls + +
+[docs] + @abstractmethod + async def get_asv( + self, agent_state: TAgentState, obs: list[Message] + ) -> tuple[OpResult[ToolRequestMessage], TAgentState, float]: + """ + Get new action, state, and value given state and observation messages. + + NOTE: the method's name has action listed before state to help you realize it's + a new state. + + Args: + agent_state: Optional current agent state, pass None if irrelevant. + This can be something like agent memory. + obs: Most recent list of observation messages from the environment's steps. + If more observations than the most recent list are necessary, track them + in the agent state. + + Returns: + Three-tuple of new action, new agent state, and estimated value. The + agent_state is returned as a copy so that you can safely mutate it + without affecting the original. The estimated value is the agent's + estimate of the future rewards given the input state and observations, + and is used for RL training. If estimated value doesn't matter, just + return 0. The value could also come from a Q-value evaluated at the + action chosen by the agent. + """
+ + +
+[docs] + @abstractmethod + async def init_state(self, tools: list[Tool]) -> TAgentState: + """Initializes the first agent state with the provided tools."""
+ + +
+[docs] + def named_ops(self) -> Iterable[tuple[str, Op]]: + """Analogous to torch.nn.Module.named_parameters().""" + return _find_ops(self)
+ + +
+[docs] + @classmethod + def from_name(cls, name: str, **kwargs) -> Agent: + return _AGENT_REGISTRY[name](**kwargs)
+
+ + + +
+[docs] +class AgentConfig(BaseModel): + """Configuration for specifying the type of agent i.e. the subclass of Agent above.""" + + model_config = ConfigDict(extra="forbid") + + agent_type: str = Field( + description="The type of agent to be used. " + "This should be a subclass of Agent above.", + ) + agent_kwargs: dict[str, JsonValue] = Field( + default_factory=dict, + description="Keyword arguments to pass to the agent's constructor.", + ) + +
+[docs] + def construct_agent(self) -> Agent: + return Agent.from_name(self.agent_type, **self.agent_kwargs)
+ + + def __hash__(self) -> int: + return hash(self.agent_type + json.dumps(self.agent_kwargs, sort_keys=True))
+ + + +def _find_ops( # noqa: C901 + root: object, root_name: str = "", visited: set[int] | None = None +) -> Iterable[tuple[str, Op]]: + """Recursive function to find children that are Ops and the attr chain to reach them. + + E.g. if root.module.op is an Op, then we will yield ("module.op", root.module.op). + These are not fully qualified names, but more like "locally qualified names". In the above + example, "root." + "module.op" is the fully qualified name. + This is an internal function - Agent.named_ops() should usually suffice. + + Args: + root: Any object that might hold Ops. + root_name: The name of the root object. Defaults to empty string and is passed as an arg to + make this method recursive. + visited: a set of visited node IDs to avoid loops. Defaults to None. + + Yields: + Two-tuple of (locally qualified name, Op) pairs + """ + # Recursive function to find children that are Ops and the + # attribute chain to reach them. + if visited is None: + visited = set() + + if isinstance(root, Op): + yield root_name, root + # Assume an Op may not have sub-Ops. I think this is sound, since + # we wouldn't be tracking the compute graph properly if it did. + return + + if "__pydantic_parent_namespace__" in root_name: + # Skip Pydantic internals + return + + # Don't recurse into PyTorch objects because they won't contain Ops + if torch is not None and ( # type: ignore[redundant-expr] + isinstance(root, torch.Tensor | torch.nn.Module) + ): + return + + # Similarly for numpy + if isinstance(root, np.ndarray): + return + + # loop through 3 types of containers: dicts, collections, and objects + if isinstance(root, Mapping): + named_attrs: Any = root.items() + elif isinstance(root, Sequence | Collection) and not isinstance(root, str | bytes): + named_attrs = enumerate(root) + elif hasattr(root, "__dict__"): + # object? + named_attrs = root.__dict__.items() + else: + # couldn't descend + return + + for k, v in named_attrs: + id_v = id(v) + if id_v not in visited: + # only visit each object once - avoid loops, etc. + visited.add(id_v) + if root_name: + k = f"{root_name}.{k}" + yield from _find_ops(v, root_name=k, visited=visited) +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent/agent_client.html b/docs/_build/html/_modules/ldp/agent/agent_client.html new file mode 100644 index 00000000..d520c0cb --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent/agent_client.html @@ -0,0 +1,260 @@ + + + + + + + ldp.agent.agent_client — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent.agent_client

+import os
+import secrets
+from typing import TYPE_CHECKING, Annotated, TypeVar
+
+import httpx
+from aviary.message import Message
+from aviary.tools import Messages, Tool, ToolRequestMessage, ToolsAdapter
+from pydantic import BaseModel
+
+from ldp.graph import OpResult, get_training_mode
+
+from .agent import Agent
+from .simple_agent import SimpleAgentState
+
+if TYPE_CHECKING:
+    from fastapi import FastAPI
+
+TSerializableAgentState = TypeVar("TSerializableAgentState", bound=BaseModel)
+
+
+
+[docs] +class HTTPAgentClient(Agent[TSerializableAgentState]): + """Interact with an Agent running in a server via POST requests.""" + + def __init__( + self, + agent_state_type: type[TSerializableAgentState], + server_url: str, + request_headers: httpx._types.HeaderTypes | None = None, + request_timeout: float | None = None, + ): + super().__init__() + self._agent_state_type = agent_state_type + self._request_url = server_url + self._request_headers = request_headers + self._request_timeout = request_timeout + +
+[docs] + async def get_asv( + self, + agent_state: TSerializableAgentState, + obs: list[Message], + ) -> tuple[OpResult[ToolRequestMessage], TSerializableAgentState, float]: + async with httpx.AsyncClient() as client: + response = await client.post( + f"{self._request_url}/get_asv", + json={ + "agent_state": agent_state.model_dump(), + "obs": [m.model_dump() for m in obs], + "training": get_training_mode(), + }, + headers=self._request_headers, + timeout=self._request_timeout, + ) + response.raise_for_status() + response_data = response.json() + return ( + OpResult.from_dict(ToolRequestMessage, response_data[0]), + self._agent_state_type(**response_data[1]), + response_data[2], + )
+ + +
+[docs] + async def init_state(self, tools: list[Tool]) -> TSerializableAgentState: + async with httpx.AsyncClient() as client: + response = await client.post( + f"{self._request_url}/init_state", + json=ToolsAdapter.dump_python(tools), + headers=self._request_headers, + timeout=self._request_timeout, + ) + response.raise_for_status() + return self._agent_state_type(**response.json())
+
+ + + +
+[docs] +def make_simple_agent_server( + agent: Agent[SimpleAgentState], render_docs: bool = False +) -> "FastAPI": + """ + Make a FastAPI app designed to work with the above HTTPAgentClient. + + Here's how this works: + 1. There is an entity orchestrating an Agent's interactions with an Environment. + A simple example of this is an integration test that sequentially calls + Agent.get_asv and Environment.step. + 2. That entity is given the above HTTPAgentClient. Any Agent.init_state or + Agent.get_asv calls the orchestration entity makes are actually + POST requests under the hood. The agent's "brains" aren't local. + 3. Remotely, this server code is running, and is where the actual Agent logic lives. + An example of this is a remote server containing GPU(s). + """ + try: + from fastapi import Body, Depends, FastAPI, HTTPException, status + from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer + except ModuleNotFoundError as exc: + raise ImportError( + "Please install aviary with the 'server' extra like so:" + " `pip install aviary[server]`." + ) from exc + + asgi_app = FastAPI( + title=f"aviary.Agent {type(agent).__name__}", + description="Serve inference endpoints for an aviary.Agent with a SimpleAgentState", + # Only render Swagger docs if local since we don't have a login here + docs_url="/docs" if render_docs else None, + redoc_url="/redoc" if render_docs else None, + ) + auth_scheme = HTTPBearer() + + async def validate_token( + token: Annotated[HTTPAuthorizationCredentials, Depends(auth_scheme)], + ) -> HTTPAuthorizationCredentials: + # NOTE: don't use os.environ.get() to avoid possible empty string matches, and + # to have clearer server failures if the AUTH_TOKEN env var isn't present + if not secrets.compare_digest(token.credentials, os.environ["AUTH_TOKEN"]): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect bearer token", + headers={"WWW-Authenticate": "Bearer"}, + ) + return token + + @asgi_app.get("/info") + def info( + _: Annotated[HTTPAuthorizationCredentials, Depends(validate_token)], + ) -> dict[str, str]: + """Get agent metadata, useful for debugging.""" + return {"agent_type": type(agent).__name__} + + @asgi_app.post("/get_asv") + async def get_asv( + agent_state: SimpleAgentState, + obs: Messages, + _: Annotated[HTTPAuthorizationCredentials, Depends(validate_token)], + training: Annotated[bool, Body()] = True, + ) -> tuple[dict, SimpleAgentState, float]: + if training: + raise NotImplementedError("Training is not yet supported.") + action, agent_state, vhat = await agent.get_asv(agent_state, obs) + return action.to_dict(), agent_state, vhat + + @asgi_app.post("/init_state") + async def init_state( + tools: list[Tool], + _: Annotated[HTTPAuthorizationCredentials, Depends(validate_token)], + ) -> SimpleAgentState: + return await agent.init_state(tools) + + return asgi_app
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent/interactive_agent.html b/docs/_build/html/_modules/ldp/agent/interactive_agent.html new file mode 100644 index 00000000..89da7c21 --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent/interactive_agent.html @@ -0,0 +1,225 @@ + + + + + + + ldp.agent.interactive_agent — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent.interactive_agent

+import contextlib
+import json
+from typing import Any
+
+from aviary.message import Message
+from aviary.tools import Tool, ToolRequestMessage
+from aviary.tools.base import ToolCall
+
+from ldp.graph import IdentityOp, OpResult, compute_graph
+
+from .agent import Agent
+from .simple_agent import SimpleAgentState
+
+MISSING_DEFAULT = object()
+CLEAR = "CLEAR"  # Clears the current input and allows the user to start over, e.g. if they made a mistake
+EXIT = "EXIT"  # Exits the agent by raising a RuntimeError. Makes it possible to interrupt a rollout
+
+
+
+[docs] +class InteractiveAgent(Agent[SimpleAgentState]): + """An "agent" that provides an interface for human users to interact with environments.""" + + def __init__(self): + self.action_op = IdentityOp[ToolRequestMessage]() + +
+[docs] + async def init_state(self, tools: list[Tool]) -> SimpleAgentState: + print() # add a newline to flush any progress bars, etc + print("AVAILABLE TOOLS:\n" + ("-" * 80)) + for tool in tools: + info = tool.info + docstring = f"{info.name}(" + arg_docs = [] + for pname, pprops in info.parameters.properties.items(): + docstring += self._get_param_string(pname, pprops) + ", " + arg_doc = " " + pname + if "description" in pprops: + arg_doc += ": " + pprops.get("description", "") + arg_docs.append(arg_doc) + + docstring = docstring.rstrip(", ") + "):\n" + docstring += " " + info.description + "\n\n" + docstring += "\n".join(arg_docs) + docstring += "\n" + print(docstring) + print("-" * 80) + return SimpleAgentState(tools=tools)
+ + +
+[docs] + @compute_graph() + async def get_asv( # noqa: C901 + self, agent_state: SimpleAgentState, obs: list[Message] + ) -> tuple[OpResult[ToolRequestMessage], SimpleAgentState, float]: + print() # add a newline to flush any progress bars, etc + print("OBSERVATIONS:\n" + ("-" * 80)) + for msg in obs: + print((msg.content or "") + "\n") + print("-" * 80) + + next_agent_state = agent_state.get_next_state(obs) + + tool: Tool | None = None + while not tool: + tool_choice = input(">>> Select tool by name: ") + if tool_choice == CLEAR: + continue + if tool_choice == EXIT: + raise RuntimeError("User requested to kill the agent.") + + tool = next( + (t for t in agent_state.tools if t.info.name == tool_choice), None + ) + if not tool: + print( + f"Tool '{tool_choice}' not found. Please select from the above tools." + ) + + params: dict[str, Any] = {} + for pname, pprops in tool.info.parameters.properties.items(): + pdefault = pprops.get("default", MISSING_DEFAULT) + prompt = f">>> Enter parameter ({self._get_param_string(pname, pprops)}): " + while True: + value = input(prompt) + if value == CLEAR: + return await self.get_asv(agent_state, obs) # just start over + if value == EXIT: + raise RuntimeError("User requested to kill the agent.") + + with contextlib.suppress(json.JSONDecodeError): + # lets us load ints, etc. Otherwise, assume it's a string + value = json.loads(value) + if not value: + if pdefault is MISSING_DEFAULT: + print("Parameter is required.") + continue + + value = pdefault + + params[pname] = value + break + + tool_call = ToolCall.from_tool(tool, **params) + action = await self.action_op(ToolRequestMessage(tool_calls=[tool_call])) + + next_agent_state.messages = [*next_agent_state.messages, action.value] + + return action, next_agent_state, 0.0
+ + + @staticmethod + def _get_param_string(pname: str, pprops: dict[str, Any]) -> str: + pstring = pname + if ptype := (pprops.get("type") or "Any"): + pstring += f": {ptype}" + + if (pdefault := pprops.get("default", MISSING_DEFAULT)) is not MISSING_DEFAULT: + pstring += f" = {pdefault}" + return pstring
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent/memory_agent.html b/docs/_build/html/_modules/ldp/agent/memory_agent.html new file mode 100644 index 00000000..588d3cd1 --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent/memory_agent.html @@ -0,0 +1,235 @@ + + + + + + + ldp.agent.memory_agent — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent.memory_agent

+"""This module defines the MemoryAgent class, which extends a base agent model with memory.
+
+capabilities. The MemoryAgent can pick and invoke tools based on the stored and retrieved
+memories, formatted using specified prompts. A memory is typically a set of previous trajectories
+"""
+
+from collections.abc import Awaitable, Callable, Iterable
+from typing import ClassVar, cast
+
+from aviary.message import Message
+from aviary.tools import ToolRequestMessage
+from pydantic import ConfigDict, Field
+
+from ldp.graph import (
+    FxnOp,
+    Memory,
+    MemoryModel,
+    MemoryOp,
+    OpResult,
+    PromptOp,
+    compute_graph,
+)
+from ldp.llms.prompts import indent_xml
+
+from .simple_agent import SimpleAgent, SimpleAgentState
+
+
+async def _default_query_factory(messages: Iterable[Message]) -> str:
+    return "\n\n".join([str(m) for m in messages if m.role != "system"])
+
+
+
+[docs] +class MemoryAgent(SimpleAgent): + """ + Simple agent that can pick and invoke tools with memory. + + NOTE: the MemoryAgent does not maintain an explicit value estimate, + it simply supplies previous trajectories via the prompt. + As such, the value estimate vhat will always be zero. + """ + + # Working around https://github.com/pydantic/pydantic/issues/10551 + default_query_factory: ClassVar[Callable[[Iterable[Message]], Awaitable[str]]] = ( + _default_query_factory + ) + + prompt: str = Field( + default=( + "<episode-memories>\n<description>\n" + "These are relevant memories from previous attempts at similar tasks, " + "along with the action taken and the discounted cumulative reward from that action. " + "A negative reward is failure, a positive reward is success.\n" + "</description>{memories}</episode-memories>\n\n" + "Considering the memories, choose the next action." + ), + description="Prompt that includes the memories.", + ) + query_factory: Callable[[Iterable[Message]], Awaitable[str]] = Field( + default=default_query_factory, + description=( + "Async function to generate a Memory query string from messages. It's async" + " so this can involve an LLM completion if desired." + ), + exclude=True, + ) + memory_prompt: str = Field( + default="<memory><obs>{input}</obs><action>{output}</action><reward>{value}</reward></memory>", + description="Prompt for formatting an individual memory. " + "Use XML instead of JSON to avoid potential escaping issues.", + ) + num_memories: int = Field( + default=MemoryModel.DEFAULT_MEMORY_MATCHES, + description="Number of memories to retrieve from MemoryOp", + ) + # Freeze to ensure the only mutation happens in either the agent state (which is + # passed around) or in the internal Ops + model_config = ConfigDict(frozen=True) + + @staticmethod + def _format_memories(prompt: str, memories: Iterable[Memory]) -> str: + return indent_xml( + "\n".join([ + prompt.format(**m.model_dump(exclude={"run_id", "template"})) + for m in memories + ]) + ) + + @staticmethod + def _package_messages( + msgs: list[Message], memory_prompt: str, use_memories: bool + ) -> list[Message]: + if use_memories: + return [*msgs, Message(content=memory_prompt)] + return msgs + + def __init__(self, memory_model: MemoryModel | None = None, **kwargs): + super().__init__(**kwargs) + self._query_factory_op = FxnOp[str](self.query_factory) + self._memory_op = MemoryOp(memory_model) + self._format_memory_op = FxnOp(self._format_memories) + self._prompt_op = PromptOp(self.prompt) + self._package_op = FxnOp(self._package_messages) + +
+[docs] + @compute_graph() + async def get_asv( + self, agent_state: SimpleAgentState, obs: list[Message] + ) -> tuple[OpResult[ToolRequestMessage], SimpleAgentState, float]: + next_state = agent_state.get_next_state(obs) + + memories = await self._memory_op( + query=await self._query_factory_op(next_state.messages), + matches=self.num_memories, + ) + packaged_messages = await self._package_op( + next_state.messages, + memory_prompt=await self._prompt_op( + memories=await self._format_memory_op(self.memory_prompt, memories) + ), + use_memories=bool(memories.value), + ) + result = cast( + OpResult[ToolRequestMessage], + await self._llm_call_op( + await self._config_op(), msgs=packaged_messages, tools=next_state.tools + ), + ) + next_state.messages = [*next_state.messages, result.value] + return result, next_state, 0.0
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent/react_agent.html b/docs/_build/html/_modules/ldp/agent/react_agent.html new file mode 100644 index 00000000..1dba1962 --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent/react_agent.html @@ -0,0 +1,255 @@ + + + + + + + ldp.agent.react_agent — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent.react_agent

+import logging
+from typing import Any, Self, cast
+
+from aviary.message import MalformedMessageError, Message
+from aviary.tools import Tool, ToolRequestMessage, ToolResponseMessage
+from pydantic import BaseModel, ConfigDict, Field
+from tenacity import (
+    Future,
+    RetryCallState,
+    before_sleep_log,
+    retry,
+    retry_if_exception_type,
+    stop_after_attempt,
+)
+
+from ldp.graph import OpResult, compute_graph
+from ldp.graph.modules.react import (
+    ACT_DEFAULT_PROMPT_TEMPLATE,
+    REACT_DEFAULT_PROMPT_TEMPLATE,
+    ReActModule,
+    ToolDescriptionMethods,
+)
+
+from . import DefaultLLMModelNames
+from .agent import Agent
+from .simple_agent import SimpleAgentState
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class ReActAgent(BaseModel, Agent[SimpleAgentState]): + """An Act or ReAct Agent built to work with chat models. + + Paper: https://arxiv.org/abs/2210.03629 + + The ReAct style is like so, and note Act style has no 'Thought: ' entries: + System: + Answer the following questions as best you can. You have access to the following tools: + + {tools} + + Use the following format: + + Thought: you should always think about what to do + Action: the action to take, should be one of [{tool_names}] + Action Input: the input to the action + Observation: the result of the action + ... (this Thought/Action/Action Input/Observation can repeat N times) + User: + {questions} + Assistant: + Thought: + Action: + Action Input: + User: + Observation: + Assistant: + Thought: + Action: + Action Input: + ... + + One notable design decision is that ReAct's state does not necessarily + track ToolRequestMessage. Recall that aviary is in a partially observable + domain, meaning we don't need to have perfect symmetry with Environments. + Instead, ReActAgent's state stores a ReAct-style message history, where the + messages are plain Message (and not a ToolRequestMessage). + """ + + # Freeze to ensure the only mutation happens in either the agent state (which is + # passed around) or in the internal Ops + model_config = ConfigDict(frozen=True) + + llm_model: dict[str, Any] = Field( + default={ + "model": DefaultLLMModelNames.OPENAI.value, + "temperature": 0.1, + "logprobs": True, + "top_logprobs": 1, + }, + description="Starting configuration for the LLM model.", + ) + sys_prompt: str = Field( + default=REACT_DEFAULT_PROMPT_TEMPLATE, + description="Learnable system prompt template, defaults to ReAct.", + ) + tool_description_method: ToolDescriptionMethods = Field( + default=ToolDescriptionMethods.STR, + description="Method used to describe the tools, defaults to 'str' description.", + ) + +
+[docs] + @classmethod + def make_act_agent(cls, **kwargs) -> Self: + return cls(sys_prompt=ACT_DEFAULT_PROMPT_TEMPLATE, **kwargs)
+ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._react_module = ReActModule( + self.llm_model, self.sys_prompt, self.tool_description_method + ) + +
+[docs] + async def init_state(self, tools: list[Tool]) -> SimpleAgentState: + return SimpleAgentState(tools=tools)
+ + +
+[docs] + @staticmethod + def after_retry_failure_log(retry_state: RetryCallState): + logger.error( + f"Failed across {retry_state.attempt_number} attempts to run get_asv given" + f" arguments {retry_state.args} and kwargs {retry_state.kwargs}." + ) + # NOTE: this blows up with the underlying exception... it isn't wrapped in a + # RetryError like normal tenacity + return cast(Future, retry_state.outcome).result()
+ + +
+[docs] + @retry( + retry=retry_if_exception_type(MalformedMessageError), + before_sleep=before_sleep_log(logger, logging.WARNING), + stop=stop_after_attempt(5), + retry_error_callback=after_retry_failure_log, + ) + @compute_graph() + async def get_asv( + self, agent_state: SimpleAgentState, obs: list[Message] + ) -> tuple[OpResult[ToolRequestMessage], SimpleAgentState, float]: + next_state = agent_state.get_next_state( + obs=[ + Message(content=f"Observation: {m.content}") + if isinstance(m, ToolResponseMessage) + else m + for m in obs + ] + ) + + final_result, react_message = await self._react_module( + messages=next_state.messages, tools=next_state.tools + ) + next_state.messages = [*next_state.messages, react_message] + return final_result, next_state, 0.0
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent/simple_agent.html b/docs/_build/html/_modules/ldp/agent/simple_agent.html new file mode 100644 index 00000000..012a7c1e --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent/simple_agent.html @@ -0,0 +1,217 @@ + + + + + + + ldp.agent.simple_agent — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent.simple_agent

+from __future__ import annotations
+
+from typing import Any, Self, cast
+
+from aviary.message import Message
+from aviary.tools import Tool, ToolRequestMessage, ToolResponseMessage
+from pydantic import BaseModel, ConfigDict, Field
+
+from ldp.graph import ConfigOp, LLMCallOp, OpResult, compute_graph
+from ldp.llms import prepend_sys
+
+from . import DefaultLLMModelNames
+from .agent import Agent
+
+
+
+[docs] +class SimpleAgentState(BaseModel): + """Simple bucket for an Agent to access tools and store messages.""" + + tools: list[Tool] = Field(default_factory=list) + messages: list[ToolRequestMessage | ToolResponseMessage | Message] = Field( + default_factory=list + ) + +
+[docs] + def get_next_state( + self, + obs: list[Message] | None = None, + tools: list[Tool] | None = None, + **kwargs, + ) -> Self: + """ + Get the next agent state without mutating the optional prior state. + + Do not mutate self here, just read from it. + + Args: + obs: Optional observation messages to use in creating the next state. + tools: Optional list of tools available to the agent. If unspecified, these + should be pulled from the prior_state. + kwargs: Additional keyword arguments to pass to this class's constructor. + + Returns: + The next agent state (which is not an in-place change to self). + """ + return type(self)( + tools=tools if tools is not None else self.tools, + messages=self.messages + (obs or []), + **kwargs, + )
+
+ + + +
+[docs] +class SimpleAgent(BaseModel, Agent[SimpleAgentState]): + """Simple agent that can pick and invoke tools with a language model. + + It does not have a system prompt because it's meant to be lightweight. + """ + + # Freeze to ensure the only mutation happens in either the agent state (which is + # passed around) or in the internal Ops + model_config = ConfigDict(frozen=True) + + llm_model: dict[str, Any] = Field( + default={"model": DefaultLLMModelNames.OPENAI.value, "temperature": 0.1}, + description="Starting configuration for the LLM model. Trainable.", + ) + sys_prompt: str | None = Field( + default=None, + description=( + "Opt-in system prompt. If one is passed, the system prompt is not set up to" + " be trainable, because this class is meant to be quite simple as far as" + " possible hyperparameters." + ), + ) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._config_op = ConfigOp[dict](config=self.llm_model) + self._llm_call_op = LLMCallOp() + +
+[docs] + async def init_state(self, tools: list[Tool]) -> SimpleAgentState: + return SimpleAgentState(tools=tools)
+ + +
+[docs] + @compute_graph() + async def get_asv( + self, agent_state: SimpleAgentState, obs: list[Message] + ) -> tuple[OpResult[ToolRequestMessage], SimpleAgentState, float]: + next_state = agent_state.get_next_state(obs) + + messages = ( + prepend_sys(next_state.messages, sys_content=self.sys_prompt) + if self.sys_prompt is not None + else next_state.messages + ) + result = cast( + OpResult[ToolRequestMessage], + await self._llm_call_op( + await self._config_op(), msgs=messages, tools=next_state.tools + ), + ) + next_state.messages = [*next_state.messages, result.value] + return result, next_state, 0.0
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/agent/tree_of_thoughts_agent.html b/docs/_build/html/_modules/ldp/agent/tree_of_thoughts_agent.html new file mode 100644 index 00000000..f8bca7ff --- /dev/null +++ b/docs/_build/html/_modules/ldp/agent/tree_of_thoughts_agent.html @@ -0,0 +1,251 @@ + + + + + + + ldp.agent.tree_of_thoughts_agent — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.agent.tree_of_thoughts_agent

+"""Module for the Tree of Thoughts agent.
+
+This module defines the Tree of Thoughts agent which uses a language model to generate and evaluate possible
+steps in a puzzle or problem-solving environment. The agent employs a tree search mechanism to explore different
+solutions and selects the most promising ones based on evaluations.
+
+This module is based on the following paper: https://openreview.net/forum?id=5Xc1ecxO1h
+
+Note: TreeofThoughtsAgent is currently tested as a baseline agent for Game of 24. It does not yet support tool calls
+that operate on the intermediate reasoning steps. This would probably entail a redefinition of the POMDP to
+undertake intermediate reasoning steps as environment steps.
+"""
+
+import logging
+from collections.abc import Callable
+from typing import Any
+
+from aviary.message import Message
+from aviary.tools import Tool, ToolCall, ToolRequestMessage
+from pydantic import BaseModel, ConfigDict, Field
+
+from ldp.graph import FxnOp, LLMCallOp, OpResult, compute_graph, get_call_id, op_call
+from ldp.llms import prepend_sys
+
+from . import DefaultLLMModelNames
+from .agent import Agent
+from .simple_agent import SimpleAgentState
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class TreeofThoughtsAgent(BaseModel, Agent[SimpleAgentState]): + """Tree of Thoughts Agent. + + This agent uses a tree search mechanism combined with an LLM to generate and evaluate + possible steps in a problem-solving environment. It is designed to explore different solutions + and select the most promising ones based on a heuristic evaluation function. + """ + + # Freeze to ensure the only mutation happens in either the agent state (which is + # passed around) or in the internal Ops + model_config = ConfigDict(frozen=True) + + llm_model: dict[str, Any] = Field( + default={"model": DefaultLLMModelNames.OPENAI.value, "temperature": 0.1}, + description="Starting configuration for the LLM model.", + ) + value_prompt_func: Callable[[str, str], str] = Field( + default=lambda x, y: f"Value prompt for input: {x}, current path: {y}", + description="Function to format value prompt template.", + ) + proposal_prompt_func: Callable[[str, str], str] = Field( + default=lambda x, y: f"Proposal prompt for input: {x}, current path: {y}", + description="Function to format proposal prompt template.", + ) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._prepend_op = FxnOp(prepend_sys) + self._llm_call_op = LLMCallOp() + +
+[docs] + async def init_state(self, tools: list[Tool]) -> SimpleAgentState: + return SimpleAgentState(tools=tools)
+ + +
+[docs] + @compute_graph() + async def get_asv( # type: ignore[override] + self, + agent_state: SimpleAgentState, + obs: list[Message], + eval_function: Callable[[str, list[str]], float], + n_steps: int = 0, + n_select_samples: int = 0, + ) -> tuple[OpResult[ToolRequestMessage], SimpleAgentState, float]: + """Generate and evaluate possible steps in the problem-solving process. + + Args: + agent_state: The current state of the agent. + obs: The observations provided to the agent. + eval_function: Function to evaluate the generated paths in the tree. + n_steps: Number of steps to generate. Defaults to 0. Dictated by the environment. + n_select_samples: Number of tree nodes to select to explore in each step. Defaults to 0. + + Returns: + The result of the operation, the new state of the agent, and the number representing the value (0). + """ + new_state = agent_state.get_next_state() + + x = str(obs[0].content) # Current problem input + current_paths = [""] # current candidate paths through the tree + + for step in range(n_steps): + logger.info(f"Step {step}") + + # propose candidate paths + candidate_paths = [] + for path in current_paths: + proposal_prompt_init = self.proposal_prompt_func(x, path) + proposal_msgs = await self._prepend_op( + new_state.messages, sys_content=proposal_prompt_init + ) + proposal = await self._llm_call_op(self.llm_model, msgs=proposal_msgs) + # Append candidate paths to the current paths + candidate_paths += [ + path + _ + "\n" + for _ in (proposal.value.content or "").split("\n") + if _ + ] + + # score candidate paths + values = [] + for path in candidate_paths: + value_prompt_init = self.value_prompt_func(x, path) + value_msgs = await self._prepend_op( + new_state.messages, sys_content=value_prompt_init + ) + value_outputs = await self._llm_call_op(self.llm_model, msgs=value_msgs) + values.append(eval_function(path, [value_outputs.value.content or ""])) + + # greedy selection + values_with_index = [(v, i) for i, v in enumerate(values)] + sorted_values = sorted(values_with_index, key=lambda x: x[0], reverse=True) + select_ids = [i for _, i in sorted_values[:n_select_samples]] + select_new_paths = [candidate_paths[select_id] for select_id in select_ids] + current_paths = select_new_paths + + # Generate tool calls for the selected answer + tool_calls = [ + ToolCall.from_tool(tool, *[current_paths[0]]) for tool in new_state.tools + ] + result = ToolRequestMessage(content=current_paths[0], tool_calls=tool_calls) + + new_state.messages = [*new_state.messages, result] + async with op_call(): + op_result: OpResult[ToolRequestMessage] = OpResult( + call_id=get_call_id(), + op_name="TreeofThoughtsAgentOp", + op_class_name=type(self).__name__, + value=result, + ) + return op_result, new_state, 0.0
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/algorithms.html b/docs/_build/html/_modules/ldp/alg/algorithms.html new file mode 100644 index 00000000..c02eae30 --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/algorithms.html @@ -0,0 +1,226 @@ + + + + + + + ldp.alg.algorithms — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.algorithms

+import itertools
+from collections.abc import Sequence
+from typing import Any
+
+import networkx as nx
+from aviary.message import Message, join
+from aviary.tools import Tool, ToolRequestMessage
+
+from ldp.graph import OpResult
+from ldp.graph.ops import GradOutType
+
+
+
+[docs] +def to_network( # noqa: C901 + op_result: OpResult, + max_label_height: int | None = None, + max_label_width: int | None = None, + G: "nx.MultiDiGraph | None" = None, +) -> "nx.MultiDiGraph": + """ + Populate a NetworkX graph from the input op result's computation graph. + + How to export Graphviz .dot file: nx.drawing.nx_pydot.write_dot(G, "file.dot") + How to render with Graphviz: nx.drawing.nx_pydot.to_pydot(G).write_png("file.png") + Online Graphviz renderer: https://dreampuf.github.io/GraphvizOnline/ + + Args: + op_result: Starting op result to recurse parent op calls and results. + max_label_height: Optional max label height (lines). + max_label_width: Optional max label width (chars). + G: Optional graph to add nodes/edges to. Allows this to be a recursive function. + + Returns: + Populated a NetworkX multi-edge directed graph. + """ + + def gvizify(x: Any) -> str: + """Stringify and then escape colons for Graphviz labels.""" + if isinstance(x, OpResult): + x = x.value + if isinstance(x, Sequence): + if isinstance(x[0], Message): + x = join(x) + elif isinstance(x[0], Tool): + x = "\n".join(f"Tool {t.info.name}" for t in x) + elif isinstance(x, ToolRequestMessage): + # reformatting tool calls to make them easier to read + x = str(x).split(" for tool calls: ") + x = "\n".join(x).replace("; ", "\n") + result = ( + "\n".join( + # Replace double quotes since they can interfere with colon escapes + # Strip here to avoid trailing spaces in the labels + x_line[:max_label_width].replace('"', "'").strip() + for i, x_line in enumerate(str(x).split("\n")) + if not max_label_height or i < max_label_height + ) + ).strip() # Remove trailing newlines + return result if ":" not in result else f'"{result}"' # Escape colons + + call_id = op_result.call_id + assert ( + call_id is not None + ), "to_network currently assumes a compute graph is available" + ctx = op_result.ctx + + op_result_str = gvizify(op_result) + op_result_node = gvizify(f"{op_result_str}\n{call_id.fwd_id}") + if G is None: + # TODO: figure out a way to use OpResult.get_compute_graph(), which builds + # a nx.DiGraph. + G = nx.MultiDiGraph() + + op_call_str = gvizify(f"{ctx.op_name}:{call_id.fwd_id}") + if op_call_str in G: + # We have already visited this node - can skip. + return G + + G.add_node(op_result_node, style="dotted", label=op_result_str) + G.add_edge(op_call_str, op_result_node) + + if ( + result_grad := ctx.get(key="grad_output", call_id=call_id, default=None) + ) is not None: + G.add_edge( + op_result_node, + op_call_str, + label=gvizify(result_grad), + style="dotted", + ) + + input_args, input_kwargs = op_result.inputs + grads = ctx.get(key="grad_input", call_id=call_id, default=None) + if grads is None: + arg_grads: list[GradOutType | None] = [None] * len(input_args) + kwarg_grads: dict[str, GradOutType | None] = dict.fromkeys(input_kwargs) + else: + arg_grads, kwarg_grads = grads + + args_and_grads = itertools.chain( + zip(input_args, arg_grads, strict=True), + ((arg, kwarg_grads[key]) for key, arg in input_kwargs.items()), + ) + + for arg, grad in args_and_grads: + arg_str = gvizify(arg) + + if not isinstance(arg, OpResult): + G.add_node(arg_str, style="dotted") + + else: + arg_str = gvizify(f"{arg_str}\n{arg.call_id.fwd_id}") + G = to_network( + arg, + max_label_height=max_label_height, + max_label_width=max_label_width, + G=G, + ) + + G.add_edge(arg_str, op_call_str) + if grad is not None: + G.add_edge(op_call_str, arg_str, label=gvizify(grad), style="dotted") + + return G
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/beam_search.html b/docs/_build/html/_modules/ldp/alg/beam_search.html new file mode 100644 index 00000000..07142dfe --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/beam_search.html @@ -0,0 +1,329 @@ + + + + + + + ldp.alg.beam_search — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.beam_search

+import asyncio
+import uuid
+from collections.abc import Awaitable, Callable, Sequence
+from contextlib import suppress
+from typing import NamedTuple
+
+from aviary.env import Environment
+
+from ldp.agent.agent import Agent, TAgentState
+from ldp.data_structures import Trajectory, Transition
+
+from .callbacks import Callback
+from .rollout import AgentError, EnvError, TEnv, reraise_exc_as
+
+
+
+[docs] +class Beam(NamedTuple): + # An ongoing beam contains two things: the trajectory up to now + # and the environment that the last action was sampled from. We + # need both to continue sampling the next step. + traj: Trajectory + env: Environment
+ + + +
+[docs] +class BeamSearchRollout: + def __init__( + self, + agent: Agent, + beam_width: int, + samples_per_beam: int, + env_clone_fn: Callable[[TEnv], Awaitable[TEnv]], + agent_clone_fn: Callable[[TAgentState], TAgentState], + scoring_fn: Callable[[Trajectory], Awaitable[float]], + replay_actions_on_clone: bool = False, + callbacks: Sequence[Callback] | None = None, + catch_agent_failures: bool = True, + catch_env_failures: bool = True, + verbose: bool = False, + ): + self.agent = agent + + self.catch_agent_failures = catch_agent_failures + self.catch_env_failures = catch_env_failures + + self.verbose = verbose + + self.traj_buffer: dict[str, Trajectory] = {} + self.search_buffer: dict[str, list[Trajectory]] = {} + + self.beam_width = beam_width + self.samples_per_beam = samples_per_beam + + self.env_clone_fn = env_clone_fn + self.agent_clone_fn = agent_clone_fn + self.scoring_fn = scoring_fn + self.replay_actions_on_clone = replay_actions_on_clone + + self.callbacks = callbacks or [] + +
+[docs] + async def sample_trajectories( + self, + environments: Sequence[Environment], + max_steps: int | None = None, + ) -> list[Trajectory]: + self.traj_buffer.clear() + traj_ids = [uuid.uuid4().hex for _ in environments] + + tasks = [ + self._rollout(traj_id, env, max_steps) + for traj_id, env in zip(traj_ids, environments, strict=True) + ] + await asyncio.gather(*tasks) + + return [self.traj_buffer[traj_id] for traj_id in traj_ids]
+ + + async def _rollout( + self, traj_id: str, env: Environment, max_steps: int | None + ) -> None: + with suppress(AgentError, EnvError): + # for samples_per_beam==1. we want to ensemble and pick the highest-scoring one + n_seeds = 1 if self.samples_per_beam > 1 else self.beam_width + + done_beams: list[Beam] = [] + beams = [ + Beam(traj=Trajectory(traj_id=f"{traj_id}:{i}"), env=env) + for i in range(n_seeds) + ] + # will be replaced if rollout is successful + self.traj_buffer[traj_id] = beams[0].traj + self.search_buffer[traj_id] = [] + + with reraise_exc_as(EnvError, self.catch_env_failures): + init_obs, tools = await env.reset() + await asyncio.gather(*[ + c.after_env_reset(traj_id, init_obs, tools) for c in self.callbacks + ]) + + with reraise_exc_as(AgentError, self.catch_agent_failures): + seed_agent_states = await asyncio.gather( + *(self.agent.init_state(tools) for _ in range(n_seeds)) + ) + # TODO: implement after_agent_init_state callback + + while len(done_beams) < self.beam_width and beams: + new_beams = [] + for beam, seed_agent_state in zip( + beams, seed_agent_states, strict=True + ): + for i_sample in range(self.samples_per_beam): + new_env = await self._clone_env(beam) + if new_env is None: + continue + + agent_state = self.agent_clone_fn(seed_agent_state) + obs = ( + beam.traj.steps[-1].next_observation + if beam.traj.steps + else init_obs.copy() + ) + + await asyncio.gather(*[ + callback.before_transition( + traj_id, self.agent, env, agent_state, obs + ) + for callback in self.callbacks + ]) + + with reraise_exc_as(AgentError, self.catch_agent_failures): + ( + action, + next_agent_state, + vhat, + ) = await self.agent.get_asv(agent_state, obs) + await asyncio.gather(*[ + callback.after_agent_get_asv( + traj_id, action, next_agent_state, vhat + ) + for callback in self.callbacks + ]) + + with reraise_exc_as(EnvError, self.catch_env_failures): + next_obs, reward, done, trunc = await new_env.step( + action.value + ) + await asyncio.gather(*[ + callback.after_env_step( + traj_id, next_obs, reward, done, trunc + ) + for callback in self.callbacks + ]) + + step = Transition( + timestep=len(beam.traj.steps), + agent_state=agent_state, + next_agent_state=next_agent_state, + observation=obs, + next_observation=next_obs, + action=action, + reward=reward, + done=done, + truncated=trunc, + value=0.0, # will be filled in + ) + await asyncio.gather(*[ + callback.after_transition(traj_id, self.agent, env, step) + for callback in self.callbacks + ]) + + new_beam = Beam( + traj=Trajectory( + traj_id=beam.traj.traj_id + f":{i_sample}", # type: ignore[operator] + steps=[*beam.traj.steps, step], + ), + env=new_env, + ) + step.value = await self.scoring_fn(new_beam.traj) + self.search_buffer[traj_id].append(new_beam.traj) + + if ( + not new_beam.traj.done + and max_steps is not None + and len(new_beam.traj.steps) >= max_steps + ): + last_step = new_beam.traj.steps[-1] + last_step.done = last_step.truncated = True + + if new_beam.traj.done: + done_beams.append(new_beam) + else: + new_beams.append(new_beam) + + new_beams.sort(key=lambda b: b.traj.steps[-1].value, reverse=True) + beams, discarded = ( + new_beams[: self.beam_width], + new_beams[self.beam_width :], + ) + seed_agent_states = [b.traj.steps[-1].next_agent_state for b in beams] + await asyncio.gather(*[d.env.close() for d in discarded]) + + await asyncio.gather(*[b.env.close() for b in beams]) + + self.traj_buffer[traj_id] = max( + done_beams, + key=lambda b: (b.traj.steps[-1].truncated, b.traj.steps[-1].value), + ).traj + + async def _clone_env(self, beam: Beam) -> Environment | None: + try: + with reraise_exc_as(EnvError, self.catch_env_failures): + # I'm not sure how to type hint this + env = await self.env_clone_fn(beam.env) # type: ignore[arg-type] + if self.replay_actions_on_clone: + # Some envs can't be cloned, so instead replay. + # We rely on env_clone_fn to properly reset the env if needed. + # We assume a deterministic env, so the return values are discarded. + for step in beam.traj.steps: + if step.action is not None: + _ = await env.step(step.action.value) + return env + except EnvError: + return None
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/callbacks.html b/docs/_build/html/_modules/ldp/alg/callbacks.html new file mode 100644 index 00000000..9fadfc52 --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/callbacks.html @@ -0,0 +1,758 @@ + + + + + + + ldp.alg.callbacks — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.callbacks

+import json
+import logging
+import os
+import time
+from collections import defaultdict
+from collections.abc import Collection, Iterable, Sequence
+from pathlib import Path
+from typing import Any, cast
+
+import aiofiles
+from aviary.env import Environment, TaskDataset
+from aviary.message import Message
+from aviary.tools import MessagesAdapter, Tool, ToolRequestMessage
+
+from ldp.agent import Agent
+from ldp.data_structures import Trajectory, Transition
+from ldp.graph import OpCtx, OpResult
+
+try:
+    import wandb
+except ImportError:
+    wandb = None  # type: ignore[assignment]
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class Callback: + """Base class for callbacks used by RolloutManager/Evaluator/OnlineTrainer. + + Pseudocode to demonstrate how callback methods are invoked (marked as *): + + RolloutManager.sample_trajectories(): + env.reset() + callback.after_env_reset() * + agent.init_state() + callback.after_agent_init_state() * + while not done: + callback.before_transition() * + agent.get_asv() + callback.after_agent_get_asv() * + env.step() + callback.after_env_step() * + callback.after_transition() * + + Evaluator.evaluate / OnlineTrainer._eval_loop(): + callback.before_eval_loop() * + for batch in eval_dataset: + rollout_manager.sample_trajectories() + callback.after_eval_step() * + callback.after_eval_loop() * + + OfflineTrainer / OnlineTrainer.train(): + for batch in train_dataset: + rollout_manager.sample_trajectories() # if online + optimizer.aggregate() + if updating_optimizer: + optimizer.update() + callback.after_update() * + callback.after_train_step() * + """ + +
+[docs] + async def before_transition( + self, + traj_id: str, + agent: Agent, + env: Environment, + agent_state: Any, + obs: list[Message], + ) -> None: + """Invoked by runners before each transition and after agent and env reset."""
+ + +
+[docs] + async def after_agent_init_state(self, traj_id: str, init_state: Any) -> None: + """Invoked by runners after agent.init_state()."""
+ + +
+[docs] + async def after_agent_get_asv( + self, + traj_id: str, + action: OpResult[ToolRequestMessage], + next_agent_state: Any, + value: float, + ) -> None: + """Invoked by runners after agent.get_asv()."""
+ + +
+[docs] + async def after_env_reset( + self, traj_id: str, obs: list[Message], tools: list[Tool] + ) -> None: + """Invoked by runners after env.reset()."""
+ + +
+[docs] + async def after_env_step( + self, traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool + ) -> None: + """Invoked by runners after env.step()."""
+ + +
+[docs] + async def after_transition( + self, traj_id: str, agent: Agent, env: Environment, transition: Transition + ) -> None: + """Invoked by runners after each transition."""
+ + +
+[docs] + async def after_train_step(self, trajectories: Sequence[Trajectory]) -> None: + """Invoked by OnlineTrainer after each training step."""
+ + +
+[docs] + async def before_eval_loop(self) -> None: + """Invoked by Evaluator and OnlineTrainer before the evaluation loop."""
+ + +
+[docs] + async def after_eval_step(self, trajectories: Sequence[Trajectory]) -> None: + """Invoked by Evaluator and OnlineTrainer after each evaluation step."""
+ + +
+[docs] + async def after_eval_loop(self) -> None: + """Invoked by Evaluator and OnlineTrainer after the evaluation loop."""
+ + +
+[docs] + async def after_update(self) -> None: + """Invoked by OnlineTrainer after each optimizer.update() call."""
+
+ + + +
+[docs] +class TrajectoryFileCallback(Callback): + """Callback that writes trajectories to a file.""" + + def __init__(self, output_dir: os.PathLike | str): + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + + self.out_files: dict[str, Path] = {} + self.trajs: dict[str, Trajectory] = defaultdict(Trajectory) + + def _make_filename(self, traj_id: str, env: Environment) -> str: + """Create the filename for the output file.""" + return f"{traj_id}.jsonl" + +
+[docs] + async def before_transition( + self, + traj_id: str, + agent: Agent, + env: Environment, + agent_state: Any, + obs: list[Message], + ) -> None: + if traj_id not in self.out_files: + self.out_files[traj_id] = self.output_dir / self._make_filename( + traj_id, env + )
+ + +
+[docs] + async def after_transition( + self, traj_id: str, agent: Agent, env: Environment, transition: Transition + ) -> None: + assert traj_id in self.out_files + traj = self.trajs[traj_id] + traj.steps.append(transition) + # TODO: make this async? + traj.to_jsonl(self.out_files[traj_id])
+ + +
+[docs] + def cleanup(self) -> None: + for out_file in self.out_files.values(): + if out_file.exists(): + out_file.unlink()
+
+ + + +
+[docs] +class RolloutDebugDumpCallback(Callback): + """Dump JSONL files for each agent and environment step to a directory.""" + + def __init__(self, output_dir: os.PathLike | str): + """Initialize. + + Args: + output_dir: Directory to place JSONL files. + """ + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + + self.out_files: dict[str, Path] = {} + + def _get_out_file(self, traj_id: str) -> Path: + if traj_id not in self.out_files: + self.out_files[traj_id] = self.output_dir / f"{traj_id}.jsonl" + return self.out_files[traj_id] + +
+[docs] + async def before_transition( + self, + traj_id: str, + agent: Agent, + env: Environment, + agent_state, + obs: list[Message], + ) -> None: + self.start = time.time()
+ + + def _get_elapsed_time(self, reset: bool = True) -> float: + elapsed = time.time() - self.start + if reset: + self.start = time.time() + return elapsed + +
+[docs] + async def after_agent_get_asv( + self, + traj_id: str, + action: OpResult[ToolRequestMessage], + next_agent_state: Any, + value: float, + ) -> None: + log_jsonl = json.dumps({ + "event": "AGENT_GET_ASV", + "elapsed": self._get_elapsed_time(), + "action": action.value.model_dump(), + "value": value, + }) + async with aiofiles.open(self._get_out_file(traj_id), "a") as f: + await f.write(log_jsonl + "\n")
+ + +
+[docs] + async def after_env_step( + self, traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool + ) -> None: + log_jsonl = json.dumps({ + "event": "ENV_STEP", + "elapsed": self._get_elapsed_time(), + "obs": MessagesAdapter.dump_python(obs), + "reward": reward, + "done": done, + "truncated": trunc, + }) + async with aiofiles.open(self._get_out_file(traj_id), "a") as f: + await f.write(log_jsonl + "\n")
+
+ + + +
+[docs] +class ComputeTrajectoryMetricsMixin: + """Mixin for TaskDataset classes to enable them to compute metrics.""" + + # Tools or tool names to include in trajectory metrics + tools_to_track: Collection[str | Tool] = set() + +
+[docs] + def compute_trajectory_metrics( + self, + trajectories: Sequence[Trajectory], + ) -> dict[str, list[float]]: + metrics: dict[str, list[float]] = { + "reward": [ + sum(step.reward for step in traj.steps) for traj in trajectories + ], + "truncation_rate": [ + sum(step.truncated for step in traj.steps) for traj in trajectories + ], + "avg_value": [ + sum(step.value for step in traj.steps) / len(traj.steps) + for traj in trajectories + ], + "num_steps": [len(traj.steps) for traj in trajectories], + "failures": [traj.failed for traj in trajectories], + } + for tool in self.tools_to_track: # Default of empty set means this is not run + if isinstance(tool, Tool): + tool = tool.info.name + metrics[f"tool_{tool}"] = [ + sum( + sum(tc.function.name == tool for tc in s.action.value.tool_calls) + for s in traj.steps + if isinstance(s.action, OpResult) + ) + for traj in trajectories + ] + return metrics
+
+ + + +
+[docs] +class TrajectoryMetricsCallback(Callback): + """ + Compute metrics that are defined by task datasets. + + NOTE: evaluation portion's after_eval_step/loop() is not concurrency safe because + trajectories should be stored in the order of after_eval_step() calls. + """ + + def __init__( + self, + train_dataset: TaskDataset | None = None, + eval_dataset: TaskDataset | None = None, + track_tool_usage: bool = False, + ): + self._datasets = train_dataset, eval_dataset + self._track_tool_usage = track_tool_usage + for ds in self._datasets: + if ds and not isinstance(ds, ComputeTrajectoryMetricsMixin): + raise ValueError( + f"Dataset {ds} didn't implement" + f" {ComputeTrajectoryMetricsMixin.__name__}, which is required for" + " this callback." + ) + self._train_metrics_fn = ( + train_dataset.compute_trajectory_metrics if train_dataset else None # type: ignore[attr-defined] + ) + self._eval_metrics_fn = ( + eval_dataset.compute_trajectory_metrics if eval_dataset else None # type: ignore[attr-defined] + ) + + self._train_metrics: dict[str, list[float]] | None = None + self._eval_metrics: dict[str, list[float]] = {} + +
+[docs] + async def after_env_reset( + self, traj_id: str, obs: list[Message], tools: list[Tool] + ) -> None: + for ds in (ds for ds in self._datasets if ds): + if self._track_tool_usage: + cast(ComputeTrajectoryMetricsMixin, ds).tools_to_track = { + t.info.name for t in tools + }
+ + +
+[docs] + async def after_train_step(self, trajectories: Sequence[Trajectory]) -> None: + if self._train_metrics_fn is not None: + self._train_metrics = self._train_metrics_fn(trajectories)
+ + +
+[docs] + async def after_eval_step(self, trajectories: Sequence[Trajectory]) -> None: + if self._eval_metrics_fn is not None: + for k, v in self._eval_metrics_fn(trajectories).items(): + if k not in self._eval_metrics: + # Don't use defaultdict - error prone in user code + self._eval_metrics[k] = [] + self._eval_metrics[k].extend(v)
+ + +
+[docs] + async def after_eval_loop(self) -> None: + self._eval_metrics.clear()
+
+ + + +
+[docs] +class MeanMetricsCallback(TrajectoryMetricsCallback): + """Take a mean of all metrics.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._train_means: dict[str, float] | None = None + self._eval_means: dict[str, float] | None = None + +
+[docs] + async def after_train_step(self, trajectories: Sequence[Trajectory]) -> None: + await super().after_train_step(trajectories) + if self._train_metrics is not None: + # may be None if train_dataset was not provided + self._train_means = self._compute_means(self._train_metrics)
+ + +
+[docs] + async def after_eval_loop(self) -> None: + if self._eval_metrics: + # may be empty if eval_dataset was not provided + self._eval_means = self._compute_means(self._eval_metrics) + await super().after_eval_loop()
+ + + @staticmethod + def _compute_means(metrics: dict[str, list[float]]) -> dict[str, float]: + return {k: sum(v) / len(v) for k, v in metrics.items()} + + @property + def train_means(self) -> dict[str, float]: + if self._train_means is None: + raise RuntimeError( + "Training means are only available after this callback is invoked." + ) + return self._train_means + + @property + def eval_means(self) -> dict[str, float]: + if self._eval_means is None: + raise RuntimeError( + "Evaluation means are only available after this callback is invoked." + ) + return self._eval_means
+ + + +
+[docs] +class WandBLoggingCallback(TrajectoryMetricsCallback): + def __init__(self, *args, **kwargs): + if wandb is None: + raise ImportError( + f"{type(self).__name__} processing requires the 'monitor' extra for" + " 'wandb'. Please: `pip install aviary-internal[monitor]`." + ) + super().__init__(*args, **kwargs) + + self._num_train_step = 0 + +
+[docs] + async def after_train_step(self, trajectories: Sequence[Trajectory]) -> None: + await super().after_train_step(trajectories) + self._num_train_step += 1 + + if self._train_metrics is None: + return + + # Each wandb.log() increments the wandb step by 1. Log the training step here + # so we can use it as an x-axis for training metrics that are logged by different + # wandb.log() calls. + wandb.log( + { + f"train/{key}_mean": sum(vals) / len(vals) + for key, vals in self._train_metrics.items() + } + | {"train/step": self._num_train_step} + )
+ + +
+[docs] + async def after_eval_loop(self) -> None: + if not self._eval_metrics: + return + + wandb.log({ + f"eval/{key}_mean": (sum(vals) / len(vals) if vals else None) + for key, vals in self._eval_metrics.items() + }) + + await super().after_eval_loop()
+
+ + + +
+[docs] +class ClearContextCallback(Callback): + def __init__(self, op_names: Iterable[str] | None = None): + self._op_names = op_names + +
+[docs] + async def after_eval_step(self, trajectories: Sequence[Trajectory]) -> None: + OpCtx.clear_contexts(self._op_names)
+ + +
+[docs] + async def after_update(self) -> None: + OpCtx.clear_contexts(self._op_names)
+
+ + + +
+[docs] +class LoggingCallback(MeanMetricsCallback): + """Custom callback for logging filtered metrics (e.g., pass rates) to the console. + + This callback extends the `MeanMetricsCallback` and allows logging of user-specified metrics + after each training step and after the evaluation loop. It calculates the specified metrics + (e.g., pass rates) from the trajectories and logs the results. + """ + + def __init__( + self, + train_dataset: TaskDataset | None = None, + eval_dataset: TaskDataset | None = None, + metrics_to_log: Collection[str] | None = None, + ): + """Initialize the callback with a list of metric keys to log. + + Args: + train_dataset: The training dataset for computing metrics. + eval_dataset: The evaluation dataset for computing metrics. + metrics_to_log: Optional metric names (e.g., ["pass"]) to log. + If left as default of None, all metrics will be logged. + """ + super().__init__(train_dataset, eval_dataset) + self.metrics_to_log = ( + metrics_to_log or set() + ) # If no metrics provided, log all by default + + def _log_filtered_metrics(self, metrics: dict[str, float], step_type: str) -> None: + """Helper function to log only the specified metrics. + + Args: + metrics: Dictionary of calculated means for the current step (e.g., train or eval). + step_type: The type of step (e.g., "Train" or "Eval") for logging purposes. + """ + if self.metrics_to_log: + for metric in self.metrics_to_log: + if metric in metrics: + logger.info( + f"{metric.upper()} RATE ({step_type}): {metrics[metric]:.5f}" + ) + else: + # Log all metrics if no specific ones are provided + logger.info(f"{step_type} Metrics: {metrics}") + +
+[docs] + async def after_train_step(self, trajectories: Sequence[Trajectory]) -> None: + """Log metrics and pass rate after each training step. + + This method is called after every training step, calculating and logging + the training metrics and pass rate. + + Args: + trajectories: A sequence of trajectories from the training step. + """ + await super().after_train_step(trajectories) # Call the parent to compute means + if self.train_means: + self._log_filtered_metrics(self.train_means, step_type="Train")
+ + +
+[docs] + async def after_eval_loop(self) -> None: + """Log metrics and pass rate after the evaluation loop. + + This method is called after the evaluation loop finishes, calculating and logging + the evaluation metrics and pass rate. + """ + await super().after_eval_loop() # Call the parent to compute means + if self.eval_means: + self._log_filtered_metrics(self.eval_means, step_type="Eval")
+
+ + + +
+[docs] +class TerminalPrintingCallback(Callback): + """Callback that prints action, observation, and timing information to the terminal.""" + + def __init__(self): + self.start_time = None + # try now, rather than start running and die + try: + from rich.pretty import pprint # noqa: F401 + except ImportError as e: + raise ImportError( + f"rich is required for {type(self).__name__}. Please install it with `pip install rich`." + ) from e + +
+[docs] + async def before_transition( + self, + traj_id: str, + agent: Agent, + env: Environment, + agent_state: Any, + obs: list[Message], + ) -> None: + """Start the timer before each transition.""" + self.start_time = time.time()
+ + +
+[docs] + async def after_agent_get_asv( + self, + traj_id: str, + action: OpResult[ToolRequestMessage], + next_agent_state: Any, + value: float, + ) -> None: + from rich.pretty import pprint + + print("\nAction:") + pprint(action.value, expand_all=True)
+ + +
+[docs] + async def after_env_step( + self, traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool + ) -> None: + from rich.pretty import pprint + + # Compute elapsed time + if self.start_time is not None: + elapsed_time = time.time() - self.start_time + self.start_time = None # Reset timer + else: + elapsed_time = 0.0 + print("\nObservation:") + pprint(obs, expand_all=True) + print(f"Elapsed time: {elapsed_time:.2f} seconds")
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/datasets.html b/docs/_build/html/_modules/ldp/alg/datasets.html new file mode 100644 index 00000000..cb2f59a5 --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/datasets.html @@ -0,0 +1,114 @@ + + + + + + + ldp.alg.datasets — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.datasets

+from aviary.env import TASK_DATASET_REGISTRY
+from aviary.env import DummyTaskDataset as _DummyTaskDataset
+
+from .callbacks import ComputeTrajectoryMetricsMixin
+
+
+
+[docs] +class DummyTaskDataset(_DummyTaskDataset, ComputeTrajectoryMetricsMixin): + pass
+ + + +TASK_DATASET_REGISTRY["dummy"] = "ldp.alg.datasets", "DummyTaskDataset" +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/optimizer.html b/docs/_build/html/_modules/ldp/alg/optimizer.html new file mode 100644 index 00000000..30aa6a46 --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/optimizer.html @@ -0,0 +1,194 @@ + + + + + + + ldp.alg.optimizer — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.optimizer

+from typing import Any, cast
+
+from pydantic import BaseModel, ConfigDict, Field
+
+from ldp.agent import Agent, MemoryAgent, ReActAgent
+from ldp.alg.optimizer.ape import APEOpt, APEScoreFn
+from ldp.alg.optimizer.memory import MemoryFactory, MemoryOpt, PositiveMemoryOpt
+from ldp.alg.optimizer.opt import _OPTIMIZER_REGISTRY, ChainedOptimizer, Optimizer
+
+_DEFAULT_OPTIMIZER_ERROR_MSG = (
+    "Didn't yet implement an optimizer of type {opt_type} for {agent_type}."
+)
+AUTOSELECT_BEST_OPTIMIZER = None
+
+
+
+[docs] +class OptimizerConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + optimizer_type: str | None = AUTOSELECT_BEST_OPTIMIZER + optimizer_kwargs: dict[str, Any] = Field(default_factory=dict)
+ + + +_DEFAULT_OPTIMIZER_MAP: dict[type[Agent], type[Optimizer]] = { + MemoryAgent: MemoryOpt, + ReActAgent: APEOpt, +} + + +
+[docs] +def default_optimizer_factory( + agent: Agent, + optimizer_cls: str | type[Optimizer] | None = AUTOSELECT_BEST_OPTIMIZER, + **optimizer_kwargs, +) -> Optimizer: + """A method that constructs a default optimizer for commonly-used agents. + + Args: + agent: Agent to construct the optimizer for. + optimizer_cls: The optimizer class to use. If not specified, we will try a + default based on the provided agent. + optimizer_kwargs: Arguments forwarded to optimizer_cls. + + Returns: + Instantiated optimizer. + """ + if isinstance(optimizer_cls, str): + try: + optimizer_cls = _OPTIMIZER_REGISTRY[optimizer_cls] + except KeyError: + raise TypeError( + f"Optimizer class not supported by default_optimizer_factory: {optimizer_cls}" + ) from None + + if optimizer_cls is None: + optimizer_cls = _DEFAULT_OPTIMIZER_MAP.get(agent.__class__) + + # convince mypy that optimizer_cls is a type from here on + optimizer_cls = cast(type, optimizer_cls) + + if isinstance(agent, MemoryAgent): + if optimizer_cls != MemoryOpt: + raise NotImplementedError( + _DEFAULT_OPTIMIZER_ERROR_MSG.format( + opt_type=optimizer_cls.__name__, agent_type=MemoryAgent.__name__ + ) + ) + return MemoryOpt.from_agent(agent, **optimizer_kwargs) + if isinstance(agent, ReActAgent): + if optimizer_cls != APEOpt: + raise NotImplementedError( + _DEFAULT_OPTIMIZER_ERROR_MSG.format( + opt_type=optimizer_cls.__name__, agent_type=ReActAgent.__name__ + ) + ) + return APEOpt.from_agent(agent, **optimizer_kwargs) + raise TypeError(f"Unsupported agent type: {agent.__class__.__name__}")
+ + + +__all__ = [ + "APEOpt", + "APEScoreFn", + "ChainedOptimizer", + "MemoryFactory", + "MemoryOpt", + "Optimizer", + "OptimizerConfig", + "PositiveMemoryOpt", + "default_optimizer_factory", +] +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/optimizer/ape.html b/docs/_build/html/_modules/ldp/alg/optimizer/ape.html new file mode 100644 index 00000000..a8c456d9 --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/optimizer/ape.html @@ -0,0 +1,428 @@ + + + + + + + ldp.alg.optimizer.ape — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.optimizer.ape

+from __future__ import annotations
+
+import asyncio
+import logging
+from collections import UserDict
+from enum import StrEnum, auto
+from typing import Any, Self, cast
+
+from aviary.message import Message
+from pydantic import (
+    BaseModel,
+    ConfigDict,
+    Field,
+    JsonValue,
+    RootModel,
+    ValidationError,
+    model_validator,
+)
+
+from ldp.agent import ReActAgent
+from ldp.alg.optimizer.opt import Optimizer
+from ldp.data_structures import Trajectory
+from ldp.graph import LLMCallOp, OpResult, PromptOp
+from ldp.llms import LLMModel, LLMResult
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class APEScoreFn(StrEnum): + # Use the reward as the APE score (as proposed in the paper). + # Goal is to maximize this score. + REWARD = auto() + # Use the gradient of the output of the PromptOp as the APE score. + # Goal is to push this to zero. + GRADIENT = auto()
+ + + +class _FormatDict(UserDict): + """Custom dictionary that stores missing items.""" + + def __init__(self) -> None: + super().__init__() + self.key_set: set[str] = set() + + def __missing__(self, key: str) -> str: + self.key_set.add(key) + return key + + +
+[docs] +def get_formatted_variables(s: str) -> set[str]: + """Returns the set of variables implied by the format string.""" + format_dict = _FormatDict() + s.format_map(format_dict) + return format_dict.key_set
+ + + +
+[docs] +class OutputPrompt(BaseModel): + prompt: str = Field(description="Prompt for language model")
+ + + +
+[docs] +class Example(BaseModel): + input: JsonValue + output: JsonValue + score: float
+ + + +ExampleList = RootModel[list[Example]] + + +
+[docs] +class APEOpt(BaseModel, Optimizer): + """ + Basic optimizer that acts as an Automatic Prompt Engineer (APE). + + Paper: https://openreview.net/pdf?id=92gvk82DE- + + Details: + - This implements the "forward mode generation" strategy. + - The score function used is the gradient (float) at the output of the + PromptOp being optimized. A zero gradient means the prompt was "good", + and a non-zero gradient means we can learn from the prompt. + - Possible improvements include: + - Extending the score function to the LLM result's logprobs + - Iterating with Monte Carlo Search + - Use of memory for further example augmentation + """ + + model_config = ConfigDict(arbitrary_types_allowed=True) + + ### Configuration + max_examples: int | None = Field( + default=50, # Comes from APE paper section 5.2 + description=( + "Max number of examples to include in the below query_prompt, or None for" + " no limit. The paper mentions that more examples produce better prompt" + " proposals." + ), + ) + system_prompt: str = ( + "We are optimizing prompts for a language model." + " The model sees a prompt, an input, and then generates an output." + ) + query_prompt: str = ( + "Here are correct example outputs that the language model and prompt should produce:" + "\n{good_examples}" + '\n\nThe current prompt is: "{prompt}"' + "\n\nWhich resulted in the following incorrect input, output, and {score}:" + "\n{examples}" + "\n\nRevise the current prompt to improve the outputs." + " Your proposed prompt should be concise, correct, and specify the desired output format." + ) + llm: LLMModel = Field( + default_factory=LLMModel, + description=( + "LLM used to update the prompt inside the PromptOp. The paper mentions that" + " larger models produce better prompt proposals." + ), + ) + + prompt_op: PromptOp = Field(description="PromptOp to be optimized.") + llm_call_op: LLMCallOp = Field(description="LLMCallOp to be optimized.") + + score_fn: APEScoreFn = APEScoreFn.REWARD + good_reward_threshold: float | None = Field( + default=None, + description="If using reward as the score_fn, then a good example is defined by " + "reward>=good_reward_threshold.", + ) + reward_discount: float = 1.0 + + ### State + examples: list[Example] = Field(default_factory=list) + good_examples: list[Example] = Field(default_factory=list) + steps: int = 0 + trace: list[str] = Field( + default_factory=list, description="History of prompts used." + ) + +
+[docs] + @model_validator(mode="after") + def validate_score_fn(self): + if self.score_fn == APEScoreFn.REWARD: + if self.good_reward_threshold is None: + raise ValueError( + "good_reward_threshold must be set if using reward as the score function" + ) + self._score_str = "rewards" + elif self.score_fn == APEScoreFn.GRADIENT: + # The gradient into the prompt op is the (signed) backpropagated error, and "gradient" would + # be confusing to the model in the prompt. + self._score_str = "errors" + else: + raise ValueError(f"Invalid score function {self.score_fn}") + + return self
+ + +
+[docs] + def model_post_init(self, __context: Any) -> None: + if self.prompt_op.prompt not in self.trace: + self.trace.append(self.prompt_op.prompt) + + # Make sure updates are not run concurrently + self._update_lock = asyncio.Lock()
+ + +
+[docs] + @classmethod + def from_agent(cls, agent: ReActAgent, **kwargs) -> Self: + return cls( + llm_call_op=agent._react_module.tool_select_module.llm_call_op, + prompt_op=agent._react_module.prompt_op, + **kwargs, + )
+ + +
+[docs] + def aggregate_trajectory(self, trajectory: Trajectory) -> None: + if trajectory.failed: + return + + if self.score_fn == APEScoreFn.REWARD: + d_returns = trajectory.compute_discounted_returns(self.reward_discount) + + for i_step, step in enumerate(trajectory.steps): + action_call_id = cast(OpResult, step.action).call_id + llm_call_ids = self.llm_call_op.get_call_ids({action_call_id.run_id}) + + if self.score_fn == APEScoreFn.GRADIENT: + prompt_call_id, *extra_prompt_call_ids = self.prompt_op.get_call_ids({ + action_call_id.run_id + }) + # TODO: loosen this restriction once grad acc/topological traversal are done + assert ( + not extra_prompt_call_ids + ), "APE only supports one prompt call per run" + + for llm_call_id in llm_call_ids: + result = cast( + LLMResult | None, + self.llm_call_op.ctx.get(llm_call_id, "result"), + ) + if result is None or not result.messages or not result.prompt: + continue + # (x: first prompt's user message's content, y: AI response's content) + x = next( + cast(str, m.content) for m in result.prompt if m.role == "user" + ) + y = cast(str, result.messages[0].content) + + if self.score_fn == APEScoreFn.GRADIENT: + score = self.prompt_op.ctx.get( + prompt_call_id, "grad_output", default=None + ) + if score is None: + # backprop did not reach this op call - move on + continue + is_good = score == 0 + else: + score = d_returns[i_step] # pylint: disable=possibly-used-before-assignment + is_good = score >= cast(float, self.good_reward_threshold) + + example = Example(input=x, output=y, score=score) + (self.good_examples if is_good else self.examples).append(example)
+ + +
+[docs] + async def update(self) -> None: + async with self._update_lock: + if not self.examples: + raise ValueError("No examples to update the prompt with.") + + new_p = await self._get_updated_prompt( + self.examples, self.good_examples, self.prompt_op.prompt + ) + # Check any template vars remain, and if some were added or + # lost, discard this new prompt + if new_p != self.prompt_op.prompt and get_formatted_variables( + new_p + ) != get_formatted_variables(self.prompt_op.prompt): + logger.warning( + "Update broke prompt templating." + f"\n\nNew prompt:\n{new_p}" + f"\n\nPrior prompt:\n{self.prompt_op.prompt}" + ) + else: + if new_p == self.prompt_op.prompt: + logger.warning("Update did not change the prompt.") + self.examples.clear() + self.prompt_op.prompt = new_p + self.trace.append(new_p) + self.steps += 1
+ + + def _prepare_examples(self, examples: list[Example]) -> str: + if not examples: + return "" + if self.max_examples and len(examples) > self.max_examples: + if self.score_fn == APEScoreFn.GRADIENT: + # Return examples closest to decision boundary, + # aka ones with the lowest L1-normalized error + # NOTE: this pairs with our setting of Example.score = PromptOp's output + # gradient inside the update method, so examples with error values closer to + # 0 are defined to be higher quality + examples = sorted(examples, key=lambda e: abs(e.score))[ + : self.max_examples + ] + else: + # In reward mode, we want to show the examples with the highest reward, per the paper + # TODO: consider whether uniform sampling is better + examples = sorted(examples, key=lambda e: -e.score)[: self.max_examples] + return ExampleList.model_validate(examples).model_dump_json() + + async def _get_updated_prompt( + self, examples: list[Example], good_examples: list[Example], prompt: str + ) -> str: + messages = [ + Message( + role="system", + content=self.system_prompt, + ), + Message( + role="user", + content=self.query_prompt.format( + examples=self._prepare_examples(examples), + good_examples=self._prepare_examples(good_examples), + prompt=prompt, + score=self._score_str, + ), + ), + Message( + role="assistant", + content=OutputPrompt(prompt=prompt).model_dump_json(indent=2), + ), + Message( + content=( + "You responded without changing the prompt. Don't forget to revise" + " the prompt." + ) + ), + ] + result = await self.llm.call(messages, output_type=OutputPrompt) + message_content = cast(str, cast(list[Message], result.messages)[-1].content) + try: + return OutputPrompt.model_validate_json(message_content).prompt + except ValidationError: + return prompt
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/optimizer/memory.html b/docs/_build/html/_modules/ldp/alg/optimizer/memory.html new file mode 100644 index 00000000..d4f155fb --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/optimizer/memory.html @@ -0,0 +1,285 @@ + + + + + + + ldp.alg.optimizer.memory — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.optimizer.memory

+from __future__ import annotations
+
+import logging
+from collections.abc import Iterable
+from itertools import product
+from typing import ClassVar, Protocol, Self, cast, runtime_checkable
+
+from pydantic import BaseModel, ConfigDict, Field, JsonValue
+
+from ldp.agent import MemoryAgent
+from ldp.alg.optimizer.opt import Optimizer
+from ldp.data_structures import Trajectory
+from ldp.graph import CallID, Memory, MemoryOp, Op, OpResult
+from ldp.graph.ops import TOutput
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +@runtime_checkable +class MemoryFactory(Protocol): + async def __call__( + self, + memory_op: MemoryOp, + output_op: Op[TOutput], + memory_template: str, + example_buffer: Iterable[tuple[CallID, CallID, float, JsonValue]], + ) -> list[Memory]: + """ + Create new memories from the example buffer. + + Args: + memory_op: MemoryOp whose context contains the MemoryModel's query and input. + output_op: Op whose context contains an output that can be correlated with + how good the outcome was. + memory_template: Template used for the Memory's string representation. + example_buffer: Buffer of 4-tuples containing the memory_op's call ID, the + output_op's call ID, the current discounted return, and arbitrary JSON + metadata (which can be used to add task-specific metadata the memory). + + Returns: + New Memories created. + """
+ + + +async def _default_memory_factory( + memory_op: MemoryOp, + output_op: Op[TOutput], + memory_template: str, + example_buffer: Iterable[tuple[CallID, CallID, float, JsonValue]], +) -> list[Memory]: + return [ + Memory.from_ops( + memory_op, + mem_call_id, + output_op, + output_call_id, + d_return, + template=memory_template, + metadata=metadata, + ) + for mem_call_id, output_call_id, d_return, metadata in example_buffer + ] + + +
+[docs] +class MemoryOpt(BaseModel, Optimizer): + """Trainer for memory agents. By default it is a minimizer. + + This optimizer simply adds memories to the MemoryOp using a memory factory. + """ + + model_config = ConfigDict(arbitrary_types_allowed=True) + + # Working around https://github.com/pydantic/pydantic/issues/10551 + default_memory_factory: ClassVar[MemoryFactory] = _default_memory_factory + + ### Configuration + memory_op: MemoryOp + output_op: Op + reward_discount: float = 1.0 + memory_factory: MemoryFactory = Field( + default=default_memory_factory, + description=( + "Async function to make Memories from an example buffer. It's async so this" + " can involve an LLM completion if desired." + ), + exclude=True, + ) + memory_template: str = Field( + default="Input: {input}\nOutput: {output}\nReward: {value}", + description="Template for a Memory's string representation.", + ) + + ### State + steps: int = 0 + example_buffer: list[tuple[CallID, CallID, float, JsonValue]] = Field( + default_factory=list + ) + +
+[docs] + @classmethod + def from_agent(cls, agent: MemoryAgent, **kwargs) -> Self: + return cls(memory_op=agent._memory_op, output_op=agent._llm_call_op, **kwargs)
+ + + def _memory_filter( + self, call_id: CallID, memory_op: MemoryOp, d_return: float + ) -> bool: + # only keep memories that backprop reached, i.e. those that were used in + # achieving the reward + return memory_op.ctx.get(call_id, "grad_output", default=None) is not None + +
+[docs] + def aggregate_trajectory(self, trajectory: Trajectory) -> None: + # NOTE: this is a little dangerous. This optimizer currently + # does not check which memory op calls are upstream of output op calls, + # besides making sure they belong to the same run. + # This is not a problem if we have no branching in the compute graph + # between the memory op and the *final* output op. + # TODO: fix the above using OpResult.traverse() to find the upstream calls + + if trajectory.failed: + return + + d_returns = trajectory.compute_discounted_returns(self.reward_discount) + + for step, d_return in zip(trajectory.steps, d_returns, strict=True): + output_run_id = cast(OpResult, step.action).call_id.run_id + mem_call_ids = { + m + for m in self.memory_op.get_call_ids({output_run_id}) + if self._memory_filter(m, self.memory_op, d_return) + } + output_call_ids = self.output_op.get_call_ids({output_run_id}) + if len(mem_call_ids) > 1 and len(output_call_ids) > 1: + raise ValueError( + "Multiple memory or output calls in a single run - this violates" + " our 1-1 correspondence assumption." + ) + + self.example_buffer.extend( + ( + *x, + d_return, + { + "timestep": step.timestep, + "done": step.done, + "truncated": step.truncated, + }, + ) + for x in product(mem_call_ids, output_call_ids) + )
+ + +
+[docs] + async def update(self) -> None: + """Create new memories from the example buffer and add them to MemoryOp.""" + for memory in await self.memory_factory( # pylint: disable=too-many-function-args + self.memory_op, self.output_op, self.memory_template, self.example_buffer + ): + await self.memory_op.memory_model.add_memory(memory) + self.steps += 1 + self.example_buffer.clear()
+
+ + + +
+[docs] +class PositiveMemoryOpt(MemoryOpt): + def _memory_filter( + self, call_id: CallID, memory_op: MemoryOp, d_return: float + ) -> bool: + # only keep positive memories + return d_return > 0 and super()._memory_filter(call_id, memory_op, d_return)
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/optimizer/opt.html b/docs/_build/html/_modules/ldp/alg/optimizer/opt.html new file mode 100644 index 00000000..8b01f57b --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/optimizer/opt.html @@ -0,0 +1,185 @@ + + + + + + + ldp.alg.optimizer.opt — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.optimizer.opt

+from __future__ import annotations
+
+import logging
+from abc import ABC, abstractmethod
+from collections.abc import Iterable
+
+from ldp.data_structures import Trajectory
+from ldp.shims import tqdm
+
+logger = logging.getLogger(__name__)
+
+
+# Registry for all optimizers
+_OPTIMIZER_REGISTRY: dict[str, type[Optimizer]] = {}
+
+
+
+[docs] +class Optimizer(ABC): + """Base class for all optimizers.""" + + def __init_subclass__(cls) -> None: + # Register each optimizer subclass + _OPTIMIZER_REGISTRY[cls.__name__] = cls + return super().__init_subclass__() + +
+[docs] + def aggregate( + self, trajectories: Iterable[Trajectory], show_pbar: bool = False + ) -> None: + """Aggregate trajectories to construct training samples.""" + trajectories_with_pbar = tqdm( + trajectories, + desc="Aggregating trajectories", + ncols=0, + mininterval=1, + disable=not show_pbar, + ) + for trajectory in trajectories_with_pbar: + self.aggregate_trajectory(trajectory)
+ + +
+[docs] + @abstractmethod + def aggregate_trajectory(self, trajectory: Trajectory) -> None: + """Aggregate transitions from a single trajectory to construct training samples."""
+ + +
+[docs] + @abstractmethod + async def update(self) -> None: + """Update the model based on the aggregated samples."""
+
+ + + +
+[docs] +class ChainedOptimizer(Optimizer): + """An optimizer that runs a sequence of sub-optimizers in the order they are provided.""" + + def __init__(self, *optimizers: Optimizer): + self.optimizers = optimizers + +
+[docs] + def aggregate( + self, trajectories: Iterable[Trajectory], show_pbar: bool = False + ) -> None: + for optimizer in self.optimizers: + optimizer.aggregate(trajectories, show_pbar=show_pbar)
+ + +
+[docs] + async def update(self) -> None: + for optimizer in self.optimizers: + await optimizer.update()
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/optimizer/replay_buffers.html b/docs/_build/html/_modules/ldp/alg/optimizer/replay_buffers.html new file mode 100644 index 00000000..904db5f8 --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/optimizer/replay_buffers.html @@ -0,0 +1,145 @@ + + + + + + + ldp.alg.optimizer.replay_buffers — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.optimizer.replay_buffers

+import random
+from collections import UserList
+
+
+
+[docs] +class CircularReplayBuffer(UserList[dict]): +
+[docs] + def resize(self, size: int): + if len(self) > size: + self.data = self.data[-size:]
+ + +
+[docs] + def batched_iter( + self, batch_size: int, shuffle: bool = True, infinite: bool = False + ): + while True: + indices = list(range(len(self))) + if shuffle: + random.shuffle(indices) + + for i in range(0, len(self), batch_size): + keys = self.data[0].keys() + + batch: dict[str, list] = {k: [] for k in keys} + for j in indices[i : i + batch_size]: + if self.data[j].keys() != keys: + raise RuntimeError( + "Found buffer element with inconsistent keys" + ) + + for k in keys: + batch[k].append(self.data[j][k]) + + yield batch + + if not infinite: + break
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/rollout.html b/docs/_build/html/_modules/ldp/alg/rollout.html new file mode 100644 index 00000000..56a34b41 --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/rollout.html @@ -0,0 +1,435 @@ + + + + + + + ldp.alg.rollout — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.rollout

+import asyncio
+import itertools
+import logging
+import uuid
+from collections.abc import Callable, Iterator, Sequence
+from contextlib import contextmanager, nullcontext
+from typing import Any, TypeVar, overload
+
+from aviary.env import Environment
+from aviary.message import Message
+
+from ldp.agent import Agent
+from ldp.data_structures import Trajectory, Transition
+
+from .callbacks import Callback
+
+logger = logging.getLogger(__name__)
+
+
+TEnv = TypeVar("TEnv", bound=Environment)
+
+
+
+[docs] +class CaughtError(Exception): + """Base class for reraised exceptions when catching is enabled.""" + + def __init__(self, original_exc: Exception): + self.original_exc = original_exc + + exc_type = "undefined"
+ + + +
+[docs] +class AgentError(CaughtError): + exc_type = "agent"
+ + + +
+[docs] +class EnvError(CaughtError): + exc_type = "env"
+ + + +
+[docs] +@contextmanager +def reraise_exc_as(reraise: type[CaughtError], enabled: bool) -> Iterator[None]: + try: + yield + except Exception as e: + if enabled: + logging.exception(f"Caught {reraise.exc_type} exception.") + raise reraise(e) from e + raise
+ + + +
+[docs] +class RolloutManager: + def __init__( + self, + agent: Agent, + catch_agent_failures: bool = True, + catch_env_failures: bool = True, + callbacks: Sequence[Callback] | None = None, + concurrency_limit: int | None = None, + ): + self.agent = agent + + self.catch_agent_failures = catch_agent_failures + self.catch_env_failures = catch_env_failures + + self.concurrency_limiter = ( + asyncio.Semaphore(concurrency_limit) if concurrency_limit else nullcontext() + ) + + self.traj_buffer: dict[str, Trajectory] = {} + self.callbacks = callbacks or [] + + @overload + async def sample_trajectories( # noqa: D418 + self, + environment_factory: Callable[[], TEnv], + batch_size: int = 1, + max_steps: int | None = None, + ) -> list[tuple[Trajectory, TEnv]]: + """Run rollouts in parallel, using a factory to construct environments. + + We will construct `batch_size` environments and run rollouts on each of them. + If `max_steps` is set, rollouts will be truncated at this value. If a rollout + has fewer than `max_steps`, then a new environment will be constructed and another + rollout will be started until `max_steps` is reached. + + Args: + environment_factory: A no-argument callable that returns + an environment instance + batch_size (int, optional): Defaults to 1. + max_steps (int | None, optional): Max steps per rollout. Defaults to None (see above). + + Returns: + list[tuple[Trajectory, Environment]]: A list of (trajectory, environment) tuples: one per rollout. + """ + + @overload + async def sample_trajectories( # noqa: D418 + self, + environments: Sequence[Environment], + max_steps: int | None = None, + ) -> list[Trajectory]: + """Run rollouts in parallel on a list of provided environments. + + Args: + environments: A list of environments to run rollouts on. + max_steps: Max steps per rollout. Defaults to None, in which case the rollouts are run + until environment returns done. + """ + +
+[docs] + async def sample_trajectories(self, **kwargs): + if "environment_factory" in kwargs: + assert ( + "environments" not in kwargs + ), "Cannot use environment_factory with environments" + + return await self._sample_trajectories_from_env_factory( + kwargs["environment_factory"], + kwargs.get("batch_size", 1), + kwargs.get("max_steps"), + ) + + if "environments" in kwargs: + assert ( + "environment_factory" not in kwargs + ), "Cannot use environments with environment_factory" + return await self._sample_trajectories_from_envs( + kwargs["environments"], kwargs.get("max_steps") + ) + + raise TypeError( + "sample_trajectories() missing required " + "arguments 'environment_factory' or 'environments'" + )
+ + + async def _sample_trajectories_from_env_factory( + self, + environment_factory: Callable[[], Environment], + batch_size: int = 1, + max_steps: int | None = None, + ) -> list[tuple[Trajectory, Environment]]: + self.traj_buffer.clear() + + async def rollout_with_args(idx: int, **rollout_kwargs): + return idx, await self._rollout(**rollout_kwargs), rollout_kwargs + + accumulated_steps = [0] * batch_size + # submit initial batch of tasks + tasks = [ + asyncio.create_task( + rollout_with_args( + idx, + traj_id=uuid.uuid4().hex, + env=environment_factory(), + max_steps=max_steps, + ) + ) + for idx in range(batch_size) + ] + + results = [] + while tasks: + done, pending = await asyncio.wait( + tasks, return_when=asyncio.FIRST_COMPLETED + ) + new_tasks = [] + for task in done: + idx, traj, kwargs = await task + results.append((traj, kwargs["env"])) + accumulated_steps[idx] += len(traj.steps) + if ( + max_steps is not None + and (remaining_steps := max_steps - accumulated_steps[idx]) > 0 + ): + # submit another task if we haven't reached max_steps + new_task = asyncio.create_task( + rollout_with_args( + idx, + traj_id=uuid.uuid4().hex, + env=environment_factory(), + max_steps=remaining_steps, + ) + ) + new_tasks.append(new_task) + + tasks = list(pending) + new_tasks + + return results + + async def _sample_trajectories_from_envs( + self, + environments: Sequence[Environment], + max_steps: int | None = None, + ) -> list[Trajectory]: + self.traj_buffer.clear() + + traj_ids = [uuid.uuid4().hex for _ in range(len(environments))] + await asyncio.gather( + *( + self._rollout(*args, max_steps=max_steps) + for args in zip(traj_ids, environments, strict=True) + ) + ) + return [self.traj_buffer[traj_id] for traj_id in traj_ids] + + async def _rollout( + self, + traj_id: str, + env: Environment, + max_steps: int | None, + ) -> Trajectory: + trajectory = Trajectory(traj_id=traj_id) + + async def store_step(step: Transition): + await asyncio.gather(*[ + callback.after_transition(traj_id, self.agent, env, step) + for callback in self.callbacks + ]) + trajectory.steps.append(step) + + # Set default values to store in the buffer in case reset/init_state fail + obs: list[Message] = [] + agent_state: Any = None + + try: + with reraise_exc_as(EnvError, enabled=self.catch_env_failures): + obs, tools = await env.reset() + await asyncio.gather(*[ + c.after_env_reset(traj_id, obs, tools) for c in self.callbacks + ]) + + with reraise_exc_as(AgentError, enabled=self.catch_agent_failures): + agent_state = await self.agent.init_state(tools) + await asyncio.gather(*[ + c.after_agent_init_state(traj_id, agent_state) for c in self.callbacks + ]) + + for timestep in itertools.count(): + step = await self._take_step(timestep, traj_id, env, agent_state, obs) + + if timestep + 1 == max_steps and not step.done: + # Mark as truncated if we hit max_steps and the state is not terminal. + # Do it before store_step(), so that callbacks can access this info + step.truncated = True + + # We assume the below won't throw a CaughtError + await store_step(step) + + # set things up for the next iteration + agent_state = step.next_agent_state + obs = step.next_observation + + if step.done or step.truncated: + break + + except CaughtError as e: + # NOTE: This trajectory should not be used for regular training. + # We save the last transition here for debugging, etc. + await store_step( + Transition( + timestep=len(trajectory.steps), + agent_state=agent_state, + next_agent_state=None, + observation=obs, + next_observation=[], + action=None, + done=True, + metadata={"exception": repr(e.original_exc)}, + ) + ) + + self.traj_buffer[traj_id] = trajectory + return trajectory + + async def _take_step( + self, + timestep: int, + traj_id: str, + env: Environment, + agent_state: Any, + obs: list[Message], + ) -> Transition: + async with self.concurrency_limiter: + await asyncio.gather(*[ + callback.before_transition(traj_id, self.agent, env, agent_state, obs) + for callback in self.callbacks + ]) + + with reraise_exc_as(AgentError, enabled=self.catch_agent_failures): + ( + action, + next_agent_state, + value, + ) = await self.agent.get_asv(agent_state, obs) + await asyncio.gather(*[ + callback.after_agent_get_asv(traj_id, action, next_agent_state, value) + for callback in self.callbacks + ]) + + with reraise_exc_as(EnvError, enabled=self.catch_env_failures): + next_obs, reward, done, trunc = await env.step(action.value) + await asyncio.gather(*[ + callback.after_env_step(traj_id, next_obs, reward, done, trunc) + for callback in self.callbacks + ]) + + return Transition( + timestep=timestep, + agent_state=agent_state, + next_agent_state=next_agent_state, + action=action, + reward=reward, + value=value, + observation=obs, + next_observation=next_obs, + done=done, + truncated=trunc, + )
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/runners.html b/docs/_build/html/_modules/ldp/alg/runners.html new file mode 100644 index 00000000..181c2d0b --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/runners.html @@ -0,0 +1,482 @@ + + + + + + + ldp.alg.runners — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.runners

+from __future__ import annotations
+
+import asyncio
+import math
+import random
+from collections.abc import Sequence
+from typing import cast
+
+from aviary.env import Environment, TaskDataset
+from pydantic import BaseModel, ConfigDict, Field
+
+from ldp.agent import Agent
+from ldp.alg.optimizer import Optimizer
+from ldp.data_structures import Trajectory
+from ldp.graph import OpResult, eval_mode, train_mode
+from ldp.shims import tqdm, trange
+
+from .callbacks import Callback, ClearContextCallback
+from .rollout import RolloutManager
+
+
+async def _run_eval_loop(
+    dataset: TaskDataset,
+    rollout_manager: RolloutManager,
+    batch_size: int,
+    num_iterations: int | None,
+    max_rollout_steps: int | None,
+    callbacks: Sequence[Callback],
+    shuffle: bool = False,
+) -> None:
+    await asyncio.gather(*[callback.before_eval_loop() for callback in callbacks])
+
+    if num_iterations is None:
+        try:
+            num_iterations = math.ceil(len(dataset) / batch_size)
+        except TypeError:
+            raise ValueError(
+                "If num_iterations is not provided, the "
+                "dataset must be finite and implement __len__."
+            ) from None
+    if not num_iterations:
+        return
+
+    with tqdm(
+        desc="Evaluation Iterations", ncols=0, total=num_iterations, leave=False
+    ) as pbar:
+        # We use pbar.n as a counter for the number of training steps
+        while pbar.n < num_iterations:
+            for batch in dataset.iter_batches(batch_size, shuffle=shuffle):
+                trajectories = await rollout_manager.sample_trajectories(
+                    environments=batch, max_steps=max_rollout_steps
+                )
+
+                # Close the environment after we have sampled from it,
+                # in case it needs to tear down resources.
+                await asyncio.gather(*(env.close() for env in batch))
+
+                await asyncio.gather(*[
+                    callback.after_eval_step(trajectories) for callback in callbacks
+                ])
+                pbar.update()
+
+                if pbar.n == num_iterations:
+                    break
+
+    await asyncio.gather(*[callback.after_eval_loop() for callback in callbacks])
+
+
+
+[docs] +class EvaluatorConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + batch_size: int = 1 + num_eval_iterations: int | None = Field( + None, + description="Number of eval iterations. " + "If not provided, will exhaust the dataset. " + "If 0, will not run the eval loop. ", + ) + max_rollout_steps: int | None = None + catch_agent_failures: bool = True + catch_env_failures: bool = True + clear_ctx_at_each_iter: bool = False + +
+[docs] + def make_rollout_manager( + self, agent: Agent, callbacks: Sequence[Callback] + ) -> RolloutManager: + return RolloutManager( + agent=agent, + callbacks=callbacks, + catch_agent_failures=self.catch_agent_failures, + catch_env_failures=self.catch_env_failures, + )
+
+ + + +
+[docs] +class Evaluator: + def __init__( + self, + config: EvaluatorConfig, + agent: Agent, + dataset: TaskDataset, + callbacks: Sequence[Callback] | None = None, + ): + self.config = config + self.agent = agent + self.dataset = dataset + self.callbacks = callbacks or [] + if self.config.clear_ctx_at_each_iter: + clear_cb = ClearContextCallback() + self.callbacks = [*self.callbacks, clear_cb] if callbacks else [clear_cb] + self.rollout_manager = self.config.make_rollout_manager(agent, self.callbacks) + + @eval_mode() + async def evaluate(self, **kwargs) -> None: + """Run the agent over the provided dataset in eval mode.""" + return await self.run(**kwargs) + +
+[docs] + async def run(self, **kwargs) -> None: + """Run the agent over the provided dataset. + + This method does not set training mode, so it can be used to collect + trajectories for offline training. + """ + await _run_eval_loop( + dataset=self.dataset, + rollout_manager=self.rollout_manager, + batch_size=self.config.batch_size, + num_iterations=self.config.num_eval_iterations, + max_rollout_steps=self.config.max_rollout_steps, + callbacks=self.callbacks, + **kwargs, + )
+
+ + + +
+[docs] +class OnlineTrainerConfig(EvaluatorConfig): + batch_size: int + num_train_iterations: int = Field( + ge=0, + description=( + "Number of iterations (at one batch per iteration) to process during" + " training, and setting to 0 skips training." + ), + ) + num_rollouts_per_env: int = Field( + default=1, + description=( + "Number of rollouts to execute for each environment per training iteration." + ), + ) + update_every: int = Field( + default=1, + description="Number of training iterations between optimizer update calls.", + ge=1, + ) + eval_every: int | None = Field( + None, + description=( + "If set, will repeatedly evaluate on the validation set after this many" + " iterations. If unset (default), no evaluation is performed." + ), + ) + eval_before: bool = Field( + default=True, + description=( + "If True (default), evaluate on the validation set before kicking off" + " training." + ), + ) + clear_ctx_at_each_iter: bool = False
+ + + +
+[docs] +class OnlineTrainer: + def __init__( + self, + config: OnlineTrainerConfig, + agent: Agent, + optimizer: Optimizer, + train_dataset: TaskDataset, + eval_dataset: TaskDataset | None = None, + callbacks: Sequence[Callback] | None = None, + ): + if config.eval_every is not None and eval_dataset is None: + raise ValueError("Must specify eval_dataset if eval_every is set") + + self.config = config + self.agent = agent + self.train_dataset = train_dataset + self.eval_dataset = eval_dataset + self.optimizer = optimizer + self.callbacks = callbacks or [] + if self.config.clear_ctx_at_each_iter: + clear_cb = ClearContextCallback() + self.callbacks = [*self.callbacks, clear_cb] if callbacks else [clear_cb] + self.rollout_manager = self.config.make_rollout_manager( + agent=agent, callbacks=self.callbacks + ) + +
+[docs] + async def train(self) -> None: + if self.config.eval_before: + await self.evaluate() + + with tqdm( + desc="Training Iterations", ncols=0, total=self.config.num_train_iterations + ) as pbar: + # We use pbar.n as a counter for the number of training steps + while pbar.n < self.config.num_train_iterations: + for batch in self.train_dataset.iter_batches( + self.config.batch_size, shuffle=True + ): + await self._training_step(pbar.n, batch) + pbar.update() # Increment pbar.n by 1 + + if ( + self.config.eval_every is not None + and pbar.n % self.config.eval_every == 0 + ): + await self.evaluate() + + if pbar.n == self.config.num_train_iterations: + break # Will also break out of the outer while loop + + await self.evaluate()
+ + + @eval_mode() + async def evaluate(self, **kwargs) -> None: + await _run_eval_loop( + dataset=cast(TaskDataset, self.eval_dataset), + rollout_manager=self.rollout_manager, + batch_size=self.config.batch_size, + num_iterations=self.config.num_eval_iterations, + max_rollout_steps=self.config.max_rollout_steps, + callbacks=self.callbacks, + **kwargs, + ) + + @train_mode() + async def _training_step(self, i_iter: int, envs: Sequence[Environment]) -> None: + training_batch: list[Trajectory] = [] + + for _ in range(self.config.num_rollouts_per_env): + trajectories = await self.rollout_manager.sample_trajectories( + environments=envs, max_steps=self.config.max_rollout_steps + ) + + # Close the environments after we have sampled from them, in case they need to tear down resources. + await asyncio.gather(*[env.close() for env in envs]) + + training_batch.extend(traj for traj in trajectories if not traj.failed) + + await self._optimizer_step(i_iter, training_batch) + + await asyncio.gather(*[ + callback.after_train_step(trajectories) for callback in self.callbacks + ]) + + async def _optimizer_step( + self, i_iter: int, training_batch: Sequence[Trajectory] + ) -> None: + for traj in training_batch: + for step in traj.steps: + # TODO: make this async + # step.action is not None because we checked traj.failed above + cast(OpResult, step.action).compute_grads() + + self.optimizer.aggregate(training_batch) + + if (i_iter + 1) % self.config.update_every == 0: + await self.optimizer.update() + + await asyncio.gather(*[ + callback.after_update() for callback in self.callbacks + ])
+ + + +
+[docs] +class OfflineTrainerConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + batch_size: int + update_every: int = Field( + default=1, + description="Number of training iterations to run before updating the model.", + ge=1, + ) + clear_ctx_at_each_iter: bool = False
+ + # TODO: add some concept of eval loops + + +
+[docs] +class OfflineTrainer: + def __init__( + self, + config: OfflineTrainerConfig, + agent: Agent, + optimizer: Optimizer, + train_trajectories: list[Trajectory], + callbacks: Sequence[Callback] | None = None, + ): + self.config = config + self.agent = agent + self.optimizer = optimizer + # copy so we can shuffle + self.train_trajectories = train_trajectories.copy() + self.callbacks = callbacks or [] + if self.config.clear_ctx_at_each_iter: + clear_cb = ClearContextCallback() + self.callbacks = [*self.callbacks, clear_cb] if callbacks else [clear_cb] + +
+[docs] + async def train(self) -> None: + random.shuffle(self.train_trajectories) + + full_batch = len(self.train_trajectories) <= self.config.batch_size + + if full_batch: + # Separating out the full batch case lets the user run a single update() + # step even if train_trajectories is empty. This can be useful if the + # optimizer is pre-populated with offline training data, for example. + batch = self.train_trajectories + + self.optimizer.aggregate(batch, show_pbar=True) + await self.optimizer.update() + + await asyncio.gather(*[ + callback.after_update() for callback in self.callbacks + ]) + + await asyncio.gather(*[ + callback.after_train_step(batch) for callback in self.callbacks + ]) + + else: + for training_step, i_batch_start in enumerate( + trange( + 0, + len(self.train_trajectories), + self.config.batch_size, + desc="Training Iterations", + ncols=0, + ) + ): + batch = self.train_trajectories[ + i_batch_start : i_batch_start + self.config.batch_size + ] + + self.optimizer.aggregate(batch) + + if (training_step + 1) % self.config.update_every == 0: + await self.optimizer.update() + await asyncio.gather(*[ + callback.after_update() for callback in self.callbacks + ]) + + await asyncio.gather(*[ + callback.after_train_step(batch) for callback in self.callbacks + ])
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/alg/tree_search.html b/docs/_build/html/_modules/ldp/alg/tree_search.html new file mode 100644 index 00000000..d5b83a0f --- /dev/null +++ b/docs/_build/html/_modules/ldp/alg/tree_search.html @@ -0,0 +1,276 @@ + + + + + + + ldp.alg.tree_search — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.alg.tree_search

+import asyncio
+import logging
+import uuid
+from collections.abc import Awaitable, Callable, Sequence
+from typing import Any
+
+from aviary.message import Message
+from aviary.utils import is_coroutine_callable
+
+from ldp.agent import Agent
+from ldp.data_structures import TransitionTree
+
+from .callbacks import Callback
+from .rollout import (
+    AgentError,
+    CaughtError,
+    EnvError,
+    RolloutManager,
+    TEnv,
+    reraise_exc_as,
+)
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class TreeSearchRollout(RolloutManager): + def __init__( + self, + agent: Agent, + branching_factor: int, + env_clone_fn: Callable[[TEnv], Awaitable[TEnv]] | Callable[[TEnv], TEnv], + catch_agent_failures: bool = True, + catch_env_failures: bool = True, + callbacks: Sequence[Callback] | None = None, + concurrency_limit: int | None = None, + target_reward: float | None = None, + ): + super().__init__( + agent, + catch_agent_failures=catch_agent_failures, + catch_env_failures=catch_env_failures, + callbacks=callbacks, + concurrency_limit=concurrency_limit, + ) + + self.branching_factor = branching_factor + self.target_reward = ( + target_reward if target_reward is not None else float("inf") + ) + self.target_reward_hit: set[str] = set() + + self.env_clone_fn = env_clone_fn + +
+[docs] + async def sample_trees( + self, + environments: Sequence[TEnv], + max_depth: int | None = None, + ) -> list[TransitionTree]: + return await asyncio.gather(*[ + self.sample_tree(env, max_depth) for env in environments + ])
+ + +
+[docs] + async def sample_tree(self, env: TEnv, max_depth: int | None) -> TransitionTree: + max_depth_f = max_depth if max_depth is not None else float("inf") + tree = TransitionTree(root_id=str(uuid.uuid4())) + + try: + with reraise_exc_as(EnvError, enabled=self.catch_env_failures): + obs, tools = await env.reset() + await asyncio.gather(*[ + c.after_env_reset(tree.root_id, obs, tools) for c in self.callbacks + ]) + + with reraise_exc_as(AgentError, enabled=self.catch_agent_failures): + agent_state = await self.agent.init_state(tools) + await asyncio.gather(*[ + c.after_agent_init_state(tree.root_id, agent_state) + for c in self.callbacks + ]) + except CaughtError: + return tree + + await self._descend( + tree=tree, + prev_step_id=tree.root_id, + env=env, + agent_state=agent_state, + obs=obs, + prev_timestep=-1, + prev_cumulative_reward=0.0, + max_depth=max_depth_f, + ) + + return tree
+ + + async def _descend( + self, + tree: TransitionTree, + prev_step_id: str, + env: TEnv, + agent_state: Any, + obs: list[Message], + prev_timestep: int, + prev_cumulative_reward: float, + max_depth: float, + ) -> None: + # Descend one level in the tree, by adding branching_factor children to the branch + # Then, recurse on each child + + if tree.root_id in self.target_reward_hit: + # If at least one branch hit the target reward, stop descending + return + + timestep = prev_timestep + 1 + + async def inner_descend(idx: int) -> None: + if is_coroutine_callable(self.env_clone_fn): + cloned_env = await self.env_clone_fn(env) # type: ignore[arg-type, misc] + else: + cloned_env = self.env_clone_fn(env) # type: ignore[arg-type] + + # Descend one step + step_id = f"{prev_step_id}:{idx}" + try: + step = await self._take_step( + timestep, step_id, cloned_env, agent_state, obs + ) + except CaughtError: + # If we failed, do not extend the branch - just give up on this path + return + + if timestep + 1 == max_depth and not step.done: + # Mark as truncated if we hit max_steps and the state is not terminal. + step.truncated = True + + await asyncio.gather(*[ + callback.after_transition(step_id, self.agent, cloned_env, step) + for callback in self.callbacks + ]) + + tree.add_transition(step_id, step) + + cumulative_reward = prev_cumulative_reward + step.reward + if cumulative_reward >= self.target_reward: + # signal other descents to stop too + self.target_reward_hit.add(tree.root_id) + return + + if step.done or step.truncated: + return + + # Recurse + await self._descend( + tree=tree, + prev_step_id=step_id, + env=cloned_env, + agent_state=step.next_agent_state, + obs=step.next_observation, + prev_timestep=timestep, + prev_cumulative_reward=cumulative_reward, + max_depth=max_depth, + ) + + # Add branching_factor children + await asyncio.gather(*[ + inner_descend(idx) for idx in range(self.branching_factor) + ])
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/data_structures.html b/docs/_build/html/_modules/ldp/data_structures.html new file mode 100644 index 00000000..630e8c3b --- /dev/null +++ b/docs/_build/html/_modules/ldp/data_structures.html @@ -0,0 +1,500 @@ + + + + + + + ldp.data_structures — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.data_structures

+from __future__ import annotations
+
+import json
+import logging
+import os
+from collections.abc import Callable, Hashable
+from typing import Any, ClassVar, Self, cast
+from uuid import UUID
+
+import networkx as nx
+from aviary.message import Message, join
+from aviary.tools import ToolRequestMessage, ToolResponseMessage
+from pydantic import BaseModel, ConfigDict, Field, JsonValue, field_validator
+
+from ldp.graph import OpResult
+from ldp.utils import discounted_returns
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class Transition(BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid") + + # Sentinel value for missing observation, as opposed to empty observation + # Only used for tests; a user should never use this. + NO_OBSERVATION: ClassVar[list[Message]] = [] + + timestep: int = Field(description="Zero-indexed MDP timestep t.") + + agent_state: Any = Field( + description=( + "Agent.get_asv's input. This is `s_t` in RL terms. Note that `s_0` comes" + " from `Agent.init_state()`" + ) + ) + next_agent_state: Any = Field( + description="Agent.get_asv's output. This is s_t+1 in RL terms." + ) + + observation: list[ToolResponseMessage | Message] = Field( + description="Agent.get_asv's input. This is o_t in RL terms." + ) + next_observation: list[ToolResponseMessage | Message] = Field( + description="Environment.step output. This is o_t+1 in RL terms." + ) + + action: OpResult[ToolRequestMessage] | None = Field( + default=None, description="Agent.get_asv output. This is a_t in RL terms." + ) + + reward: float = Field( + default=0.0, description="Environment.step output. This is r_t in RL terms." + ) + + truncated: bool = Field( + default=False, description="timestep t's Environment.step output." + ) + done: bool = Field( + default=False, description="timestep t's Environment.step output." + ) + value: float = Field( + default=0.0, + description=( + "Value estimate output from timestep t's Agent.get_asv. This is v(s_t)" + " [state value function] or q(s_t, a_t) [state-action value]." + ), + ) + # JsonValue so we can serialize + metadata: dict[str, JsonValue] = Field(default_factory=dict) + +
+[docs] + @field_validator("action", mode="before") + @classmethod + def construct_action( + cls, action: OpResult[ToolRequestMessage] | dict | None + ) -> OpResult[ToolRequestMessage] | None: + if isinstance(action, dict): + return OpResult.from_dict(ToolRequestMessage, action) + return action
+ + + @property + def failed(self) -> bool: + """Get if an exception was encountered during rollout, for convenience. + + If True, this transition should not be trained on. + Failed transitions are for debugging purposes. + """ + return bool(self.metadata.get("exception")) + +
+[docs] + def model_dump_json(self, *, indent: int | None = None, **kwargs) -> str: + # The kwargs for model_dump are the same as super().model_dump_json, + # with the exception of indent. + dump = self.model_dump(**kwargs) + if self.action is not None: + dump["action"] = self.action.to_dict() + return json.dumps(dump, indent=indent)
+
+ + + +
+[docs] +class Trajectory(BaseModel): + model_config = ConfigDict(extra="forbid") + + traj_id: str | None = None + steps: list[Transition] = Field(default_factory=list) + + @property + def failed(self) -> bool: + return any(step.failed for step in self.steps) + + @property + def done(self) -> bool: + if not self.steps: + return False + return self.steps[-1].done + +
+[docs] + def to_jsonl(self, filename: str | os.PathLike) -> None: + with open(filename, "w") as f: + f.write(json.dumps(self.traj_id) + "\n") + f.writelines(s.model_dump_json() + "\n" for s in self.steps)
+ + +
+[docs] + @classmethod + def from_jsonl(cls, filename: str | os.PathLike) -> Self: + with open(filename) as f: + reader = iter(f) + traj = cls(traj_id=json.loads(next(reader))) + for json_line in reader: + traj.steps.append(Transition(**json.loads(json_line))) + return traj
+ + +
+[docs] + def compute_discounted_returns(self, discount: float = 1.0) -> list[float]: + """Compute the discounted returns for each step in the trajectory.""" + return discounted_returns( + rewards=[step.reward for step in self.steps], + terminated=[step.truncated for step in self.steps], + discount=discount, + )
+
+ + + +
+[docs] +class TransitionTree: + def __init__(self, root_id: str | UUID): + """A tree of transitions. + + If A->B is an edge in this tree, then A and B are consecutive + transitions in an LDP. Any path from the root node to a terminal + node constitutes a complete LDP. + + A node may be assigned an arbitrary weight, which will be treated + as a relative probability of sampling that node. For example, if + A(weight=1) and B(w=2) are both children of the same node, + then we treat B as twice as likely as A. + + Args: + root_id: A unique identifier for the root node of the tree. + All IDs of transitions added to this tree must begin with + the same root_id. + """ + self.root_id = str(root_id) + + self.tree = nx.DiGraph() # the actual tree + self.rev_tree = nx.DiGraph() # the same as self.tree, but with reversed edges + + self._add_node(self.root_id, transition=None, weight=1.0) + + def _add_node( + self, step_id: str, transition: Transition | None, weight: float + ) -> None: + self.tree.add_node(step_id, transition=transition, weight=weight) + self.rev_tree.add_node(step_id) + + def _add_edge(self, parent_step_id: str, child_step_id: str) -> None: + self.tree.add_edge(parent_step_id, child_step_id) + self.rev_tree.add_edge(child_step_id, parent_step_id) + +
+[docs] + def get_transition(self, step_id: str) -> Transition: + if step_id == self.root_id: + raise ValueError("Root node has no transition.") + + return cast(Transition, self.tree.nodes[step_id]["transition"])
+ + +
+[docs] + def get_weight(self, step_id: str) -> float: + return cast(float, self.tree.nodes[step_id]["weight"])
+ + +
+[docs] + def add_transition( + self, step_id: str, step: Transition, weight: float = 1.0 + ) -> None: + """Add a transition to the tree. + + Args: + step_id: A unique identifier for the root node of the tree. + The expected form of the step ID is "{parent step ID}:{step index}". + step: The transition to add. + weight: Weight of the transition. Defaults to 1.0. + """ + root_id, *step_ids = step_id.split(":") + assert ( + root_id == self.root_id + ), f"Step ID {step_id} does not start with root ID {self.root_id}" + assert step_ids, "Step ID cannot be the same as the root ID." + # TODO: maybe this should be warning? + assert ( + step_id not in self.tree + ), f"Step ID {step_id} already exists in the tree." + + self._add_node(step_id, transition=step, weight=weight) + + parent_id = ":".join([root_id, *step_ids[:-1]]) + if parent_id in self.tree: + self._add_edge(parent_id, step_id)
+ + +
+[docs] + def get_trajectories(self) -> list[Trajectory]: + """Return a list of trajectories. + + Since each path from the root node to a terminal node defines + a unique trajectory, N(terminal node) trajectories will be returned. + The trajectory ID will be set to the ID of the terminal step. + + Note that we include failed and truncated trajectories; it is up to the + caller to decide what to do them. + + Returns: + All trajectories in this tree. + """ + trajs = [] + step: Transition | None + + for step_id, step in self.tree.nodes(data="transition"): + if not step: + # root node + continue + + is_terminal = ( + # check terminal conditions in increasing order of expense + step.done + or step.truncated + or step.failed + or self.tree.out_degree(step_id) == 0 + ) + + if not is_terminal: + continue + + # set the ID to the terminal node, which uniquely identifies the path + traj = Trajectory(traj_id=step_id) + # Build the trajectory up from a terminal node + current_step: Transition | None = step + current_step_id = step_id + + # Walk backwards towards the root (current_step=None) + while current_step: + traj.steps.append(current_step) + + parent_step_id, *extra = list(self.rev_tree.successors(current_step_id)) + assert not extra, f"Expected a single parent, but got {len(extra) + 1}" + + current_step_id = parent_step_id + current_step = self.tree.nodes[parent_step_id]["transition"] + + # would've added things in reverse order, so fix that here + traj.steps.sort(key=lambda x: x.timestep) + trajs.append(traj) + + return trajs
+ + +
+[docs] + def assign_mc_value_estimates(self, discount_factor: float = 1.0) -> None: + """Assign Monte Carlo state-action value estimates to each transition (in-place). + + Args: + discount_factor: The discount factor to use when computing cumulative + future rewards. + """ + for step_id in nx.topological_sort(self.rev_tree): + step: Transition | None = self.tree.nodes[step_id]["transition"] + if step is None: + continue + + if children := list(self.tree.successors(step_id)): + # V_{t+1}(s') = sum_{a'} p(a'|s') * Q_{t+1}(s', a') + # Here we assume p(a'|s') is uniform over the sampled actions.. + # TODO: don't make that assumption where a logprob is available + weights = [self.get_weight(child_id) for child_id in children] + steps = [self.get_transition(child_id) for child_id in children] + v_tp1 = sum( + w * step.value for w, step in zip(weights, steps, strict=True) + ) / sum(weights) + else: + v_tp1 = 0.0 + + # Q_t(s_t, a_t) = r_{t+1} + gamma * V_{t+1}(s_{t+1}) + # (we are assuming the environment is deterministic) + step.value = step.reward + discount_factor * v_tp1
+ + +
+[docs] + def merge_identical_nodes( + self, + agent_state_hash_fn: Callable[[Any], Hashable], + observation_hash_fn: Callable[ + [list[ToolResponseMessage | Message]], Hashable + ] = join, + next_observation_hash_fn: Callable[ + [list[ToolResponseMessage | Message]], Hashable + ] = join, + ) -> TransitionTree: + """Merge nodes with identical (state, observation, action)s. Returns a new tree. + + Args: + agent_state_hash_fn: A function that returns a hashable representation + of the agent state of a transition. + observation_hash_fn: A function that returns a hashable representation + of the observation messages of a transition. + next_observation_hash_fn: A function that returns a hashable representation + of the next observation messages of a transition. + """ + new_tree = TransitionTree(self.root_id) + + # step hash -> step ID + seen_hash_to_step_id: dict[int, str] = {} + # old step ID -> new step ID + node_remap: dict[str, str] = {self.root_id: self.root_id} + + for step_id in nx.topological_sort(self.tree): + step: Transition | None = self.tree.nodes[step_id]["transition"] + if step is None: + continue + + state_hash = agent_state_hash_fn(step.agent_state) + + if step.action is not None: + tool_request_msg = step.action.value + # NOTE: we are ignoring tool call ID in the comparison of tool requests. + # Thus, the tool call ID is excluded from the hash, so we can't just + # simply call str(tool_request_msg) + action_str = (tool_request_msg.content or "") + " ".join( + str(tc) for tc in tool_request_msg.tool_calls + ) + else: + action_str = "" + + step_hash = hash(( + state_hash, + action_str, + # (s, a, o): works for deterministic envs + observation_hash_fn(step.observation), + # (s, a, o, o'): works for both deterministic and stochastic envs + next_observation_hash_fn(step.next_observation), + )) + step_weight = self.get_weight(step_id) + + if step_hash in seen_hash_to_step_id: # Seen: merge + merged_step_id = node_remap[step_id] = seen_hash_to_step_id[step_hash] + # Not sure if this is the fastest way to do this + new_tree.tree.nodes[merged_step_id]["weight"] += step_weight + else: # Unseen: don't merge + node_remap[step_id] = seen_hash_to_step_id[step_hash] = step_id + parent_id = node_remap[":".join(step_id.split(":")[:-1])] + + # manually add transitions, since the step_id substring relationship + # will be broken + new_tree._add_node(step_id, transition=step, weight=step_weight) + new_tree._add_edge(parent_id, step_id) + + return new_tree
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/async_torch.html b/docs/_build/html/_modules/ldp/graph/async_torch.html new file mode 100644 index 00000000..5c3a09aa --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/async_torch.html @@ -0,0 +1,315 @@ + + + + + + + ldp.graph.async_torch — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.async_torch

+__all__ = ["AsyncTorchModule", "async_protect_torch_call"]
+
+import asyncio
+import operator
+import time
+from abc import ABC, abstractmethod
+from collections.abc import Callable
+from contextlib import nullcontext
+from typing import Any
+from uuid import UUID, uuid4
+
+try:
+    import torch
+    from torch import nn
+    from torch.utils.data import default_collate
+except ImportError:
+    raise ImportError(
+        "ldp.graph.async_torch requires PyTorch as a dependency. "
+        "Please run `pip install ldp[nn]`."
+    ) from None
+
+_TORCH_LOCK = asyncio.Lock()
+
+# Supported devices here: https://pytorch.org/docs/stable/amp.html#torch.autocast
+_AUTOCAST_DEVICES = {"cpu", "cuda", "hpu", "xpu"}
+
+
+def _get_autocast_context(dtype: torch.dtype | None, device_type: str):
+    return (
+        nullcontext()
+        if dtype is None or device_type not in _AUTOCAST_DEVICES
+        else torch.autocast(dtype=dtype, device_type=device_type)
+    )
+
+
+def _get_grad_context(no_grad: bool):
+    return torch.no_grad() if no_grad else nullcontext()
+
+
+
+[docs] +def async_protect_torch_call( + module: nn.Module, + module_call_fn: Callable = lambda m, *args, **kwargs: m(*args, **kwargs), + no_grad: bool = False, + autocast_dtype: torch.dtype | None = None, + autocast_device_type=None, +) -> Callable: + async def wrapped_call(*args, **kwargs): + async with _TORCH_LOCK: + with ( + _get_grad_context(no_grad), + _get_autocast_context(autocast_dtype, autocast_device_type), + ): + return module_call_fn(module, *args, **kwargs) + + return wrapped_call
+ + + +# TODO: make max_wait_interval adaptive. We can use a heuristic like +# half the average time for a single call. If it's not provided, enable +# adaptive mode. + + +class AsyncBufferedWorker(ABC): + """Abstract class for a worker that buffers inputs and processes them in batches.""" + + def __init__( + self, + batch_size: int, + max_wait_interval: float, + collate_fn: Callable = lambda x: x, + decollate_fn: Callable = lambda x: x, + ): + """Initialize. + + Args: + batch_size: The target batch size to use when calling the module. As soon as + batch_size calls are made, a forward pass is executed. + max_wait_interval: The maximum time (sec) to wait for a batch to fill up + before executing the calls we have buffered. + collate_fn: A function to pre-process a list of inputs into a batch. Defaults to a + no-op. + decollate_fn: Kind of like the opposite of collate_fn. This function should take + the batched output and return an ordered list of outputs. Defaults to no-op. + """ + self.batch_size = batch_size + self.timeout = max_wait_interval + self.collate_fn = collate_fn + self.decollate_fn = decollate_fn + + self._work_buffer: list[tuple[float, UUID, dict[str, Any]]] = [] + self._result_buffer: dict[UUID, Any] = {} + self._lock = asyncio.Lock() + + async def __call__(self, **kwargs): + request_id = uuid4() + request_ts = time.time() + + async with self._lock: + # Make sure only one coroutine is using the work buffer at a time + self._work_buffer.append((request_ts, request_id, kwargs)) + + while True: + async with self._lock: + # Only one coroutine allowed in here when: + # - modifying the result buffer + # - modifying the work buffer + + if request_id in self._result_buffer: + # Our request was fulfilled by this or another coroutine! + return self._result_buffer.pop(request_id) + + # Try to run a batch. + await self._maybe_process_batch() + + # Sleep, to let another coroutine take over if it needs to + await asyncio.sleep(0.0) + + async def _maybe_process_batch(self): + """If the buffer is >= batch size or we have been waiting long enough, process the old batch. + + If neither condition is met, do nothing. + """ + now = time.time() + + # sort by oldest requests first + self._work_buffer.sort(key=operator.itemgetter(0)) + + if ( + len(self._work_buffer) >= self.batch_size + or now - self._work_buffer[0][0] > self.timeout + ): + # if we're over batch size or have at least one input waiting for + # more than timeout, pull out a batch to run + batch = self._work_buffer[: self.batch_size] + self._work_buffer = self._work_buffer[self.batch_size :] + + # Construct the batch tensors + sample_kwargs = [x[2] for x in batch] + batch_kwargs = self.collate_fn(sample_kwargs) + + batched_results = await self._batched_call(batch_kwargs) + request_ids = [x[1] for x in batch] + results = self.decollate_fn(batched_results) + self._result_buffer.update(zip(request_ids, results, strict=True)) + + @abstractmethod + async def _batched_call(self, batch_kwargs: dict[str, Any]): + """Logic to call the worker on a batch of inputs.""" + + +
+[docs] +class AsyncTorchModule(AsyncBufferedWorker): + def __init__( + self, + module: nn.Module, + batch_size: int, + max_wait_interval: float, + collate_fn: Callable = default_collate, + decollate_fn: Callable = list, + module_call_fn: Callable = lambda m, *args, **kwargs: m(*args, **kwargs), + ): + """A wrapper around a torch.nn.Module that allows for async calls. + + Usage: + ```python + my_model = nn.Linear(2, 2) + async_model = AsyncTorchModule(my_model, batch_size=4, max_wait_interval=0.01) + + result = await asyncio.gather(*[ + async_model(input=torch.rand(2)) for _ in range(10) + ]) + ``` + In the above example, note that we are making 10 calls with a batch size of 4. + The first two groups of 4 will be batched and executed as they arrive. The last 2 + will wait for max_wait_interval and then execute. + + NOTE: This module is not thread-safe and currently always operates in no_grad() mode. + It may be possible to relax the latter constraint. + + Args: + module: The PyTorch module to wrap. + batch_size: See parent class. + max_wait_interval: See parent class. + collate_fn: A PyTorch collate function to use when batching inputs. Defaults to + the PyTorch default_collate. + decollate_fn: Kind of like the opposite of collate_fn. This function should take + the batched output and return an ordered list of outputs. Defaults to list. + module_call_fn: Function that allows for customizing the call to the module. + """ + super().__init__( + batch_size=batch_size, + max_wait_interval=max_wait_interval, + collate_fn=collate_fn, + decollate_fn=decollate_fn, + ) + self.module = module + self.module_call_fn = module_call_fn + + def _get_dtype_and_device(self) -> tuple[torch.dtype, torch.device]: + param = next(self.module.parameters()) + return param.dtype, param.device + + async def _batched_call(self, batch_kwargs: dict[str, Any]): + # Call the module and store results + # To be safe, set _TORCH_LOCK to prevent other + # coroutines from messing with torch state while running. + async with _TORCH_LOCK: + dtype, device = self._get_dtype_and_device() + with torch.no_grad(), _get_autocast_context(dtype, device.type): + return self.module_call_fn(self.module, **batch_kwargs)
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/common_ops.html b/docs/_build/html/_modules/ldp/graph/common_ops.html new file mode 100644 index 00000000..38ae331c --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/common_ops.html @@ -0,0 +1,596 @@ + + + + + + + ldp.graph.common_ops — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.common_ops

+"""This module contains commonly-used Op implementations."""
+
+from __future__ import annotations
+
+import asyncio
+import functools
+import inspect
+import logging
+from collections.abc import Awaitable, Callable
+from functools import lru_cache
+from typing import Generic, TypeVar, cast, overload
+
+import numpy as np
+import tree
+from aviary.message import Message
+from aviary.tools import Tool, ToolRequestMessage
+from aviary.utils import is_coroutine_callable
+from pydantic import BaseModel
+
+from ldp.llms import (
+    EmbeddingModel,
+    HybridEmbeddingModel,
+    LiteEmbeddingModel,
+    LLMModel,
+    LLMResult,
+    SparseEmbeddingModel,
+)
+
+from .gradient_estimators import assign_constant_grads
+from .memory import Memory, MemoryModel, UIndexMemoryModel
+from .op_utils import CallID, get_call_id, get_training_mode
+from .ops import GradInType, Op, OpCtx, ResultOrValue, TOutput
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +def logsumexp(a: np.ndarray | list[float]) -> float: + a_max = np.max(a) + return a_max + np.log(np.sum(np.exp(a - a_max)))
+ + + +
+[docs] +class IdentityOp(Op[TOutput]): + """ + An operation that simply returns the input value. + + NOTE: this op is equivalent to FxnOp(lambda x: x). + """ + +
+[docs] + async def forward(self, value: TOutput) -> TOutput: + # We assume value already has the correct run_id from its producer + return value
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + return [], {"value": grad_output}
+
+ + + +
+[docs] +class StopGradOp(IdentityOp[TOutput]): + """Pass through Op that terminates gradients in the backward pass.""" + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + return assign_constant_grads(input_args, input_kwargs, None)
+
+ + + +TConfig = TypeVar("TConfig", bound=BaseModel | dict) + + +
+[docs] +class ConfigOp(Op[TConfig], Generic[TConfig]): + """An operation that contains a configuration object.""" + + def __init__(self, config: TConfig): + self.config = config + +
+[docs] + async def forward(self) -> TConfig: + return self.config
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + # Check that the grad_output structure is consistent with our config + tree.assert_same_structure( + grad_output, ctx.get(call_id, "output").value, check_types=False + ) + + # Terminate here - we're a leaf since a ConfigOp takes no inputs + return [], {}
+
+ + + +TResult = TypeVar("TResult") + + +
+[docs] +class Cacheable(Generic[TResult]): + def __init__(self, co: Awaitable[TResult]) -> None: + self.co = co + self.done = False + self.result: TResult | None = None + self.lock = asyncio.Lock() + +
+[docs] + async def get_result(self) -> TResult | None: + async with self.lock: + if not self.done: + self.result = await self.co + self.done = True + return self.result
+ + + def __await__(self): + return self.get_result().__await__()
+ + + +
+[docs] +def async_cache(func): + @functools.lru_cache(maxsize=1024) + @functools.wraps(func) + def wrapper(*args, **kwargs): + return Cacheable(co=func(*args, **kwargs)) + + return wrapper
+ + + +
+[docs] +class FxnOp(Op[TOutput]): + """ + Wrap a function for a straight through gradient approximation for all args/kwargs. + + Basically, consider the fxn as a transform upon the inputs during the forward pass, + and propagating the same gradient for all inputs during the backward pass. + """ + + def __init__( + self, + fxn: Callable[..., TOutput] | Callable[..., Awaitable[TOutput]], + cache: bool = False, + fxn_name: str | None = None, # useful for lambdas + ): + if cache: + self.fxn = ( + async_cache(fxn) if is_coroutine_callable(fxn) else lru_cache()(fxn) + ) + else: + self.fxn = fxn + + try: + self.fxn_name = fxn_name or fxn.__name__ + except AttributeError: # unittest.mock.Mock or lambda + self.fxn_name = str(fxn) + + # override forward args with the signature of the function + fwd_sig = inspect.signature(self.fxn) + self._fwd_args = list(fwd_sig.parameters.values()) + + def __repr__(self) -> str: + return f"{type(self).__name__} {self.fxn_name} ({id(self)})" + +
+[docs] + async def forward(self, *args, **kwargs) -> TOutput: + if is_coroutine_callable(self.fxn): + return await self.fxn(*args, **kwargs) + return self.fxn(*args, **kwargs)
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + return assign_constant_grads(input_args, input_kwargs, 0.0)
+
+ + + +
+[docs] +class PromptOp(FxnOp[str]): + """An operation that formats kwargs into a prompt string.""" + + async def _fxn( + self, prompt_kwargs: dict[str, str] | None = None, **kwargs: str + ) -> str: + return self.prompt.format(**{**(prompt_kwargs or {}), **kwargs}) + + def __init__(self, prompt: str): + self.prompt = prompt + super().__init__(fxn=self._fxn, cache=False) + + def __repr__(self) -> str: + # we want to use Op.__repr__, not FxnOp.__repr__ + return super(FxnOp, self).__repr__()
+ + + +
+[docs] +class LLMCallOp(Op[Message]): + """An operation for LLM calls interaction.""" + + def __init__(self, num_samples_logprob_estimate: int = 0) -> None: + super().__init__() + self.num_samples_partition_estimate = num_samples_logprob_estimate + + @overload + async def forward( + self, + config: dict, + msgs: list[Message], + tools: list[Tool] = ..., + tool_choice: Tool | str | None = LLMModel.TOOL_CHOICE_REQUIRED, + ) -> ToolRequestMessage: ... + + @overload + async def forward( + self, + config: dict, + msgs: list[Message], + tools: None = None, + tool_choice: str | None = LLMModel.TOOL_CHOICE_REQUIRED, + ) -> Message: ... + +
+[docs] + async def forward( + self, + config: dict, + msgs: list[Message], + tools: list[Tool] | None = None, + tool_choice: Tool | str | None = LLMModel.TOOL_CHOICE_REQUIRED, + ) -> Message: + model = LLMModel(config=config) + + result = await model.call(messages=msgs, tools=tools, tool_choice=tool_choice) + if result.messages is None: + raise ValueError("No messages returned") + + # if not set, assume temp = 1. TODO: when would it not be set? + temperature: float = (result.config or {}).get("temperature", 1.0) + + # Compute a Monte Carlo estimate of the logprob of this sequence at the given temperature. + logprob = await self.compute_logprob( + raw_log_p=result.logprob, + temperature=temperature, + model=model, + messages=msgs, + tools=tools, + tool_choice=tool_choice, + ) + + call_id = get_call_id() + self.ctx.update(call_id, "result", result) + # This is the logprob of this sequence according to the raw model, without + # any temperature/top-p distribution shaping. + self.ctx.update(call_id, "raw_logprob", result.logprob) + + self.ctx.update(call_id, "temperature", temperature) + self.ctx.update(call_id, "logprob", logprob) + + return result.messages[0]
+ + +
+[docs] + async def compute_logprob( + self, + raw_log_p: float | None, + temperature: float, + model: LLMModel, + **model_kwargs, + ) -> float | None: + """This method computes a Monte Carlo estimate of logprob for a given temperature. + + It takes as input the logprob at T=1. The derivation is in Section 5.1 of the Aviary notes. + """ + if temperature == 1: + return raw_log_p + + if temperature == 0: + return 1.0 + + if raw_log_p is None or self.num_samples_partition_estimate == 0: + return None + + # TODO: Try using n completions from a single API call. Need to modify LLMModel.call to do this, since + # it currently only checks completion.choices[0]. Would reduce cost for long prompts. + # TODO: think about whether sampling params besides temperature need to be accounted for, like top_p + results = await asyncio.gather(*[ + model.call(temperature=1, **model_kwargs) + for _ in range(self.num_samples_partition_estimate) + ]) + temp_factor = 1.0 / temperature - 1.0 + + # Partition function estimate: + # Z_T = E_P[ e^(lnP/T - lnP) ] + log_Z_T = logsumexp([ + temp_factor * cast(float, result.logprob) for result in results + ]) - np.log(self.num_samples_partition_estimate) + + return (raw_log_p / temperature) - log_Z_T
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + # By default, we want to descend into config, but not msgs/tools/tool_choice + # Essentially: we can think of each config field as an independent parameter, + # but not necessarily each message or tool. + + # tree.map_structure allows us to assign a gradient of 0 to all fields of config + grad_config = tree.map_structure(lambda _: 0.0, input_kwargs["config"]) + grad_kwargs = {"config": grad_config} + for arg in ("msgs", "tools", "tool_choice"): + if arg in input_kwargs: + grad_kwargs[arg] = 0.0 + + return [], grad_kwargs
+ + +
+[docs] + def get_examples(self) -> list[tuple[LLMResult, float]]: + examples = [ + ( + self.ctx.get(c, "result", None), + # get 'model' kwarg from grad_input + # use default of None if not found + self.ctx.get(c, "grad_input", default=([], {}))[1].get("model", None), + ) + for c in self.get_call_ids() + ] + # filter out the None values + return [(e, w) for e, w in examples if e is not None]
+
+ + + +
+[docs] +class MemoryOp(Op[list[Memory]]): + """An operation for managing memory retrieval and storage.""" + + def __init__(self, memory_model: MemoryModel | None = None): + super().__init__() + self.memory_model = memory_model or UIndexMemoryModel( + embedding_model=EmbeddingModel.from_name("sparse") + ) + +
+[docs] + async def forward( + self, + query: str, + input: str | None = None, # noqa: A002 + matches: int = 3, + ) -> list[Memory]: + """Retrieve relevant memories based on a query.""" + if get_training_mode(): + call_id = get_call_id() + self.ctx.update(call_id, "query", query) + self.ctx.update(call_id, "memory_input", input) + return await self.memory_model.get_memory(query, matches)
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + """Backward pass for memory retrieval - goes back to item.""" + return assign_constant_grads(input_args, input_kwargs, 0.0)
+
+ + + +
+[docs] +class EmbeddingOp(Op): + """A general operation for embedding text using LiteLLM.""" + + def __init__( + self, + *, + dense_embedding: str = "text-embedding-3-small", + dense_embedding_dim: int = 512, + sparse_embedding_dim: int = 0, + **embedding_model_kwargs, + ): + if "timeout" not in embedding_model_kwargs: + embedding_model_kwargs.setdefault("timeout", 60) + emb_models: list[EmbeddingModel] = [] + if dense_embedding_dim > 0: + emb_models.append( + LiteEmbeddingModel( + name=dense_embedding, + dimensions=dense_embedding_dim, + embed_kwargs=embedding_model_kwargs, + ) + ) + if sparse_embedding_dim > 0: + emb_models.append(SparseEmbeddingModel(dimensions=sparse_embedding_dim)) + self.embedding = HybridEmbeddingModel(models=emb_models) + +
+[docs] + async def forward(self, string_input: str) -> np.ndarray: + return await self.embedding.embed_text(string_input)
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args, + input_kwargs, + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + return [], {"string_input": None}
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/gradient_estimators.html b/docs/_build/html/_modules/ldp/graph/gradient_estimators.html new file mode 100644 index 00000000..f6e91c27 --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/gradient_estimators.html @@ -0,0 +1,363 @@ + + + + + + + ldp.graph.gradient_estimators — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.gradient_estimators

+"""This module defines various gradient estimators that can be patched in during backward passes."""
+
+from __future__ import annotations
+
+import logging
+from functools import partial
+from typing import Any
+
+import tree
+
+from .op_utils import CallID
+from .ops import GradInType, OpCtx, OpResult, ResultOrValue
+
+try:
+    import torch
+
+    from .torch_ops import TorchOp
+
+except ImportError:
+    torch = None  # type: ignore[assignment]
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +def assign_constant_grads( + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + value: Any, + descend: bool = True, +): + if not descend: + return [value] * len(input_args), dict.fromkeys(input_kwargs, value) + + # descend into nested objects + arg_grads = [ + tree.map_structure(lambda _: value, OpResult.unwrap_value(arg)) + for arg in input_args + ] + kwarg_grads = { + k: tree.map_structure(lambda _: value, OpResult.unwrap_value(v)) + for k, v in input_kwargs.items() + } + return arg_grads, kwarg_grads
+ + + +
+[docs] +def straight_through_estimator( + ctx: OpCtx, # noqa: ARG001 + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, # noqa: ARG001 + descend: bool = True, +) -> GradInType: + return assign_constant_grads(input_args, input_kwargs, grad_output, descend=descend)
+ + + +
+[docs] +def stop_grad( + ctx: OpCtx, # noqa: ARG001 + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, # noqa: ARG001 + call_id: CallID, # noqa: ARG001 +) -> GradInType: + # don't descend - want gradients to stop at the OpResult level + return assign_constant_grads(input_args, input_kwargs, None, descend=False)
+ + + +
+[docs] +def zero_estimator( + ctx: OpCtx, # noqa: ARG001 + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, # noqa: ARG001 + call_id: CallID, # noqa: ARG001 +) -> GradInType: + """Sets the gradient of all inputs to zero. + + Note that this is not the same as truncating the compute graph (stop_grad), + since upstream nodes can still optimize their logprobs. The zero estimator + the unbiased choice if we have no information about the gradient. + """ + return assign_constant_grads(input_args, input_kwargs, 0.0)
+ + + +
+[docs] +def llm_straight_through_estimator( + ctx: OpCtx, # noqa: ARG001 + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, # noqa: ARG001 +) -> GradInType: + """Straight-through for an LLM: descend into the config, but not msgs/tools/tool_calls. + + See LLMCallOp.backward() for more details on this choice. + Don't bother checking that input_args/input_kwargs have the right structure, + since compute_grads() will raise if not. + """ + config_grad = tree.map_structure( + lambda _: grad_output, OpResult.unwrap_value(input_kwargs["config"]) + ) + grad_args = [grad_output] * len(input_args) + grad_kwargs = {"config": config_grad} + if "msgs" in input_kwargs: + grad_kwargs["msgs"] = grad_output + if "tools" in input_kwargs: + grad_kwargs["tools"] = grad_output + + return grad_args, grad_kwargs
+ + + +
+[docs] +def assign_default_grads( + input_grads: GradInType, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + default_grad_val: float = 0.0, +) -> GradInType: + """Sets a default value of default_grad_val for every element in input_grads. + + Example: + - input_kwargs = {"a": {"b": 1, "c": 2}}, + - input_grad_kwargs = {"a": {"b": 0.1}} + Output: input_grads[1] = {"a": {"b": 0.1, "c": default_grad_val}} + + Returns: + GradInType: A tuple containing the updated input_grad_args and + input_grad_kwargs with default values assigned where necessary. + """ + + def get_nested_value(data: tree.Structure, path: list) -> Any: + """Traverse given path over data and return the value at the end of the path.""" + try: + current_value = data + for key in path: + current_value = current_value[key] + except (KeyError, IndexError): + return None # If path not found, return None (than default_grad_val will be assigned) + else: + return current_value + + def assign_default_gradients( + input_grads: tree.Structure, path: list, _value: Any + ) -> Any: + """Assign default_grad_val where grads are missing.""" + return get_nested_value(input_grads, path) or default_grad_val + + input_args_kwargs = (input_args, input_kwargs) + input_grads = tree.map_structure_with_path( + partial(assign_default_gradients, input_grads), + input_args_kwargs, + ) + + tree.assert_same_structure(input_grads, input_args_kwargs) + return input_grads
+ + + +
+[docs] +class TorchParamBackwardEstimator: + """ + Gradient estimator for `TorchOp` internal parameters. + + This estimator computes gradients with respect to the internal parameters of a + `torch.nn.Module` by calling the `backward` method of the estimator instead of the default + `backward` method of `TorchOp`. Computed gradients are stored in the context of the operation + under the key `"grad_params"`. + + Examples: + >>> torch_module = torch.nn.Sequential( + ... torch.nn.Linear(4, 4), + ... torch.nn.Linear(4, 1), + ... ) + >>> torch_op = TorchOp(torch_module) + >>> estimator = TorchParamBackwardEstimator(torch_module) + >>> result = await torch_op(torch.randn(4, requires_grad=True)) + >>> result.compute_grads(backward_fns={"TorchOp": estimator.backward}) + + Note: + This estimator is only compatible with `TorchOp` operations. + """ + + def __init__(self, module: torch.nn.Module): + if torch is None: + raise RuntimeError( + f"PyTorch library not found. Unable to use {type(self).__name__} class. " + "To install PyTorch dependencies, please run `pip install ldp[nn]`." + ) + self.params = dict(module.named_parameters()) + +
+[docs] + def backward( + self, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + tensor_args, tensor_kwargs = ctx.get(call_id, TorchOp.CTX_TENSOR_INPUT_KEY) + n_pos_args = len(tensor_args) + n_pos_kwargs = len(tensor_kwargs) + output = ctx.get(call_id, "output").value + + if not isinstance(grad_output, torch.Tensor): + grad_output = torch.tensor( + grad_output, + dtype=output.dtype, + ) + grad_output = grad_output.to(output.device) + + while grad_output.ndim < output.ndim: + # Assume we can broadcast, so expand dims + # e.g. if output.shape = (2, 1, 1) and grad_output is a scalar + # then we want to expand to (1, 1, 1) and then broadcast + grad_output = grad_output.unsqueeze(-1) + + if output.shape != grad_output.shape: + raise RuntimeError( + f"Output shape {output.shape} does not match grad_output shape {grad_output.shape}" + ) + + gradients = torch.autograd.grad( + output, + [*tensor_args, *tensor_kwargs.values(), *self.params.values()], + grad_outputs=grad_output, + ) + + grad_args = [grad.detach().cpu().float() for grad in gradients[:n_pos_args]] + grad_kwargs = { + k: grad.detach().cpu().float() + for k, grad in zip( + tensor_kwargs.keys(), gradients[n_pos_args:n_pos_kwargs], strict=True + ) + } + grad_params = { + name: grad.detach().cpu().float() + for name, grad in zip( + self.params.keys(), gradients[n_pos_kwargs:], strict=True + ) + } + + ctx.update(call_id=call_id, key="grad_params", value=grad_params) + + return grad_args, grad_kwargs
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/loss_ops.html b/docs/_build/html/_modules/ldp/graph/loss_ops.html new file mode 100644 index 00000000..df94fb87 --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/loss_ops.html @@ -0,0 +1,144 @@ + + + + + + + ldp.graph.loss_ops — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.loss_ops

+"""This module contains loss Op implementations."""
+
+from typing import TYPE_CHECKING
+
+import tree
+
+from .op_utils import CallID
+from .ops import GradInType, Op, OpCtx
+
+if TYPE_CHECKING:
+    import numpy.typing as npt
+    import torch
+
+
+
+[docs] +class MSELossOp(Op): +
+[docs] + async def forward( + self, + prediction: "npt.NDArray | torch.Tensor", + target: "npt.NDArray | torch.Tensor", + ) -> "float | torch.Tensor": + return ((prediction - target) ** 2).mean()
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args, + input_kwargs, + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + prediction = input_kwargs["prediction"] + target = input_kwargs["target"] + grad = 2 * (prediction - target) + return [], {"prediction": grad, "target": None}
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/memory.html b/docs/_build/html/_modules/ldp/graph/memory.html new file mode 100644 index 00000000..30c3f12b --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/memory.html @@ -0,0 +1,315 @@ + + + + + + + ldp.graph.memory — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.memory

+import asyncio
+from abc import ABC, abstractmethod
+from collections.abc import AsyncIterator
+from contextlib import asynccontextmanager
+from typing import TYPE_CHECKING, Any, ClassVar, Generic, Self, TypeVar, cast
+from uuid import UUID
+
+import numpy as np
+import numpy.typing as npt
+from pydantic import (
+    BaseModel,
+    ConfigDict,
+    Field,
+    JsonValue,
+    PrivateAttr,
+    field_validator,
+    model_validator,
+)
+from usearch.index import Index
+
+from ldp.llms import EmbeddingModel
+
+if TYPE_CHECKING:
+    from .common_ops import MemoryOp
+    from .op_utils import CallID
+    from .ops import Op, OpResult, TOutput
+
+
+
+[docs] +class Memory(BaseModel): + """A single memory about an input, output, and value tuple. + + A memory is a record of an input, output, and resulting value. Typically used + for prompting a language model. Or, it could be about a whole forward pass where + the input is the observation and the output is the action taken. + The query is optionally different and used for + retrieving the memory. For example, it could be much larger because it won't + be formatted in the resulting prompt. + """ + + query: str = Field( + description="String to be embedded into a retrieval key for a memory index." + ) + input: str | None = Field( + default=None, + description=( + "Some input (e.g. prompt to LLM, observation). If None (default), the input" + " is set to match the query." + ), + ) + output: str = Field(description="Some output (e.g. tool selection).") + value: float | str = Field( + description="Measure of the output's quality (e.g. loss)." + ) + metadata: JsonValue = Field( + default_factory=dict, + description=( + "Optional JSON metadata to store with the memory. An example is storing" + " information an optimizer can use at training time." + ), + ) + run_id: UUID | None = Field( + default=None, + description=( + "Associate run_id for debugging purposes to trace " + "which forward pass generated the memory." + ), + ) + template: str = "Input: {input}\nOutput: {output}\nValue: {value}" + +
+[docs] + @model_validator(mode="before") + @classmethod + def ensure_query(cls, data: Any) -> Any: + """Copy input to match the query if input is None.""" + if isinstance(data, dict) and data.get("input") is None: + data["input"] = data["query"] + return data
+ + + def __str__(self) -> str: + return self.template.format(**self.model_dump()) + +
+[docs] + @classmethod + def from_ops( + cls, + mem_op: "MemoryOp", + mem_call_id: "CallID", + output_op: "Op[TOutput]", + output_call_id: "CallID", + value: float, + **kwargs, + ) -> Self: + """Create from a MemoryOp, output Op, and their call IDs.""" + query: str = mem_op.ctx.get(mem_call_id, "query") + memory_input: str | None = mem_op.ctx.get(mem_call_id, "memory_input") + output_result: OpResult[TOutput] = output_op.ctx.get(output_call_id, "output") + return cls( + query=query, + input=memory_input if memory_input is not None else query, + output=str(output_result.value), + value=value, + run_id=output_call_id.run_id, + **kwargs, + )
+
+ + + +TIndex = TypeVar("TIndex") + + +
+[docs] +class MemoryModel(BaseModel, Generic[TIndex], ABC): + """A collection of memories with retrieval.""" + + model_config = ConfigDict(arbitrary_types_allowed=True) + + embedding_model: EmbeddingModel = Field( + default_factory=lambda: EmbeddingModel.from_name( + "hybrid-text-embedding-3-small" + ) + ) + memories: dict[int, Memory] = Field(default_factory=dict) + _index: TIndex + _index_lock: asyncio.Lock = PrivateAttr(default_factory=asyncio.Lock) + +
+[docs] + @field_validator("memories") + @classmethod + def enforce_empty(cls, v: dict) -> dict: + if v: + raise ValueError("Memories must be empty at construction time.") + return v
+ + +
+[docs] + async def add_memory(self, memory: Memory) -> None: + key = await self._add_to_index( + embedding=await self.embedding_model.embed_text(memory.query) + ) + self.memories[key] = memory
+ + + DEFAULT_MEMORY_MATCHES: ClassVar[int] = 3 + +
+[docs] + async def get_memory( + self, query: str, matches: int = DEFAULT_MEMORY_MATCHES + ) -> list[Memory]: + return await self._search_index( + embedding=await self.embedding_model.embed_text(query), matches=matches + )
+ + + def __len__(self) -> int: + return len(self.memories) + +
+[docs] + @asynccontextmanager + async def safe_access_index(self) -> AsyncIterator[TIndex]: + """Get the internal Index under the protection of an internal Lock.""" + # pylint bug, SEE: https://github.com/pylint-dev/pylint/issues/9813 + async with self._index_lock: # pylint: disable=not-async-context-manager + yield self._index
+ + + @abstractmethod + async def _add_to_index(self, embedding: np.ndarray) -> int: + """Add an embedding to the internal Index and return its key.""" + + @abstractmethod + async def _search_index( + self, embedding: np.ndarray, matches: int = DEFAULT_MEMORY_MATCHES + ) -> list[Memory]: + """Search the internal Index, returning a 'matches' amount of Memories."""
+ + + +
+[docs] +class UIndexMemoryModel(MemoryModel[Index]): + """Memory model using a U-Search index.""" + + def __init__(self, **kwargs): + super().__init__(**kwargs) + if not self.embedding_model.dimensions: + raise TypeError("Specify dimensions to the embedding model.") + self._index = Index(ndim=self.embedding_model.dimensions) + + async def _add_to_index(self, embedding: np.ndarray) -> int: + async with self.safe_access_index() as index: + added_value = cast( + npt.NDArray[np.int_], index.add(len(self.memories), embedding) + ) + return added_value.item() + + async def _search_index( + self, embedding: np.ndarray, matches: int = MemoryModel.DEFAULT_MEMORY_MATCHES + ) -> list[Memory]: + async with self.safe_access_index() as index: + search_matches = index.search(embedding, matches) + # mypy doesn't respect "old style" __getitem__/__len__ as iterable, + # so we have this ignore. SEE: https://github.com/python/mypy/issues/9737 + return [self.memories[m.key] for m in search_matches] # type: ignore[union-attr]
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/modules/llm_call.html b/docs/_build/html/_modules/ldp/graph/modules/llm_call.html new file mode 100644 index 00000000..a8f91bf3 --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/modules/llm_call.html @@ -0,0 +1,131 @@ + + + + + + + ldp.graph.modules.llm_call — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.modules.llm_call

+from collections.abc import Callable, Iterable
+from typing import Any, Generic, TypeVar
+
+from aviary.message import Message
+
+from ldp.graph import ConfigOp, FxnOp, LLMCallOp, OpResult, compute_graph
+
+TParsedMessage = TypeVar("TParsedMessage", bound=Message)
+
+
+
+[docs] +class ParsedLLMCallModule(Generic[TParsedMessage]): + """Module for a processing-based tool selection, with a learnable configuration.""" + + def __init__( + self, llm_model: dict[str, Any], parser: Callable[..., TParsedMessage] + ): + self.config_op = ConfigOp[dict](config=llm_model) + self.llm_call_op = LLMCallOp() + self.parse_msg_op = FxnOp(parser) + + @compute_graph() + async def __call__( + self, messages: Iterable[Message], *parse_args, **parse_kwargs + ) -> tuple[OpResult[TParsedMessage], Message]: + raw_result = await self.llm_call_op(await self.config_op(), msgs=messages) + return await self.parse_msg_op( + raw_result, *parse_args, **parse_kwargs + ), raw_result.value
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/modules/react.html b/docs/_build/html/_modules/ldp/graph/modules/react.html new file mode 100644 index 00000000..99c9bf69 --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/modules/react.html @@ -0,0 +1,366 @@ + + + + + + + ldp.graph.modules.react — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.modules.react

+import ast
+import re
+import textwrap
+from collections.abc import Iterable
+from enum import StrEnum
+from typing import Any
+
+from aviary.message import EMPTY_CONTENT_BASE_MSG, MalformedMessageError, Message
+from aviary.tools import Tool, ToolCall, ToolRequestMessage
+
+from ldp.graph import FxnOp, OpResult, PromptOp, compute_graph
+from ldp.llms import prepend_sys
+
+from .llm_call import ParsedLLMCallModule
+
+_DEFAULT_PROMPT_TEMPLATE = textwrap.dedent(
+    """    Answer the following questions as best you can. You have access to the following tools:
+
+    {{tools}}
+
+    Use the following format:
+
+    {fields}
+    ... (this {fields_description} can repeat N times)
+
+    Example:
+
+    {example}"""
+)
+REACT_DEFAULT_PROMPT_TEMPLATE = _DEFAULT_PROMPT_TEMPLATE.format(
+    fields=(
+        "Thought: you should always think about what to do"
+        "\nAction: the action to take, should be one of [{tool_names}]"
+        "\nAction Input: comma separated list of inputs to action as python tuple"
+        "\nObservation: the result of the action"
+    ),
+    fields_description="Thought/Action/Action Input/Observation",
+    example=(
+        "Thought: I need to use the get_weather tool"
+        "\nAction: get_weather"
+        '\nAction Input: "New York", 7'
+        "\nObservation: The 7 day forecast for New York is [...]"
+    ),
+)
+ACT_DEFAULT_PROMPT_TEMPLATE = _DEFAULT_PROMPT_TEMPLATE.format(
+    fields=(
+        "Action: the action to take, should be one of [{tool_names}]"
+        "\nAction Input: comma separated list of inputs to action as python tuple"
+        "\nObservation: the result of the action"
+    ),
+    fields_description="Action/Action Input/Observation",
+    example=(
+        "Action: get_weather"
+        '\nAction Input: "New York", 7'
+        "\nObservation: The 7 day forecast for New York is [...]"
+    ),
+)
+
+
+
+[docs] +def parse_message(m: Message, tools: list[Tool]) -> ToolRequestMessage: # noqa: C901 + """ + Parse an Act or ReAct Message into a ToolRequestMessage. + + Args: + m: Input raw message. + tools: Tools used to confirm a valid tool selection + + Returns: + Parsed ToolRequestMessage. + """ + if not m.content: + raise MalformedMessageError( + f"{EMPTY_CONTENT_BASE_MSG} of type {type(m).__name__}." + ) + + message_content = m.content + # strip (and overwrite) up to end of action input + loc = message_content.find("Action Input:") + if loc != -1: + loc = message_content.find("\n", loc) + message_content = message_content[: loc if loc > 0 else None] + # we need to override the message too - don't want the model to hallucinate + m.content = message_content + + action_args: tuple[Any, ...] = () + # https://regex101.com/r/qmqZ7Z/1 + action_input = re.search(r"Input:[ \t]*([ \S]*)", m.content) + # only parse if it takes arguments + if action_input and action_input.group(1).strip(): + input_str = action_input.group(1).strip() + # if it has commas and no quotes, it's almost certainly a tuple without + # parentheses, so we add them + if "," in input_str and not ( + input_str.startswith("(") and input_str.endswith(")") + ): + input_str = f"({input_str})" + try: + if input_str.startswith("(") and input_str.endswith(")"): + # Handle tuples and quoted strings inside + if '"' not in input_str and "'" not in input_str: + # Add quotes around each element within parentheses if they are not already quoted + # and if they are not purely numbers. There may exist a killer regex for this + # but I am a simple man + + # just catches things like "1.1".isnumeric() == False + # so we can't just use isnumeric + def is_number(s: str) -> bool: + try: + float(s) + except ValueError: + return False + return True + + input_str = ", ".join( + f'"{e.strip()}"' if not is_number(e) else str(e) + for e in input_str.strip("()").split(",") + if e.strip() + ) + input_str = f"({input_str})" + eval_result = ast.literal_eval(input_str) + action_args = ( + (eval_result,) + if not isinstance(eval_result, tuple) + else eval_result + ) + else: + # Convert to int or float if possible + try: + action_args = (ast.literal_eval(input_str),) + except (ValueError, SyntaxError): + action_args = (input_str,) + except Exception as exc: + raise MalformedMessageError( + f"Action Input {input_str} could not be parsed." + ) from exc + + if len(action_args) == 1 and isinstance(action_args[0], tuple): + action_args = action_args[0] + + action = re.search(r"Action:[ \t]*(\S*)", m.content) + if not action: + raise MalformedMessageError("Action not emitted.") + tool_name = action.group(1).strip() + # have to match up name to tool to line up args in order + try: + tool = next(t for t in tools if t.info.name == tool_name) + except StopIteration as exc: + raise MalformedMessageError(f"Tool {tool_name} not found in tools.") from exc + if len(action_args) < len(tool.info.parameters.required): + raise MalformedMessageError( + f"Action Input {action_args!r} shorter than {tool.info.name!r} tool's" + " parameters." + ) + + # Anecdotally we've observed thought also often captures the action + # NOTE: for Act agents there is no Thought, so the regex will return None + thought = re.search(r"Thought:[ \t]*(.*)", m.content) + return ToolRequestMessage( + content=thought.group(1) if thought else None, + tool_calls=[ToolCall.from_tool(tool, *action_args)], + )
+ + + +
+[docs] +class ToolDescriptionMethods(StrEnum): + """Possible methods of describing the tools.""" + + STR = "describe_str" + XML = "describe_xml" + JSON = "describe_json" + +
+[docs] + def get_prompt_prefix(self) -> str: + """Get the prefix to put in front of the prompt.""" + if self == self.STR: + return "" + if self == self.JSON: + return "Tools are specified with a JSON schema." + return "Tools are specified with an XML schema."
+
+ + + +
+[docs] +class ReActModule: + """An Act or ReAct module built to work with chat models. + + Paper: https://arxiv.org/abs/2210.03629 + + The ReAct style is like so, and note Act style has no 'Thought: ' entries: + System: + Answer the following questions as best you can. You have access to the following tools: + + {tools} + + Use the following format: + + Thought: you should always think about what to do + Action: the action to take, should be one of [{tool_names}] + Action Input: the input to the action + Observation: the result of the action + ... (this Thought/Action/Action Input/Observation can repeat N times) + User: + {questions} + Assistant: + Thought: + Action: + Action Input: + User: + Observation: + Assistant: + Thought: + Action: + Action Input: + ... + """ + +
+[docs] + @staticmethod + def parse_message(m: Message, tools: list[Tool]) -> ToolRequestMessage: + return parse_message(m, tools)
+ + + async def _create_system_prompt(self, tools: list[Tool]) -> OpResult[str]: + tool_info = "\n".join([ + getattr(t.info, self._tool_description_method)() for t in tools + ]) + if prefix := self._tool_description_method.get_prompt_prefix(): + tool_info = f"{prefix}\n{tool_info}" + tool_names = ", ".join([t.info.name for t in tools]) + return await self.prompt_op( + schema_type=self._tool_description_method.value, + tools=tool_info.strip(), + tool_names=tool_names, + ) + + def __init__( + self, + llm_model: dict[str, Any], + sys_prompt: str = REACT_DEFAULT_PROMPT_TEMPLATE, + tool_description_method: ToolDescriptionMethods = ToolDescriptionMethods.STR, + ): + self.prompt_op = PromptOp(sys_prompt) + self._tool_description_method = tool_description_method + llm_model["stop"] = ["Observation:"] + self.package_msg_op = FxnOp(prepend_sys) + self.tool_select_module = ParsedLLMCallModule[ToolRequestMessage]( + llm_model=llm_model, parser=self.parse_message + ) + + @compute_graph() + async def __call__( + self, messages: Iterable[Message], tools: list[Tool] + ) -> tuple[OpResult[ToolRequestMessage], Message]: + packaged_msgs = await self.package_msg_op( + messages, sys_content=await self._create_system_prompt(tools) + ) + return await self.tool_select_module(packaged_msgs, tools=tools) # type: ignore[arg-type]
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/modules/reflect.html b/docs/_build/html/_modules/ldp/graph/modules/reflect.html new file mode 100644 index 00000000..72b6af7f --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/modules/reflect.html @@ -0,0 +1,164 @@ + + + + + + + ldp.graph.modules.reflect — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.modules.reflect

+from typing import Any
+
+from aviary.message import Message
+from pydantic import BaseModel, Field
+
+from ldp.graph import ConfigOp, FxnOp, LLMCallOp, PromptOp, compute_graph
+from ldp.graph.ops import ResultOrValue
+from ldp.llms import append_to_sys
+from ldp.llms.prompts import indent_xml
+
+
+
+[docs] +class ReflectModuleConfig(BaseModel): + """Configuration for the ReflectModuleConfig.""" + + llm_model: dict[str, Any] = Field( + default={"model": "gpt-3.5-turbo"}, + description="Starting configuration for the LLM model.", + )
+ + + +
+[docs] +class ReflectModule: + """A module that simply gives an LLM to reflect on an input.""" + + def __init__(self, start_config: ReflectModuleConfig): + self.llm_call_op = LLMCallOp() + self.prompt_op = PromptOp( + "Consider a proposed response based on context. Reflect on the response" + " within <thought> tags then conclude with a possibly revised response" + " within <final-response> tags." + ) + self.config_op = ConfigOp[ReflectModuleConfig](config=start_config) + self.llm_config_op = FxnOp[dict](lambda c: c.llm_model) + self.package_fxn = FxnOp(append_to_sys) + + def extract_msg(msg: Message, backup_response: str) -> str: + msg_str = msg.content + if msg_str and "<final-response>" in msg_str: + return msg_str.split("<final-response>")[1].split("</final-response>")[ + 0 + ] + if msg_str and "<response>" in msg_str: + return msg_str.split("<response>")[1].split("</response>")[0] + return backup_response + + self.extract_msg = FxnOp(extract_msg) + + @compute_graph() + async def __call__( + self, context: ResultOrValue[str], response: ResultOrValue[str] + ) -> ResultOrValue[str]: + llm_config = await self.llm_config_op(await self.config_op()) + sys_str = await self.prompt_op() + user_str = indent_xml( + f"<context>{context}</context><response>{response}</response>" + ) + msg = await self.package_fxn(user_str, sys_str) + llm_result = await self.llm_call_op(llm_config, msg) + return await self.extract_msg(llm_result, response)
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/modules/thought.html b/docs/_build/html/_modules/ldp/graph/modules/thought.html new file mode 100644 index 00000000..93b49fba --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/modules/thought.html @@ -0,0 +1,146 @@ + + + + + + + ldp.graph.modules.thought — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.modules.thought

+from collections.abc import Iterable, Mapping
+from typing import Any
+
+from aviary.message import Message
+from aviary.tools import ToolRequestMessage
+
+from ldp.graph import FxnOp, OpResult, PromptOp, compute_graph
+from ldp.llms import prepend_sys_and_append_sys
+
+from .llm_call import ParsedLLMCallModule
+
+
+
+[docs] +class ThoughtModule: + @staticmethod + def _downcast_to_message(message: Message | ToolRequestMessage) -> Message: + if isinstance(message, ToolRequestMessage): + # Downcast into a normal Message if the LLM tried to call tools + return Message(role=message.role, content=message.content) + return message + + def __init__( + self, llm_model: dict[str, Any], first_sys_prompt: str, second_sys_prompt: str + ): + self.first_sys_prompt_op = PromptOp(first_sys_prompt) + self.second_sys_prompt_op = PromptOp(second_sys_prompt) + self.package_msg_op = FxnOp(prepend_sys_and_append_sys) + self.llm_call = ParsedLLMCallModule[Message]( + llm_model, parser=self._downcast_to_message + ) + + @compute_graph() + async def __call__( + self, + messages: Iterable[Message], + first_prompt_kwargs: Mapping[str, Any], + second_prompt_kwargs: Mapping[str, Any], + ) -> OpResult[Message]: + packaged_msgs = await self.package_msg_op( + messages, + initial_sys_content=await self.first_sys_prompt_op(**first_prompt_kwargs), + final_sys_content=await self.second_sys_prompt_op(**second_prompt_kwargs), + ) + return (await self.llm_call(packaged_msgs))[0] # type: ignore[arg-type]
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/op_utils.html b/docs/_build/html/_modules/ldp/graph/op_utils.html new file mode 100644 index 00000000..03149253 --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/op_utils.html @@ -0,0 +1,295 @@ + + + + + + + ldp.graph.op_utils — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.op_utils

+import contextvars
+from collections.abc import AsyncIterator
+from contextlib import asynccontextmanager
+from uuid import UUID, uuid4
+
+from aviary.utils import is_coroutine_callable
+from pydantic import BaseModel, field_serializer, field_validator
+
+
+
+[docs] +class CallID(BaseModel): + run_id: UUID + fwd_id: UUID + + def __repr__(self) -> str: + return f"{self.run_id}:{self.fwd_id}" + + def __hash__(self) -> int: + return hash((self.run_id, self.fwd_id)) + +
+[docs] + @field_validator("run_id", "fwd_id", mode="before") + @classmethod + def validate_uuid(cls, value: UUID | str) -> UUID: + if isinstance(value, str): + return UUID(value) + return value
+ + +
+[docs] + @field_serializer("run_id", "fwd_id") + def serialize_uuid(self, value: UUID) -> str: + return str(value)
+ + + def __init__(self, run_id: str | UUID, fwd_id: str | UUID): + # Convenience so we can use positional arguments + super().__init__(run_id=run_id, fwd_id=fwd_id)
+ + + +_RUN_ID = contextvars.ContextVar[UUID]("run_id") +_CALL_ID = contextvars.ContextVar[CallID]("call_id") + + +
+[docs] +@asynccontextmanager +async def compute_graph() -> AsyncIterator[UUID]: + """Initialize a compute graph by setting a run ID. + + If a run ID is already set (i.e. we are already inside a + get_run_id() context), then the existing run ID is returned. + Otherwise, a new UUID is created. + """ + try: + # If a run ID is set, return it. + run_id = _RUN_ID.get() + token: contextvars.Token | None = None + except LookupError: + # If not, make a new run ID. + run_id = uuid4() + token = _RUN_ID.set(run_id) + + try: + yield run_id + finally: + if token is not None: + # token is not None if we made a new run ID. In that case, + # reset the context to its previous state. + _RUN_ID.reset(token)
+ + + +
+[docs] +def get_run_id() -> UUID: + """Get the current run ID.""" + try: + return _RUN_ID.get() + except LookupError: + raise RuntimeError( + "Attempting to access run ID, but not inside compute graph context." + ) from None
+ + + +
+[docs] +@asynccontextmanager +async def op_call() -> AsyncIterator[CallID]: + """Decorate an op call with a call ID. + + If a call ID is already set (i.e. we are already inside an op call), + then the existing call ID is returned. + Otherwise, a new UUID is created. + """ + # Get run_id in case we need to construct a CallID, but this also serves + # as a check that we're inside compute_graph() + run_id = get_run_id() + + try: + call_id = _CALL_ID.get() + token: contextvars.Token | None = None + except LookupError: + fwd_id = uuid4() + call_id = CallID(run_id, fwd_id) + token = _CALL_ID.set(call_id) + + try: + yield call_id + finally: + if token is not None: + # token is not None if we made a new call ID. In that case, + # reset the context to its previous state. + _CALL_ID.reset(token)
+ + + +
+[docs] +def get_call_id() -> CallID: + """Get the current call ID.""" + try: + return _CALL_ID.get() + except LookupError: + raise RuntimeError( + "Attempting to access call ID, but not inside op call context." + ) from None
+ + + +_TRAINING_MODE = contextvars.ContextVar[bool]("training_mode", default=True) + + +
+[docs] +def get_training_mode() -> bool: + """Get the current training mode.""" + return _TRAINING_MODE.get()
+ + + +
+[docs] +def set_training_mode(training_mode: bool) -> None: + """Set the training mode.""" + _TRAINING_MODE.set(training_mode)
+ + + +class _TrainingModeContext: + """Automatically set and reset the training_mode with a context manager.""" + + def __init__(self, training_mode: bool): + self.training_mode = training_mode + self.prev_training_mode = get_training_mode() + + def __call__(self, fn=None): + if fn is None: + return self + + if is_coroutine_callable(fn): + + async def wrapper(*args, **kwargs): + async with self: + return await fn(*args, **kwargs) + + else: + + def wrapper(*args, **kwargs): + with self: + return fn(*args, **kwargs) + + return wrapper + + def __enter__(self) -> None: + self.prev_training_mode = get_training_mode() + set_training_mode(self.training_mode) + + def __exit__(self, exc_type, exc_value, traceback) -> None: + set_training_mode(self.prev_training_mode) + + async def __aenter__(self) -> None: + self.__enter__() + + async def __aexit__(self, exc_type, exc_value, traceback) -> None: + self.__exit__(exc_type, exc_value, traceback) + + +train_mode = _TrainingModeContext(training_mode=True) +eval_mode = _TrainingModeContext(training_mode=False) +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/ops.html b/docs/_build/html/_modules/ldp/graph/ops.html new file mode 100644 index 00000000..c7f319c1 --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/ops.html @@ -0,0 +1,702 @@ + + + + + + + ldp.graph.ops — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.ops

+"""This module defines the Op class and its helper classes."""
+
+from __future__ import annotations
+
+import inspect
+import itertools
+import logging
+from abc import ABC, abstractmethod
+from collections import defaultdict
+from collections.abc import Callable, Collection, Iterable, Iterator, Mapping, Sequence
+from typing import Any, ClassVar, Generic, TypeAlias, TypeVar
+from uuid import UUID
+
+import networkx as nx
+import tree
+from pydantic import BaseModel, Field
+
+from .op_utils import CallID, compute_graph, get_call_id, get_training_mode, op_call
+
+logger = logging.getLogger(__name__)
+
+
+GradOutType: TypeAlias = tree.Structure | None  # None means the gradient has terminated
+GradInType: TypeAlias = tuple[Sequence[GradOutType], Mapping[str, GradOutType]]
+BackwardsType: TypeAlias = Callable[
+    # Call signature of Op.backward or GradientEstimator.backward
+    ["OpCtx", list, dict, tree.Structure, "CallID"], GradInType
+]
+TOutput = TypeVar("TOutput")
+
+
+
+[docs] +class OpResult(Generic[TOutput]): + """Result of a forward pass, used in the compute graph.""" + + def __init__( + self, call_id: CallID | Any, op_name: str, op_class_name: str, value: TOutput + ): + """ + Initialize an OpResult instance. + + Args: + call_id: The unique identifier for the call. + op_name: Name of the Op instance (i.e. op.name) that produced this OpResult. + op_class_name: Fully qualified name of the class of the Op that produced this OpResult. + value: The output of the call. + """ + self.call_id = CallID.model_validate(call_id) + self.op_name = op_name + self.op_class_name = op_class_name + self.value = value + +
+[docs] + def to_dict(self) -> dict[str, Any]: + value_dump = ( + self.value.model_dump() if isinstance(self.value, BaseModel) else self.value + ) + + return { + "call_id": self.call_id.model_dump(), + "op_name": self.op_name, + "op_class_name": self.op_class_name, + "value": value_dump, + }
+ + +
+[docs] + @classmethod + def from_dict( + cls, t_output: type[TOutput], dump: dict[str, Any] + ) -> OpResult[TOutput]: + value = dump.pop("value") + if issubclass(t_output, BaseModel): + value = t_output.model_validate(value) + + return cls[t_output](**dump, value=value) # type: ignore[index]
+ + + def __hash__(self) -> int: + return hash(self.call_id) + +
+[docs] + def compute_grads( + self, + grad_output: tree.Structure | None = None, + backward_fns: Mapping[str | type, BackwardsType] | None = None, + ) -> None: + """ + Compute the gradient of the backward graph in-place. + + This executes topological traversal. + It is up to the Op to: + (a) define the backward computation + (b) store internal gradients for optimizer updates. + """ + # call ID -> [d op(x) / d x] for each op that consumes x + grad_outputs: dict[CallID, list[tree.Structure]] = defaultdict(list) + + # grad_outputs stores a list of output grads (corresponding to each consuming op call). + # Since the root node is not consumed by any other node, we create a singleton list here. + # If None was passed, set it to 0 so that we don't prune the compute graph here. + grad_outputs[self.call_id] = [grad_output] if grad_output is not None else [0.0] + + # We will traverse the graph in reverse topological order + for node in self.traverse(): + # get output gradients + grad_output = grad_outputs[node.call_id] + if not grad_output: + # compute graph terminated + continue + # Make sure structure of grads match before summing + try: + [tree.assert_same_structure(grad_output[0], g) for g in grad_output[1:]] + except ValueError as e: + raise ValueError( + f"Mismatched gradient structures in compute graph for at Op: {self.op_name}." + ) from e + aggregated_grad_output = tree.map_structure(lambda *x: sum(x), *grad_output) # noqa: FURB111 + + input_args, input_kwargs = node.inputs + arg_grads, kwarg_grads = node._run_backward( + input_args, + input_kwargs, + aggregated_grad_output, + node._resolve_backward_impl(backward_fns), + ) + + for a, g in zip(input_args, arg_grads, strict=True): + # Must have exact match between input_args and arg_grads + # Only propagate gradients to input OpResults if grad is not None + if g is not None and isinstance(a, OpResult): + grad_outputs[a.call_id].append(g) + + if kwarg_grads.keys() != input_kwargs.keys(): + raise ValueError( + f"Mismatch between grads returned in Op.backward and its input kwargs. " + f"Expected {input_kwargs.keys()}, got {kwarg_grads.keys()}." + ) + for k, a in input_kwargs.items(): + # input_kwargs.keys() may be a subset of kwarg_grads.keys() if defaults + # are specified + if (g := kwarg_grads[k]) is not None and isinstance(a, OpResult): + grad_outputs[a.call_id].append(g)
+ + + def _resolve_backward_impl( + self, backward_fns: Mapping[str | type, BackwardsType] | None + ) -> BackwardsType: + backward_fns = backward_fns or {} + for key in (self.ctx.op_name, self.op_class_name, self.op_class): + if key in backward_fns: + return backward_fns[key] + return self.op_class.backward + + def _run_backward( + self, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: tree.Structure, + backward_fn: BackwardsType, + ) -> GradInType: + self._update_ctx("grad_output", grad_output) + unwrapped_input_args = [OpResult.unwrap_value(a) for a in input_args] + unwrapped_input_kwargs = { + k: OpResult.unwrap_value(v) for k, v in input_kwargs.items() + } + input_grads = backward_fn( + self.ctx, + unwrapped_input_args, + unwrapped_input_kwargs, + grad_output, + self.call_id, + ) + self._update_ctx("grad_input", input_grads) + return input_grads + + @property + def op_class(self) -> type[Op]: + return _OP_CLASS_REGISTRY[self.op_class_name] + + @property + def ctx(self) -> OpCtx: + # This is a property to avoid serialization of the context. There are two reasons: + # 1. Contexts have their own persist() mechanism for serialization + # 2. We'd prefer contexts to be created via get_or_create(). Allowing for arbitrary + # deserialization makes it hard to enforce that. + return OpCtx.get_or_create(self.op_name) + +
+[docs] + def get_compute_graph(self, backward: bool = True) -> nx.DiGraph: + """Construct a directed graph of the compute graph that led to this OpResult. + + Args: + backward: If True (default), constructs the backwards graph in which outputs + point to inputs. If False, constructs the forward call graph. + For most cases (e.g. backprop), backward=True is desirable. + + Returns: + A digraph in which nodes are OpResults. + """ + + def add_edges(graph: nx.DiGraph, node: OpResult) -> None: + """Recursively add edges to the input graph.""" + input_args, input_kwargs = node.inputs + for x in itertools.chain(input_args, input_kwargs.values()): + if isinstance(x, OpResult): + edge = (node, x) if backward else (x, node) + graph.add_edge(*edge) + add_edges(graph, x) + + graph = nx.DiGraph() + graph.add_node(self) + add_edges(graph, self) + + return graph
+ + +
+[docs] + def traverse( + self, + topological_order: bool = True, + filter_fn: Callable[[OpResult], bool] = lambda _: True, + ) -> Iterator[OpResult]: + """Traverse the compute graph that led to this OpResult. + + Args: + topological_order: If True, traverse the backwards graph in topological + order. This requires having the whole graph in memory. If False, + traverse the backwards graph in depth-first order. This can be done + lazily and is useful if we are trying to hydrate the graph node-by-node. + Most user-facing cases can leave this as True. Defaults to True. + filter_fn: Will only yield nodes that pass this filter function. Note that + nodes that fail will still be traversed. + + Yields: + An iterator over the nodes of this graph. + """ + if topological_order: + G = self.get_compute_graph() + for node in nx.topological_sort(G): + if filter_fn(node): + yield node + + else: + # If not topological order, do a recursive depth-first traversal. + # Note that, when traversing a node, its children do not need to be available + # yet. This allows us to lazily load nodes when hydrating from a ctx backend. + if filter_fn(self): + yield self + input_args, input_kwargs = self.inputs + for a in itertools.chain(input_args, input_kwargs.values()): + if isinstance(a, OpResult): + # Recursively apply depth-first traversal on each node + yield from a.traverse(topological_order=False)
+ + + @property + def inputs(self) -> tuple[list[ResultOrValue], dict[str, ResultOrValue]]: + return self._get_from_ctx("input") + + @property + def logprob(self) -> float | None: + return self._get_from_ctx("logprob", default=None) + + @property + def grad(self) -> tree.Structure | None: + """Returns `d ln(P_{compute_graph}) / d self` or None if gradients have not been computed.""" + return self._get_from_ctx("grad_output") + + @property + def run_id(self) -> UUID: + return self.call_id.run_id + +
+[docs] + @staticmethod + def unwrap_value(result: ResultOrValue[TOutput]) -> TOutput: + if isinstance(result, OpResult): + return result.value + return result
+ + + def __repr__(self) -> str: + return ( + f"OpResult(op={self.op_class_name}:{self.op_name}, " + f"call_id={self.call_id}, value={self.value!r})" + ) + + def __str__(self) -> str: + return str(self.value) + + def _get_from_ctx(self, key: str, **kwargs): + if self.call_id is None: + raise ValueError( + "Attempting to access context but compute graph " + "is not available for this OpResult." + ) + + return self.ctx.get(call_id=self.call_id, key=key, **kwargs) + + def _update_ctx(self, key: str, value: Any): + if self.call_id is None: + raise RuntimeError( + "Attempting to update context but compute graph " + "is not available for this OpResult." + ) + + self.ctx.update(call_id=self.call_id, key=key, value=value)
+ + + +ResultOrValue: TypeAlias = OpResult[TOutput] | TOutput + +# Sentinel value for get() default +NOT_FOUND = object() + + +
+[docs] +class OpCtx(BaseModel): + # A global registry of contexts. We'd prefer to use an existing context + # for an Op if it already has been created. Also useful for persist_all() + _CTX_REGISTRY: ClassVar[dict[str, OpCtx]] = {} + + op_name: str + + data: dict = Field( + default_factory=lambda: defaultdict(dict), + exclude=True, + description="Maps run_id -> (fwd_id, key) -> value. " + "data is excluded from model_dump() etc because we do " + "not use Pydantic to persist context information. That " + "should be done via the DB backend instead. OpCtx will " + "serialize op_name, which is enough to rehydrate " + "from the DB.", + ) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._CTX_REGISTRY[self.op_name] = self + +
+[docs] + @classmethod + def get_or_create(cls, op_name: str) -> OpCtx: + """Return an OpCtx corresponding to the Op with the given name.""" + try: + return cls._CTX_REGISTRY[op_name] # Get + except KeyError: + return cls(op_name=op_name) # Create
+ + +
+[docs] + @classmethod + def clear_contexts(cls, op_names: Iterable[str] | None = None) -> None: + """Clear the data in all contexts. If op_names is provided, only clear those contexts.""" + if op_names is None: + op_names = cls._CTX_REGISTRY.keys() + for op_name in op_names: + try: + cls._CTX_REGISTRY[op_name].data.clear() + except KeyError: + logger.warning(f"Op with name={op_name} not found in context registry.")
+ + +
+[docs] + def get(self, call_id: CallID, key: str, default: Any = NOT_FOUND) -> Any: + """Get an attribute with an optional default, emulating dict.get.""" + value = self.data.get(call_id.run_id, {}).get((call_id.fwd_id, key), default) + if value is NOT_FOUND: + raise KeyError(f"call_id={call_id}, key='{key}' not found in context") + return value
+ + +
+[docs] + def update(self, call_id: CallID, key: str, value: Any): + self.data[call_id.run_id][(call_id.fwd_id, key)] = value
+ + +
+[docs] + def get_input_grads(self, call_id: CallID) -> GradInType: + # TODO: this function name is confusing. Let's deprecate it. We only use it + # in tests as far as I can tell. + try: + return self.get(call_id, "grad_input") + except KeyError as exc: + raise ValueError( + f"No gradients have been computed for call_id={call_id}." + ) from exc
+
+ + + +
+[docs] +def resolve_fully_qualified_name(cls: type) -> str: + return f"{cls.__module__}.{cls.__name__}"
+ + + +# A global registry of Op classes, so we can look up backward() implementations +# without needing an instantiated Op. +_OP_CLASS_REGISTRY: dict[str, type[Op]] = {} + + +
+[docs] +class Op(ABC, Generic[TOutput]): + """ + An operation that is 'differentiable' and can be used in an optimizer. + + Think torch.autograd.Function that can also be applied to non-differentiable + operations like prompt template formatting or Python function calls. + + These form a forward computation graph when composed with other Ops via + __call__. In training mode, this graph is constructed dynamically. + """ + + # Name is not guaranteed to be unique. Reasons: + # 1. We definitely don't want it to be unique when recreating a compute graph + # for training on previously-collected data. In that case, we want the Op's + # name to be the same as it was before, to match up contexts/OpResults + # 2. Uniqueness could make some DB lookups faster, but I don't think we run the + # risk of OpCtx clobbers as long as call_id (which is guaranteed to be unique) + # is always used as part of the key. + name: str + ctx: OpCtx + _fwd_args: list[inspect.Parameter] + +
+[docs] + def clear_ctx(self) -> None: + self.ctx.data.clear()
+ + + def __init_subclass__(cls, **kwargs): + super().__init_subclass__(**kwargs) + _OP_CLASS_REGISTRY[resolve_fully_qualified_name(cls)] = cls + + def __new__(cls, *args, **kwargs): + instance = super().__new__(cls) + + # Needs to be overridden by caller if this Op is to have + # a unique name in the compute graph. c.f. Agent.__init_subclass__ + # for an example of how to do this. + instance.set_name(cls.__name__) + + # Set an attribute to help us map positional forward arguments to parameter + # names, for the backward pass. We do this on the instance and not cls b/c + # some instancees may override (e.g FxnOp). + fwd_sig = inspect.signature(instance.forward) + instance._fwd_args = list(fwd_sig.parameters.values()) + + return instance + +
+[docs] + def set_name(self, name: str) -> None: + self.name = name + self.ctx = OpCtx.get_or_create(name)
+ + + def __repr__(self) -> str: + return f"{self.__class__.__name__} (name={self.name}, id={id(self)})" + +
+[docs] + @abstractmethod + async def forward(self, *args, **kwargs) -> TOutput: + """ + Forward pass of the Op. Must accept call_id as an argument. + + Returns: + Depending on this Op's purpose, the return may be considered an action + (e.g. a tool call) or it may not (e.g. a loss calculation). + """
+ + +
+[docs] + @classmethod + @abstractmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs, + grad_output: tree.Structure, + call_id: CallID, + ) -> GradInType: + """ + Backward pass of the Op. + + Args: + ctx: Context that was used during the forward pass. + input_args: Variable-length input arguments passed to forward, i.e. + via *args. + input_kwargs: All other arguments passed to forward pass. + grad_output: A list of backpropagated gradients from each consumer + of the output of the forward pass. It is up to the implementation + to decide how to aggregate these gradients (e.g. in most cases summing). + call_id: Call ID of the forward pass. + + Returns: + grad_input: `d log(p) / d input` for each input to the forward pass. + It should include gradients for all input positional and keyword + arguments. Set to None for gradients that should terminate. + """
+ + +
+[docs] + def get_call_ids(self, run_ids: Collection[UUID] | None = None) -> set[CallID]: + ctx = self.ctx + if run_ids is None: + run_ids = ctx.data.keys() + + # de-duplicate before constructing CallIDs + ids = {(run_id, fwd_id) for run_id in run_ids for fwd_id, _ in ctx.data[run_id]} + return set(itertools.starmap(CallID, ids))
+ + + # This compute_graph() decoration will do nothing if we are already inside a compute graph. + # We add it here in case we are calling a bare op(), in which case we want a graph + # with a single node. + @compute_graph() + @op_call() + async def __call__(self, *args, **kwargs) -> OpResult[TOutput]: + call_id = get_call_id() + + if not all( + arg.call_id.run_id == call_id.run_id + for arg in itertools.chain(args, kwargs.values()) + if isinstance(arg, OpResult) + ): + raise RuntimeError( + "All args and kwargs must have the same run_id as the call_id's run_id. " + "Consider using @compute_graph() decorator to ensure this." + ) + + # we're over-saving here - can explore later if memory usage is high + # unpack the args and kwargs from the result holders + unpacked_args = [(a.value if isinstance(a, OpResult) else a) for a in args] + unpacked_kwargs = { + k: v.value if isinstance(v, OpResult) else v for k, v in kwargs.items() + } + + if get_training_mode(): + # If training, save the inputs for the backward pass + # Map positional arguments to keyword arguments to make backward pass easier + for i_arg, (arg, param) in enumerate( + # strict=False b/c not all params in _fwd_args will be in args (i.e. defaults and **kwargs) + zip(args, self._fwd_args, strict=False) + ): + # Don't need to check for too many args or collisions with kwargs, since forward() + # will raise an exception anyway + if param.kind == inspect.Parameter.VAR_POSITIONAL: + # *args, so scoop up the rest of the arg tuple. + var_args = list(args[i_arg:]) + break + + # Normal positional arg + kwargs[param.name] = arg + else: + var_args = [] # there were no *args if we got here + + self.ctx.update(call_id, "input", (var_args, kwargs)) + + # actually call forward pass with unpacked args and kwargs + result = await self.forward(*unpacked_args, **unpacked_kwargs) + t_output: type[TOutput] = type(result) + + # Now package up my result so it can be consumed by other calls. + # Explicitly specify t_output. OpResult[TOutput] returns a generic object + op_result = OpResult[t_output]( # type: ignore[valid-type] + value=result, + call_id=call_id, + op_name=self.name, + op_class_name=resolve_fully_qualified_name(type(self)), + ) + + if get_training_mode(): + self.ctx.update(call_id, "output", op_result) + + return op_result + +
+[docs] + def get_input_grads(self, call_id: CallID) -> GradInType: + return self.ctx.get_input_grads(call_id)
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/graph/torch_ops.html b/docs/_build/html/_modules/ldp/graph/torch_ops.html new file mode 100644 index 00000000..22a7cfa9 --- /dev/null +++ b/docs/_build/html/_modules/ldp/graph/torch_ops.html @@ -0,0 +1,254 @@ + + + + + + + ldp.graph.torch_ops — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.graph.torch_ops

+import inspect
+from collections.abc import Mapping, Sequence
+from typing import Any, ClassVar
+
+try:
+    import torch
+    from torch import nn
+except ImportError:
+    raise ImportError(
+        "ldp.graph.torch_ops requires PyTorch as a dependency. "
+        "Please run `pip install ldp[nn]`."
+    ) from None
+
+from .async_torch import async_protect_torch_call
+from .op_utils import CallID, get_call_id, get_training_mode
+from .ops import GradInType, Op, OpCtx, ResultOrValue
+
+
+
+[docs] +class TorchOp(Op[torch.Tensor]): + """An operation that wraps a PyTorch module.""" + + CTX_TENSOR_INPUT_KEY: ClassVar[str] = "tensor_input" + + def __init__(self, module: nn.Module): + super().__init__() + self.module = module + + # override forward args with the signature of the function + fwd_sig = inspect.signature(self.module.forward) + self._fwd_args = list(fwd_sig.parameters.values()) + + def __str__(self) -> str: + return f"{type(self).__name__} {type(self.module).__name__} ({id(self)})" + +
+[docs] + async def forward(self, *args, **kwargs: Any) -> torch.Tensor: + tensor_args = [ + arg + if isinstance(arg, torch.Tensor) + else torch.tensor(arg, requires_grad=True) + for arg in args + ] + tensor_kwargs = { + k: v if isinstance(v, torch.Tensor) else torch.tensor(v, requires_grad=True) + for k, v in kwargs.items() + } + + is_training = get_training_mode() + + if is_training: + store_tensor_inputs( + ctx=self.ctx, + key=self.CTX_TENSOR_INPUT_KEY, + tensor_args=tensor_args, + tensor_kwargs=tensor_kwargs, + fwd_args=self._fwd_args, + ) + + return await async_protect_torch_call(self.module, no_grad=not is_training)( + *tensor_args, **tensor_kwargs + )
+ + +
+[docs] + @classmethod + def backward( + cls, + ctx: OpCtx, + input_args: list[ResultOrValue], + input_kwargs: dict[str, ResultOrValue], + grad_output: float | torch.Tensor, + call_id: CallID, + ) -> GradInType: + tensor_args, tensor_kwargs = ctx.get(call_id, cls.CTX_TENSOR_INPUT_KEY) + n_pos_args = len(tensor_args) + output = ctx.get(call_id, "output").value + + if not isinstance(grad_output, torch.Tensor): + grad_output = torch.tensor(grad_output, dtype=output.dtype) + grad_output = grad_output.to(output.device) + + while grad_output.ndim < output.ndim: + # Assume we can broadcast, so expand dims + # e.g. if output.shape = (2, 1, 1) and grad_output is a scalar + # then we want to expand to (1, 1, 1) and then broadcast + grad_output = grad_output.unsqueeze(-1) + + if output.shape != grad_output.shape: + raise RuntimeError( + f"Output shape {output.shape} does not match grad_output shape {grad_output.shape}" + ) + + gradients = torch.autograd.grad( + output, + [*tensor_args, *tensor_kwargs.values()], + grad_outputs=grad_output, + allow_unused=True, + retain_graph=True, + ) + + grad_args = [grad.detach().cpu().float() for grad in gradients[:n_pos_args]] + grad_kwargs = { + k: grad.detach().cpu().float() + for k, grad in zip( + tensor_kwargs.keys(), gradients[n_pos_args:], strict=True + ) + } + + return grad_args, grad_kwargs
+
+ + + +
+[docs] +def store_tensor_inputs( + ctx: OpCtx, + key: str, + tensor_args: Sequence[torch.Tensor], + tensor_kwargs: Mapping[str, torch.Tensor], + fwd_args: Sequence[inspect.Parameter], + detach: bool = False, +) -> None: + call_id = get_call_id() + # Save tensor inputs for backward pass. Do not clobber "input", since + # that is needed for compute graph. Map positional args to kwargs + # Copying so we don't modify tensor_kwargs in-place + ctx_kwargs = tensor_kwargs.copy() # type: ignore[attr-defined] + + # See Op.__call__ for some notes on what this is doing. + for i_arg, (arg, param) in enumerate( + # strict=False b/c not all params in _fwd_args will be in args (i.e. defaults and **kwargs) + zip(tensor_args, fwd_args, strict=False) + ): + if param.kind == inspect.Parameter.VAR_POSITIONAL: + ctx_args = list(tensor_args[i_arg:]) + break + + # Normal positional arg + ctx_kwargs[param.name] = arg + else: + ctx_args = [] # if we got here, there were no *args + + if detach: + # Detach the tensors from the compute graph and move to CPU + ctx_args = [arg.detach().cpu() for arg in ctx_args] + ctx_kwargs = {k: v.detach().cpu() for k, v in ctx_kwargs.items()} + + ctx.update(call_id, key, (ctx_args, ctx_kwargs))
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/llms/chat.html b/docs/_build/html/_modules/ldp/llms/chat.html new file mode 100644 index 00000000..f05dca82 --- /dev/null +++ b/docs/_build/html/_modules/ldp/llms/chat.html @@ -0,0 +1,469 @@ + + + + + + + ldp.llms.chat — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.llms.chat

+import asyncio
+import json
+from collections.abc import AsyncGenerator, Callable, Iterable
+from datetime import datetime
+from typing import Any, ClassVar, Self, cast
+from uuid import UUID, uuid4
+
+import litellm
+from aviary.message import Message
+from aviary.tools import Tool, ToolRequestMessage, ToolsAdapter
+from aviary.utils import is_coroutine_callable
+from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator
+
+
+
+[docs] +class JSONSchemaValidationError(ValueError): + """Raised when the completion does not match the specified schema."""
+ + + +
+[docs] +class LLMResult(BaseModel): + """A class to hold the result of a LLM completion.""" + + id: UUID = Field(default_factory=uuid4) + config: dict | None = None + prompt: list[Message] | None = Field( + default=None, description="Messages sent to the LLM." + ) + messages: list[Message] | None = Field( + default=None, description="Messages received from the LLM." + ) + prompt_count: int = Field(default=0, description="Count of prompt tokens.") + completion_count: int = Field(default=0, description="Count of completion tokens.") + model: str + date: str = Field(default_factory=datetime.now().isoformat) + seconds_to_first_token: float | None = None + seconds_to_last_token: float = 0 + logprob: float | None = Field( + default=None, description="Sum of logprobs in the completion." + ) + system_fingerprint: str | None = Field( + default=None, description="System fingerprint received from the LLM." + ) + + @property + def prompt_and_completion_costs(self) -> tuple[float, float]: + """Get a two-tuple of prompt tokens cost and completion tokens cost, in USD.""" + return litellm.cost_per_token( + self.model, + prompt_tokens=self.prompt_count, + completion_tokens=self.completion_count, + ) + + @property + def provider(self) -> str: + """Get the model provider's name (e.g. "openai", "mistral").""" + return litellm.get_llm_provider(self.model)[1] + +
+[docs] + def get_supported_openai_params(self) -> list[str] | None: + """Get the supported OpenAI parameters for the model.""" + return litellm.get_supported_openai_params(self.model)
+
+ + + +
+[docs] +def sum_logprobs(choice: litellm.utils.Choices) -> float | None: + """Calculate the sum of the log probabilities of an LLM completion (a Choices object). + + Args: + choice: A sequence of choices from the completion. + + Returns: + The sum of the log probabilities of the choice. + """ + try: + logprob_obj = choice.logprobs + except AttributeError: + return None + if isinstance(logprob_obj, dict): + if logprob_obj.get("content"): + return sum( + logprob_info["logprob"] for logprob_info in logprob_obj["content"] + ) + elif choice.logprobs.content: + return sum(logprob_info.logprob for logprob_info in choice.logprobs.content) + return None
+ + + +
+[docs] +def validate_json_completion( + completion: litellm.ModelResponse, output_type: type[BaseModel] +) -> None: + """Validate a completion against a JSON schema. + + Args: + completion: The completion to validate. + output_type: The Pydantic model to validate the completion against. + """ + try: + for choice in completion.choices: + output_type.model_validate_json(choice.message.content or "") # type: ignore[union-attr] + except ValidationError as err: + raise JSONSchemaValidationError( + "The completion does not match the specified schema." + ) from err
+ + + +
+[docs] +class MultipleCompletionLLMModel(BaseModel): + """Run n completions at once, all starting from the same messages.""" + + model_config = ConfigDict(extra="forbid") + + # this should keep the original model + # if fine-tuned, this should still refer to the base model + name: str = "unknown" + config: dict = Field( + default={ + "model": "gpt-3.5-turbo", # Default model should have cheap input/output for testing + "temperature": 0.1, + } + ) + encoding: Any | None = None + + def __str__(self) -> str: + return f"{type(self).__name__} {self.name}" + +
+[docs] + @model_validator(mode="after") + def set_model_name(self) -> Self: + if ( + self.config.get("model") in {"gpt-3.5-turbo", None} + and self.name != "unknown" + or self.name != "unknown" + and "model" not in self.config + ): + self.config["model"] = self.name + elif "model" in self.config and self.name == "unknown": + self.name = self.config["model"] + # note we do not consider case where both are set + # because that could be true if the model is fine-tuned + return self
+ + +
+[docs] + async def achat( + self, messages: Iterable[Message], **kwargs + ) -> litellm.ModelResponse: + return await litellm.acompletion( + messages=[m.model_dump(by_alias=True) for m in messages], + **(self.config | kwargs), + )
+ + +
+[docs] + async def achat_iter(self, messages: Iterable[Message], **kwargs) -> AsyncGenerator: + return cast( + AsyncGenerator, + await litellm.acompletion( + messages=[m.model_dump(by_alias=True) for m in messages], + stream=True, + stream_options={ + "include_usage": True, # Included to get prompt token counts + }, + **(self.config | kwargs), + ), + )
+ + + # SEE: https://platform.openai.com/docs/api-reference/chat/create#chat-create-tool_choice + # > `required` means the model must call one or more tools. + TOOL_CHOICE_REQUIRED: ClassVar[str] = "required" + +
+[docs] + async def call( # noqa: C901, PLR0915 + self, + messages: list[Message], + callbacks: list[Callable] | None = None, + output_type: type[BaseModel] | None = None, + tools: list[Tool] | None = None, + tool_choice: Tool | str | None = TOOL_CHOICE_REQUIRED, + **chat_kwargs, + ) -> list[LLMResult]: + start_clock = asyncio.get_running_loop().time() + + # Deal with tools. OpenAI throws an error if tool list is empty, + # so skip this block if tools in (None, []) + if tools: + chat_kwargs["tools"] = ToolsAdapter.dump_python( + tools, exclude_none=True, by_alias=True + ) + if tool_choice is not None: + chat_kwargs["tool_choice"] = ( + { + "type": "function", + "function": {"name": tool_choice.info.name}, + } + if isinstance(tool_choice, Tool) + else tool_choice + ) + + # deal with specifying output type + if output_type is not None: + schema = json.dumps( + output_type.model_json_schema(mode="serialization"), indent=2 + ) + schema_msg = f"Respond following this JSON schema:\n\n{schema}" + # Get the system prompt and its index, or the index to add it + i, system_prompt = next( + ((i, m) for i, m in enumerate(messages) if m.role == "system"), + (0, None), + ) + messages = [ + *messages[:i], + system_prompt.append_text(schema_msg, inplace=False) + if system_prompt + else Message(role="system", content=schema_msg), + *messages[i + 1 if system_prompt else i :], + ] + chat_kwargs["response_format"] = {"type": "json_object"} + + # add static configuration to kwargs + chat_kwargs = self.config | chat_kwargs + n = chat_kwargs.get("n", 1) # number of completions + if n < 1: + raise ValueError("Number of completions (n) must be >= 1.") + + prompt = [ + m + if not isinstance(m, ToolRequestMessage) or m.tool_calls + # OpenAI doesn't allow for empty tool_calls lists, so downcast empty + # ToolRequestMessage to Message here + else Message(role=m.role, content=m.content) + for m in messages + ] + results: list[LLMResult] = [] + + if callbacks is None: + completion: litellm.ModelResponse = await self.achat(prompt, **chat_kwargs) + if output_type is not None: + validate_json_completion(completion, output_type) + + for choice in completion.choices: + if isinstance(choice, litellm.utils.StreamingChoices): + raise NotImplementedError("Streaming is not yet supported.") + + if ( + tools is not None # Allows for empty tools list + or choice.finish_reason == "tool_calls" + or (getattr(choice.message, "tool_calls", None) is not None) + ): + serialized_choice_message = choice.message.model_dump() + serialized_choice_message["tool_calls"] = ( + serialized_choice_message.get("tool_calls") or [] + ) + output_messages: list[Message | ToolRequestMessage] = [ + ToolRequestMessage(**serialized_choice_message) + ] + else: + output_messages = [Message(**choice.message.model_dump())] + + results.append( + LLMResult( + model=self.name, + config=chat_kwargs, + prompt=prompt, + messages=output_messages, + logprob=sum_logprobs(choice), + system_fingerprint=completion.system_fingerprint, + # Note that these counts are aggregated over all choices + completion_count=completion.usage.completion_tokens, # type: ignore[attr-defined,unused-ignore] + prompt_count=completion.usage.prompt_tokens, # type: ignore[attr-defined,unused-ignore] + ) + ) + else: + if tools: + raise NotImplementedError("Using tools with callbacks is not supported") + if n > 1: + raise NotImplementedError( + "Multiple completions with callbacks is not supported" + ) + result = LLMResult(model=self.name, config=chat_kwargs, prompt=prompt) + + sync_callbacks = [f for f in callbacks if not is_coroutine_callable(f)] + async_callbacks = [f for f in callbacks if is_coroutine_callable(f)] + stream_completion = await self.achat_iter(messages, **chat_kwargs) + text_result = [] + role = "assistant" + + async for chunk in stream_completion: + delta = chunk.choices[0].delta + role = delta.role or role + if delta.content: + s = delta.content + if result.seconds_to_first_token == 0: + result.seconds_to_first_token = ( + asyncio.get_running_loop().time() - start_clock + ) + text_result.append(s) + [await f(s) for f in async_callbacks] + [f(s) for f in sync_callbacks] + if hasattr(chunk, "usage"): + result.prompt_count = chunk.usage.prompt_tokens + + output = "".join(text_result) + result.completion_count = litellm.token_counter( + model=self.name, + text=output, + ) + # TODO: figure out how tools stream, and log probs + result.messages = [Message(role=role, content=output)] + results.append(result) + + if not results: + # This happens in unit tests. We should probably not keep this block around + # long-term. Previously, we would emit an empty ToolRequestMessage if + # completion.choices were empty, so I am replicating that here. + results.append( + LLMResult( + model=self.name, + config=chat_kwargs, + prompt=prompt, + messages=[ToolRequestMessage(tool_calls=[])], + ) + ) + + end_clock = asyncio.get_running_loop().time() + + for result in results: + # Manually update prompt count if not set, which can + # happen if the target model doesn't support 'include_usage' + if not result.prompt_count: + result.prompt_count = litellm.token_counter( + model=self.name, + messages=[m.model_dump() for m in result.messages], # type: ignore[union-attr] + ) + + # update with server-side counts + result.seconds_to_last_token = end_clock - start_clock + + return results
+
+ + + +
+[docs] +class LLMModel(MultipleCompletionLLMModel): +
+[docs] + async def call(self, *args, **kwargs) -> LLMResult: # type: ignore[override] + return (await super().call(*args, **kwargs))[0]
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/llms/embeddings.html b/docs/_build/html/_modules/ldp/llms/embeddings.html new file mode 100644 index 00000000..874ebae9 --- /dev/null +++ b/docs/_build/html/_modules/ldp/llms/embeddings.html @@ -0,0 +1,276 @@ + + + + + + + ldp.llms.embeddings — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.llms.embeddings

+import asyncio
+from abc import ABC, abstractmethod
+from enum import StrEnum
+from typing import Any
+
+import litellm
+import numpy as np
+import tiktoken
+from pydantic import BaseModel, ConfigDict, Field, model_validator
+
+
+
+[docs] +class EmbeddingModes(StrEnum): + """Enum representing the different modes of an embedding model.""" + + DOCUMENT = "document" + QUERY = "query"
+ + + +
+[docs] +class EmbeddingModel(ABC, BaseModel): + name: str + dimensions: int | None = None + +
+[docs] + def set_mode(self, mode: EmbeddingModes) -> None: + """Several embedding models have a 'mode' or prompt which affects output."""
+ + +
+[docs] + @abstractmethod + async def embed_texts(self, texts: list[str]) -> list[np.ndarray]: + pass
+ + +
+[docs] + async def embed_text(self, text: str) -> np.ndarray: + return (await self.embed_texts([text]))[0]
+ + +
+[docs] + @staticmethod + def from_name(embedding: str, **kwargs) -> "EmbeddingModel": + if embedding.startswith("hybrid"): + dense_model = LiteEmbeddingModel(name="-".join(embedding.split("-")[1:])) + return HybridEmbeddingModel( + name=embedding, models=[dense_model, SparseEmbeddingModel(**kwargs)] + ) + if embedding == "sparse": + return SparseEmbeddingModel(**kwargs) + return LiteEmbeddingModel(name=embedding, **kwargs)
+
+ + + +
+[docs] +class LiteEmbeddingModel(EmbeddingModel): + name: str = Field(default="text-embedding-3-small") + dimensions: int | None = Field( + default=None, + description=( + "The length an embedding will have. If left unspecified, we attempt to" + " infer an un-truncated length via LiteLLM's internal model map. If this" + " inference fails, the embedding will be un-truncated." + ), + ) + batch_size: int = 16 + embed_kwargs: dict[str, Any] = Field( + default_factory=dict, + description="Extra kwargs to pass to litellm.aembedding.", + ) + +
+[docs] + @model_validator(mode="before") + @classmethod + def infer_dimensions(cls, data: dict[str, Any]) -> dict[str, Any]: + if data.get("dimensions") is not None: + return data + # Let's infer the dimensions + config: dict[str, dict[str, Any]] = litellm.get_model_cost_map( + url="https://raw.githubusercontent.com/BerriAI/litellm/main/litellm/model_prices_and_context_window_backup.json" + ) + output_vector_size: int | None = config.get(data.get("name", ""), {}).get( # noqa: FURB184 + "output_vector_size" + ) + if output_vector_size: + data["dimensions"] = output_vector_size + return data
+ + +
+[docs] + async def embed_texts(self, texts: list[str]) -> list[np.ndarray]: + embeddings = [] + # Before you get excited to asyncio.gather this: + # The point of this is to not hit the API rate limit + for i in range(0, len(texts), self.batch_size): + response = await litellm.aembedding( + model=self.name, + input=texts[i : i + self.batch_size], + encoding_format="float", + dimensions=self.dimensions, + **self.embed_kwargs, + ) + embeddings.extend([ + np.array(e["embedding"], dtype=np.float32) for e in response.data + ]) + return embeddings
+
+ + + +
+[docs] +class SparseEmbeddingModel(EmbeddingModel): + """This is a very simple keyword search model - probably best to be mixed with others.""" + + model_config = ConfigDict(arbitrary_types_allowed=True) + + name: str = "sparse" + dimensions: int = 256 + enc: tiktoken.Encoding = Field( + default_factory=lambda: tiktoken.get_encoding("cl100k_base") + ) + +
+[docs] + async def embed_texts(self, texts) -> list[np.ndarray]: + enc_batch = self.enc.encode_ordinary_batch(texts) + # now get frequency of each token rel to length + return [ + np.bincount( + [xi % self.dimensions for xi in x], minlength=self.dimensions + ).astype(np.float32) + / len(x) + for x in enc_batch + ]
+
+ + + +
+[docs] +class HybridEmbeddingModel(EmbeddingModel): + name: str = "hybrid-embed" + models: list[EmbeddingModel] + +
+[docs] + @model_validator(mode="before") + @classmethod + def infer_dimensions(cls, data: dict[str, Any]) -> dict[str, Any]: + if data.get("dimensions") is not None: + raise ValueError(f"Don't specify dimensions to {cls.__name__}.") + if not data.get("models") or any(m.dimensions is None for m in data["models"]): + return data + data["dimensions"] = sum(m.dimensions for m in data["models"]) + return data
+ + +
+[docs] + async def embed_texts(self, texts): + all_embeds = await asyncio.gather(*[m.embed_texts(texts) for m in self.models]) + return np.concatenate(all_embeds, axis=1)
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/llms/prompts.html b/docs/_build/html/_modules/ldp/llms/prompts.html new file mode 100644 index 00000000..4905f6f1 --- /dev/null +++ b/docs/_build/html/_modules/ldp/llms/prompts.html @@ -0,0 +1,215 @@ + + + + + + + ldp.llms.prompts — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.llms.prompts

+"""This module provides utility functions for appending and prepending system messages."""
+
+from collections.abc import Collection, Iterable
+
+from aviary.message import Message
+
+
+
+[docs] +def append_to_messages(messages: list[Message], new_message: Message) -> list[Message]: + """Appends a message to a list of messages, returning that in-place modified list. + + Examples: + >>> messages = [Message(content="Hello")] + >>> modified_messages = append_to_messages(messages, Message(content="New")) + >>> modified_messages + [Message(role='user', content='Hello'), Message(role='user', content='New')] + >>> id(messages) == id(modified_messages) + True + """ + messages.append(new_message) + return messages
+ + + +
+[docs] +def append_to_sys(user_content: str, sys_content: str | None = None) -> list[Message]: + """Appends a user message to a list of messages, optionally including a system message. + + Args: + user_content: The content of the user message. + sys_content: Optional content for the system message. Defaults to None. + + Returns: + A list of messages including the optional system message and the user message. + + Examples: + >>> append_to_sys("Hello, world!") + [Message(role='user', content='Hello, world!')] + + >>> append_to_sys("Hello, world!", "System initialized.") + [Message(role='system', content='System initialized.'), Message(role='user', content='Hello, world!')] + """ + sys = [Message(role="system", content=sys_content)] if sys_content else [] + return [*sys, Message(content=user_content)]
+ + + +
+[docs] +def prepend_sys(messages: Collection, sys_content: str) -> list[Message]: + """Prepends a system message to a list of messages. + + Args: + messages: The list of existing messages. + sys_content: The content of the system message to be prepended. + + Returns: + A new list of messages with the system message prepended. + + Examples: + >>> messages = [Message(role="user", content="Hello!")] + >>> prepend_sys(messages, "System initialized.") + [Message(role='system', content='System initialized.'), Message(role='user', content='Hello!')] + """ + return [Message(role="system", content=sys_content), *messages]
+ + + +
+[docs] +def indent_xml(xml_string, indent_size=2): + output = [] + indent_level = 0 + + # Split the input XML into parts by tags + parts = xml_string.replace(">", ">\n").replace("<", "\n<").split("\n") + parts = [part for part in parts if part.strip()] # Remove empty parts + + for part in parts: + if part.startswith("</"): + # Closing tag, decrease indent + indent_level -= indent_size + output.append(" " * indent_level + part) + elif part.startswith("<") and not part.endswith("/>") and ">" in part: + # Opening tag, maintain then increase indent + output.append(" " * indent_level + part) + indent_level += indent_size + elif part.endswith("/>"): + # Self-closing tag, just append + output.append(" " * indent_level + part) + else: + # Text or other data, maintain current indent + # Handle multiple lines within text nodes + text_lines = part.split("\n") + output.extend([ + " " * indent_level + line.strip() for line in text_lines if line.strip() + ]) + + return "\n".join(output)
+ + + +
+[docs] +def prepend_sys_and_append_sys( + messages: Iterable[Message], initial_sys_content: str, final_sys_content: str +) -> list[Message]: + return [ + Message(role="system", content=initial_sys_content), + *messages, + Message(role="system", content=final_sys_content), + ]
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/main.html b/docs/_build/html/_modules/ldp/main.html new file mode 100644 index 00000000..b12be050 --- /dev/null +++ b/docs/_build/html/_modules/ldp/main.html @@ -0,0 +1,179 @@ + + + + + + + ldp.main — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.main

+import argparse
+import asyncio
+import pickle
+from contextlib import suppress
+from os import PathLike
+from pathlib import Path
+
+from aviary.env import Environment
+
+from ldp.agent import Agent
+from ldp.alg.callbacks import TerminalPrintingCallback
+from ldp.alg.rollout import RolloutManager
+
+
+
+[docs] +def get_or_make_agent(agent: Agent | str | PathLike) -> Agent: + if isinstance(agent, Agent): + return agent + + if isinstance(agent, str): + with suppress(KeyError): + return Agent.from_name(agent) + + path = Path(agent) + if not path.exists(): + raise ValueError(f"Could not resolve agent: {agent}") + + with path.open("rb") as f: + return pickle.load(f) # noqa: S301
+ + + +
+[docs] +def get_or_make_environment(environment: Environment | str, task: str) -> Environment: + if isinstance(environment, Environment): + return environment + + if isinstance(environment, str): + with suppress(KeyError): + return Environment.from_name(environment, task=task) + + raise ValueError( + f"Could not resolve environment: {environment}. Available environments: {Environment.available()}" + )
+ + + +
+[docs] +async def main( + task: str, + environment: Environment | str, + agent: Agent | str | PathLike = "SimpleAgent", +): + agent = get_or_make_agent(agent) + + callback = TerminalPrintingCallback() + rollout_manager = RolloutManager(agent=agent, callbacks=[callback]) + + _ = await rollout_manager.sample_trajectories( + environment_factory=lambda: get_or_make_environment(environment, task) + )
+ + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("task", help="Task to prompt environment with.") + parser.add_argument( + "--env", required=True, help="Environment to sample trajectories from." + ) + parser.add_argument( + "--agent", default="SimpleAgent", help="Agent to sample trajectories with." + ) + args = parser.parse_args() + + asyncio.run(main(args.task, args.env, args.agent)) +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/ldp/utils.html b/docs/_build/html/_modules/ldp/utils.html new file mode 100644 index 00000000..404f07b9 --- /dev/null +++ b/docs/_build/html/_modules/ldp/utils.html @@ -0,0 +1,215 @@ + + + + + + + ldp.utils — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for ldp.utils

+import logging
+import logging.config
+import os
+from typing import Any
+
+import litellm
+
+
+
+[docs] +def configure_log_levels() -> None: + """Configure log levels.""" + # Set sane default LiteLLM logging configuration + # SEE: https://docs.litellm.ai/docs/observability/telemetry + litellm.telemetry = False + if ( + logging.getLevelNamesMapping().get( + os.environ.get("LITELLM_LOG", ""), logging.WARNING + ) + < logging.WARNING + ): + # If LITELLM_LOG is DEBUG or INFO, don't change the LiteLLM log levels + litellm_loggers_config: dict[str, Any] = {} + else: + litellm_loggers_config = { + "LiteLLM": {"level": "WARNING"}, + "LiteLLM Proxy": {"level": "WARNING"}, + "LiteLLM Router": {"level": "WARNING"}, + } + + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + # Lower level for httpx and LiteLLM + "loggers": {"httpx": {"level": "WARNING"}} | litellm_loggers_config, + })
+ + + +
+[docs] +def configure_stdout_logs( + level: int | str = logging.INFO, + fmt: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s", +) -> None: + """Configure root logger to log to stdout. + + Args: + level: Log level to be emitted to stdout. + fmt: Optional format string. + """ + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "formatters": {"standard": {"format": fmt}}, + "handlers": { + "stdout": { + "level": "INFO", + "formatter": "standard", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + }, + "root": {"level": level, "handlers": ["stdout"]}, + })
+ + + +
+[docs] +def discounted_returns( + rewards: list[float], terminated: list[bool], discount: float = 1.0 +) -> list[float]: + r""" + Calculate the discounted returns for a list of rewards, considering termination flags and a discount factor. + + The discounted return represents the future discounted rewards from each time step onwards, taking into account + whether an episode has terminated at each step. + + The discounted return \( G_t \) is given by: + + .. math:: + G_t = \sum_{k=1}^{\infty} \gamma^{k-1} R_{t+k} + + where: + - \( G_t \) is the discounted return starting from time step \( t \). + - \( \gamma \) is the discount factor. + - \( R_{t+k} \) is the reward received at time step \( t+k \). + + NOTE: this could live in ldp.alg, but it's here to avoid circular imports. + + Args: + rewards: A list of rewards at each time step. + terminated: A list of boolean flags indicating whether the episode terminated at each time step. + discount: Discount factor to apply to future rewards. Defaults to 1.0 which means no discounting is applied. + + Returns: + A list of discounted returns (rewards to go), with each element representing the + total discounted reward from that step onwards. + + Example: + >>> rewards = [1.0, 2.0, 3.0] + >>> terminated = [False, False, True] + >>> discounted_returns(rewards, terminated, discount=0.9) + [5.23, 4.7, 3.0] + """ + returns = [] + r = 0.0 + for reward, term in zip(reversed(rewards), reversed(terminated), strict=False): + # 1 - term is 0 if the episode has terminated + r = reward + discount * r * (1 - term) + returns.append(r) + returns.reverse() + return returns
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/tqdm/std.html b/docs/_build/html/_modules/tqdm/std.html new file mode 100644 index 00000000..57aede77 --- /dev/null +++ b/docs/_build/html/_modules/tqdm/std.html @@ -0,0 +1,1699 @@ + + + + + + + tqdm.std — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for tqdm.std

+"""
+Customisable progressbar decorator for iterators.
+Includes a default `range` iterator printing to `stderr`.
+
+Usage:
+>>> from tqdm import trange, tqdm
+>>> for i in trange(10):
+...     ...
+"""
+import sys
+from collections import OrderedDict, defaultdict
+from contextlib import contextmanager
+from datetime import datetime, timedelta, timezone
+from numbers import Number
+from time import time
+from warnings import warn
+from weakref import WeakSet
+
+from ._monitor import TMonitor
+from .utils import (
+    CallbackIOWrapper, Comparable, DisableOnWriteError, FormatReplace, SimpleTextIOWrapper,
+    _is_ascii, _screen_shape_wrapper, _supports_unicode, _term_move_up, disp_len, disp_trim,
+    envwrap)
+
+__author__ = "https://github.com/tqdm/tqdm#contributions"
+__all__ = ['tqdm', 'trange',
+           'TqdmTypeError', 'TqdmKeyError', 'TqdmWarning',
+           'TqdmExperimentalWarning', 'TqdmDeprecationWarning',
+           'TqdmMonitorWarning']
+
+
+class TqdmTypeError(TypeError):
+    pass
+
+
+class TqdmKeyError(KeyError):
+    pass
+
+
+class TqdmWarning(Warning):
+    """base class for all tqdm warnings.
+
+    Used for non-external-code-breaking errors, such as garbled printing.
+    """
+    def __init__(self, msg, fp_write=None, *a, **k):
+        if fp_write is not None:
+            fp_write("\n" + self.__class__.__name__ + ": " + str(msg).rstrip() + '\n')
+        else:
+            super().__init__(msg, *a, **k)
+
+
+class TqdmExperimentalWarning(TqdmWarning, FutureWarning):
+    """beta feature, unstable API and behaviour"""
+    pass
+
+
+class TqdmDeprecationWarning(TqdmWarning, DeprecationWarning):
+    # not suppressed if raised
+    pass
+
+
+class TqdmMonitorWarning(TqdmWarning, RuntimeWarning):
+    """tqdm monitor errors which do not affect external functionality"""
+    pass
+
+
+def TRLock(*args, **kwargs):
+    """threading RLock"""
+    try:
+        from threading import RLock
+        return RLock(*args, **kwargs)
+    except (ImportError, OSError):  # pragma: no cover
+        pass
+
+
+class TqdmDefaultWriteLock(object):
+    """
+    Provide a default write lock for thread and multiprocessing safety.
+    Works only on platforms supporting `fork` (so Windows is excluded).
+    You must initialise a `tqdm` or `TqdmDefaultWriteLock` instance
+    before forking in order for the write lock to work.
+    On Windows, you need to supply the lock from the parent to the children as
+    an argument to joblib or the parallelism lib you use.
+    """
+    # global thread lock so no setup required for multithreading.
+    # NB: Do not create multiprocessing lock as it sets the multiprocessing
+    # context, disallowing `spawn()`/`forkserver()`
+    th_lock = TRLock()
+
+    def __init__(self):
+        # Create global parallelism locks to avoid racing issues with parallel
+        # bars works only if fork available (Linux/MacOSX, but not Windows)
+        cls = type(self)
+        root_lock = cls.th_lock
+        if root_lock is not None:
+            root_lock.acquire()
+        cls.create_mp_lock()
+        self.locks = [lk for lk in [cls.mp_lock, cls.th_lock] if lk is not None]
+        if root_lock is not None:
+            root_lock.release()
+
+    def acquire(self, *a, **k):
+        for lock in self.locks:
+            lock.acquire(*a, **k)
+
+    def release(self):
+        for lock in self.locks[::-1]:  # Release in inverse order of acquisition
+            lock.release()
+
+    def __enter__(self):
+        self.acquire()
+
+    def __exit__(self, *exc):
+        self.release()
+
+    @classmethod
+    def create_mp_lock(cls):
+        if not hasattr(cls, 'mp_lock'):
+            try:
+                from multiprocessing import RLock
+                cls.mp_lock = RLock()
+            except (ImportError, OSError):  # pragma: no cover
+                cls.mp_lock = None
+
+    @classmethod
+    def create_th_lock(cls):
+        assert hasattr(cls, 'th_lock')
+        warn("create_th_lock not needed anymore", TqdmDeprecationWarning, stacklevel=2)
+
+
+class Bar(object):
+    """
+    `str.format`-able bar with format specifiers: `[width][type]`
+
+    - `width`
+      + unspecified (default): use `self.default_len`
+      + `int >= 0`: overrides `self.default_len`
+      + `int < 0`: subtract from `self.default_len`
+    - `type`
+      + `a`: ascii (`charset=self.ASCII` override)
+      + `u`: unicode (`charset=self.UTF` override)
+      + `b`: blank (`charset="  "` override)
+    """
+    ASCII = " 123456789#"
+    UTF = u" " + u''.join(map(chr, range(0x258F, 0x2587, -1)))
+    BLANK = "  "
+    COLOUR_RESET = '\x1b[0m'
+    COLOUR_RGB = '\x1b[38;2;%d;%d;%dm'
+    COLOURS = {'BLACK': '\x1b[30m', 'RED': '\x1b[31m', 'GREEN': '\x1b[32m',
+               'YELLOW': '\x1b[33m', 'BLUE': '\x1b[34m', 'MAGENTA': '\x1b[35m',
+               'CYAN': '\x1b[36m', 'WHITE': '\x1b[37m'}
+
+    def __init__(self, frac, default_len=10, charset=UTF, colour=None):
+        if not 0 <= frac <= 1:
+            warn("clamping frac to range [0, 1]", TqdmWarning, stacklevel=2)
+            frac = max(0, min(1, frac))
+        assert default_len > 0
+        self.frac = frac
+        self.default_len = default_len
+        self.charset = charset
+        self.colour = colour
+
+    @property
+    def colour(self):
+        return self._colour
+
+    @colour.setter
+    def colour(self, value):
+        if not value:
+            self._colour = None
+            return
+        try:
+            if value.upper() in self.COLOURS:
+                self._colour = self.COLOURS[value.upper()]
+            elif value[0] == '#' and len(value) == 7:
+                self._colour = self.COLOUR_RGB % tuple(
+                    int(i, 16) for i in (value[1:3], value[3:5], value[5:7]))
+            else:
+                raise KeyError
+        except (KeyError, AttributeError):
+            warn("Unknown colour (%s); valid choices: [hex (#00ff00), %s]" % (
+                 value, ", ".join(self.COLOURS)),
+                 TqdmWarning, stacklevel=2)
+            self._colour = None
+
+    def __format__(self, format_spec):
+        if format_spec:
+            _type = format_spec[-1].lower()
+            try:
+                charset = {'a': self.ASCII, 'u': self.UTF, 'b': self.BLANK}[_type]
+            except KeyError:
+                charset = self.charset
+            else:
+                format_spec = format_spec[:-1]
+            if format_spec:
+                N_BARS = int(format_spec)
+                if N_BARS < 0:
+                    N_BARS += self.default_len
+            else:
+                N_BARS = self.default_len
+        else:
+            charset = self.charset
+            N_BARS = self.default_len
+
+        nsyms = len(charset) - 1
+        bar_length, frac_bar_length = divmod(int(self.frac * N_BARS * nsyms), nsyms)
+
+        res = charset[-1] * bar_length
+        if bar_length < N_BARS:  # whitespace padding
+            res = res + charset[frac_bar_length] + charset[0] * (N_BARS - bar_length - 1)
+        return self.colour + res + self.COLOUR_RESET if self.colour else res
+
+
+class EMA(object):
+    """
+    Exponential moving average: smoothing to give progressively lower
+    weights to older values.
+
+    Parameters
+    ----------
+    smoothing  : float, optional
+        Smoothing factor in range [0, 1], [default: 0.3].
+        Increase to give more weight to recent values.
+        Ranges from 0 (yields old value) to 1 (yields new value).
+    """
+    def __init__(self, smoothing=0.3):
+        self.alpha = smoothing
+        self.last = 0
+        self.calls = 0
+
+    def __call__(self, x=None):
+        """
+        Parameters
+        ----------
+        x  : float
+            New value to include in EMA.
+        """
+        beta = 1 - self.alpha
+        if x is not None:
+            self.last = self.alpha * x + beta * self.last
+            self.calls += 1
+        return self.last / (1 - beta ** self.calls) if self.calls else self.last
+
+
+
+[docs] +class tqdm(Comparable): + """ + Decorate an iterable object, returning an iterator which acts exactly + like the original iterable, but prints a dynamically updating + progressbar every time a value is requested. + + Parameters + ---------- + iterable : iterable, optional + Iterable to decorate with a progressbar. + Leave blank to manually manage the updates. + desc : str, optional + Prefix for the progressbar. + total : int or float, optional + The number of expected iterations. If unspecified, + len(iterable) is used if possible. If float("inf") or as a last + resort, only basic progress statistics are displayed + (no ETA, no progressbar). + If `gui` is True and this parameter needs subsequent updating, + specify an initial arbitrary large positive number, + e.g. 9e9. + leave : bool, optional + If [default: True], keeps all traces of the progressbar + upon termination of iteration. + If `None`, will leave only if `position` is `0`. + file : `io.TextIOWrapper` or `io.StringIO`, optional + Specifies where to output the progress messages + (default: sys.stderr). Uses `file.write(str)` and `file.flush()` + methods. For encoding, see `write_bytes`. + ncols : int, optional + The width of the entire output message. If specified, + dynamically resizes the progressbar to stay within this bound. + If unspecified, attempts to use environment width. The + fallback is a meter width of 10 and no limit for the counter and + statistics. If 0, will not print any meter (only stats). + mininterval : float, optional + Minimum progress display update interval [default: 0.1] seconds. + maxinterval : float, optional + Maximum progress display update interval [default: 10] seconds. + Automatically adjusts `miniters` to correspond to `mininterval` + after long display update lag. Only works if `dynamic_miniters` + or monitor thread is enabled. + miniters : int or float, optional + Minimum progress display update interval, in iterations. + If 0 and `dynamic_miniters`, will automatically adjust to equal + `mininterval` (more CPU efficient, good for tight loops). + If > 0, will skip display of specified number of iterations. + Tweak this and `mininterval` to get very efficient loops. + If your progress is erratic with both fast and slow iterations + (network, skipping items, etc) you should set miniters=1. + ascii : bool or str, optional + If unspecified or False, use unicode (smooth blocks) to fill + the meter. The fallback is to use ASCII characters " 123456789#". + disable : bool, optional + Whether to disable the entire progressbar wrapper + [default: False]. If set to None, disable on non-TTY. + unit : str, optional + String that will be used to define the unit of each iteration + [default: it]. + unit_scale : bool or int or float, optional + If 1 or True, the number of iterations will be reduced/scaled + automatically and a metric prefix following the + International System of Units standard will be added + (kilo, mega, etc.) [default: False]. If any other non-zero + number, will scale `total` and `n`. + dynamic_ncols : bool, optional + If set, constantly alters `ncols` and `nrows` to the + environment (allowing for window resizes) [default: False]. + smoothing : float, optional + Exponential moving average smoothing factor for speed estimates + (ignored in GUI mode). Ranges from 0 (average speed) to 1 + (current/instantaneous speed) [default: 0.3]. + bar_format : str, optional + Specify a custom bar string formatting. May impact performance. + [default: '{l_bar}{bar}{r_bar}'], where + l_bar='{desc}: {percentage:3.0f}%|' and + r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' + '{rate_fmt}{postfix}]' + Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, + percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, + rate, rate_fmt, rate_noinv, rate_noinv_fmt, + rate_inv, rate_inv_fmt, postfix, unit_divisor, + remaining, remaining_s, eta. + Note that a trailing ": " is automatically removed after {desc} + if the latter is empty. + initial : int or float, optional + The initial counter value. Useful when restarting a progress + bar [default: 0]. If using float, consider specifying `{n:.3f}` + or similar in `bar_format`, or specifying `unit_scale`. + position : int, optional + Specify the line offset to print this bar (starting from 0) + Automatic if unspecified. + Useful to manage multiple bars at once (eg, from threads). + postfix : dict or *, optional + Specify additional stats to display at the end of the bar. + Calls `set_postfix(**postfix)` if possible (dict). + unit_divisor : float, optional + [default: 1000], ignored unless `unit_scale` is True. + write_bytes : bool, optional + Whether to write bytes. If (default: False) will write unicode. + lock_args : tuple, optional + Passed to `refresh` for intermediate output + (initialisation, iterating, and updating). + nrows : int, optional + The screen height. If specified, hides nested bars outside this + bound. If unspecified, attempts to use environment height. + The fallback is 20. + colour : str, optional + Bar colour (e.g. 'green', '#00ff00'). + delay : float, optional + Don't display until [default: 0] seconds have elapsed. + gui : bool, optional + WARNING: internal parameter - do not use. + Use tqdm.gui.tqdm(...) instead. If set, will attempt to use + matplotlib animations for a graphical output [default: False]. + + Returns + ------- + out : decorated iterator. + """ + + monitor_interval = 10 # set to 0 to disable the thread + monitor = None + _instances = WeakSet() + +
+[docs] + @staticmethod + def format_sizeof(num, suffix='', divisor=1000): + """ + Formats a number (greater than unity) with SI Order of Magnitude + prefixes. + + Parameters + ---------- + num : float + Number ( >= 1) to format. + suffix : str, optional + Post-postfix [default: '']. + divisor : float, optional + Divisor between prefixes [default: 1000]. + + Returns + ------- + out : str + Number with Order of Magnitude SI unit postfix. + """ + for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']: + if abs(num) < 999.5: + if abs(num) < 99.95: + if abs(num) < 9.995: + return f'{num:1.2f}{unit}{suffix}' + return f'{num:2.1f}{unit}{suffix}' + return f'{num:3.0f}{unit}{suffix}' + num /= divisor + return f'{num:3.1f}Y{suffix}'
+ + +
+[docs] + @staticmethod + def format_interval(t): + """ + Formats a number of seconds as a clock time, [H:]MM:SS + + Parameters + ---------- + t : int + Number of seconds. + + Returns + ------- + out : str + [H:]MM:SS + """ + mins, s = divmod(int(t), 60) + h, m = divmod(mins, 60) + return f'{h:d}:{m:02d}:{s:02d}' if h else f'{m:02d}:{s:02d}'
+ + +
+[docs] + @staticmethod + def format_num(n): + """ + Intelligent scientific notation (.3g). + + Parameters + ---------- + n : int or float or Numeric + A Number. + + Returns + ------- + out : str + Formatted number. + """ + f = f'{n:.3g}'.replace('e+0', 'e+').replace('e-0', 'e-') + n = str(n) + return f if len(f) < len(n) else n
+ + +
+[docs] + @staticmethod + def status_printer(file): + """ + Manage the printing and in-place updating of a line of characters. + Note that if the string is longer than a line, then in-place + updating may not work (it will print a new line at each refresh). + """ + fp = file + fp_flush = getattr(fp, 'flush', lambda: None) # pragma: no cover + if fp in (sys.stderr, sys.stdout): + getattr(sys.stderr, 'flush', lambda: None)() + getattr(sys.stdout, 'flush', lambda: None)() + + def fp_write(s): + fp.write(str(s)) + fp_flush() + + last_len = [0] + + def print_status(s): + len_s = disp_len(s) + fp_write('\r' + s + (' ' * max(last_len[0] - len_s, 0))) + last_len[0] = len_s + + return print_status
+ + +
+[docs] + @staticmethod + def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False, unit='it', + unit_scale=False, rate=None, bar_format=None, postfix=None, + unit_divisor=1000, initial=0, colour=None, **extra_kwargs): + """ + Return a string-based progress bar given some parameters + + Parameters + ---------- + n : int or float + Number of finished iterations. + total : int or float + The expected total number of iterations. If meaningless (None), + only basic progress statistics are displayed (no ETA). + elapsed : float + Number of seconds passed since start. + ncols : int, optional + The width of the entire output message. If specified, + dynamically resizes `{bar}` to stay within this bound + [default: None]. If `0`, will not print any bar (only stats). + The fallback is `{bar:10}`. + prefix : str, optional + Prefix message (included in total width) [default: '']. + Use as {desc} in bar_format string. + ascii : bool, optional or str, optional + If not set, use unicode (smooth blocks) to fill the meter + [default: False]. The fallback is to use ASCII characters + " 123456789#". + unit : str, optional + The iteration unit [default: 'it']. + unit_scale : bool or int or float, optional + If 1 or True, the number of iterations will be printed with an + appropriate SI metric prefix (k = 10^3, M = 10^6, etc.) + [default: False]. If any other non-zero number, will scale + `total` and `n`. + rate : float, optional + Manual override for iteration rate. + If [default: None], uses n/elapsed. + bar_format : str, optional + Specify a custom bar string formatting. May impact performance. + [default: '{l_bar}{bar}{r_bar}'], where + l_bar='{desc}: {percentage:3.0f}%|' and + r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' + '{rate_fmt}{postfix}]' + Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, + percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, + rate, rate_fmt, rate_noinv, rate_noinv_fmt, + rate_inv, rate_inv_fmt, postfix, unit_divisor, + remaining, remaining_s, eta. + Note that a trailing ": " is automatically removed after {desc} + if the latter is empty. + postfix : *, optional + Similar to `prefix`, but placed at the end + (e.g. for additional stats). + Note: postfix is usually a string (not a dict) for this method, + and will if possible be set to postfix = ', ' + postfix. + However other types are supported (#382). + unit_divisor : float, optional + [default: 1000], ignored unless `unit_scale` is True. + initial : int or float, optional + The initial counter value [default: 0]. + colour : str, optional + Bar colour (e.g. 'green', '#00ff00'). + + Returns + ------- + out : Formatted meter and stats, ready to display. + """ + + # sanity check: total + if total and n >= (total + 0.5): # allow float imprecision (#849) + total = None + + # apply custom scale if necessary + if unit_scale and unit_scale not in (True, 1): + if total: + total *= unit_scale + n *= unit_scale + if rate: + rate *= unit_scale # by default rate = self.avg_dn / self.avg_dt + unit_scale = False + + elapsed_str = tqdm.format_interval(elapsed) + + # if unspecified, attempt to use rate = average speed + # (we allow manual override since predicting time is an arcane art) + if rate is None and elapsed: + rate = (n - initial) / elapsed + inv_rate = 1 / rate if rate else None + format_sizeof = tqdm.format_sizeof + rate_noinv_fmt = ((format_sizeof(rate) if unit_scale else f'{rate:5.2f}') + if rate else '?') + unit + '/s' + rate_inv_fmt = ( + (format_sizeof(inv_rate) if unit_scale else f'{inv_rate:5.2f}') + if inv_rate else '?') + 's/' + unit + rate_fmt = rate_inv_fmt if inv_rate and inv_rate > 1 else rate_noinv_fmt + + if unit_scale: + n_fmt = format_sizeof(n, divisor=unit_divisor) + total_fmt = format_sizeof(total, divisor=unit_divisor) if total is not None else '?' + else: + n_fmt = str(n) + total_fmt = str(total) if total is not None else '?' + + try: + postfix = ', ' + postfix if postfix else '' + except TypeError: + pass + + remaining = (total - n) / rate if rate and total else 0 + remaining_str = tqdm.format_interval(remaining) if rate else '?' + try: + eta_dt = (datetime.now() + timedelta(seconds=remaining) + if rate and total else datetime.fromtimestamp(0, timezone.utc)) + except OverflowError: + eta_dt = datetime.max + + # format the stats displayed to the left and right sides of the bar + if prefix: + # old prefix setup work around + bool_prefix_colon_already = (prefix[-2:] == ": ") + l_bar = prefix if bool_prefix_colon_already else prefix + ": " + else: + l_bar = '' + + r_bar = f'| {n_fmt}/{total_fmt} [{elapsed_str}<{remaining_str}, {rate_fmt}{postfix}]' + + # Custom bar formatting + # Populate a dict with all available progress indicators + format_dict = { + # slight extension of self.format_dict + 'n': n, 'n_fmt': n_fmt, 'total': total, 'total_fmt': total_fmt, + 'elapsed': elapsed_str, 'elapsed_s': elapsed, + 'ncols': ncols, 'desc': prefix or '', 'unit': unit, + 'rate': inv_rate if inv_rate and inv_rate > 1 else rate, + 'rate_fmt': rate_fmt, 'rate_noinv': rate, + 'rate_noinv_fmt': rate_noinv_fmt, 'rate_inv': inv_rate, + 'rate_inv_fmt': rate_inv_fmt, + 'postfix': postfix, 'unit_divisor': unit_divisor, + 'colour': colour, + # plus more useful definitions + 'remaining': remaining_str, 'remaining_s': remaining, + 'l_bar': l_bar, 'r_bar': r_bar, 'eta': eta_dt, + **extra_kwargs} + + # total is known: we can predict some stats + if total: + # fractional and percentage progress + frac = n / total + percentage = frac * 100 + + l_bar += f'{percentage:3.0f}%|' + + if ncols == 0: + return l_bar[:-1] + r_bar[1:] + + format_dict.update(l_bar=l_bar) + if bar_format: + format_dict.update(percentage=percentage) + + # auto-remove colon for empty `{desc}` + if not prefix: + bar_format = bar_format.replace("{desc}: ", '') + else: + bar_format = "{l_bar}{bar}{r_bar}" + + full_bar = FormatReplace() + nobar = bar_format.format(bar=full_bar, **format_dict) + if not full_bar.format_called: + return nobar # no `{bar}`; nothing else to do + + # Formatting progress bar space available for bar's display + full_bar = Bar(frac, + max(1, ncols - disp_len(nobar)) if ncols else 10, + charset=Bar.ASCII if ascii is True else ascii or Bar.UTF, + colour=colour) + if not _is_ascii(full_bar.charset) and _is_ascii(bar_format): + bar_format = str(bar_format) + res = bar_format.format(bar=full_bar, **format_dict) + return disp_trim(res, ncols) if ncols else res + + elif bar_format: + # user-specified bar_format but no total + l_bar += '|' + format_dict.update(l_bar=l_bar, percentage=0) + full_bar = FormatReplace() + nobar = bar_format.format(bar=full_bar, **format_dict) + if not full_bar.format_called: + return nobar + full_bar = Bar(0, + max(1, ncols - disp_len(nobar)) if ncols else 10, + charset=Bar.BLANK, colour=colour) + res = bar_format.format(bar=full_bar, **format_dict) + return disp_trim(res, ncols) if ncols else res + else: + # no total: no progressbar, ETA, just progress stats + return (f'{(prefix + ": ") if prefix else ""}' + f'{n_fmt}{unit} [{elapsed_str}, {rate_fmt}{postfix}]')
+ + + def __new__(cls, *_, **__): + instance = object.__new__(cls) + with cls.get_lock(): # also constructs lock if non-existent + cls._instances.add(instance) + # create monitoring thread + if cls.monitor_interval and (cls.monitor is None + or not cls.monitor.report()): + try: + cls.monitor = TMonitor(cls, cls.monitor_interval) + except Exception as e: # pragma: nocover + warn("tqdm:disabling monitor support" + " (monitor_interval = 0) due to:\n" + str(e), + TqdmMonitorWarning, stacklevel=2) + cls.monitor_interval = 0 + return instance + + @classmethod + def _get_free_pos(cls, instance=None): + """Skips specified instance.""" + positions = {abs(inst.pos) for inst in cls._instances + if inst is not instance and hasattr(inst, "pos")} + return min(set(range(len(positions) + 1)).difference(positions)) + + @classmethod + def _decr_instances(cls, instance): + """ + Remove from list and reposition another unfixed bar + to fill the new gap. + + This means that by default (where all nested bars are unfixed), + order is not maintained but screen flicker/blank space is minimised. + (tqdm<=4.44.1 moved ALL subsequent unfixed bars up.) + """ + with cls._lock: + try: + cls._instances.remove(instance) + except KeyError: + # if not instance.gui: # pragma: no cover + # raise + pass # py2: maybe magically removed already + # else: + if not instance.gui: + last = (instance.nrows or 20) - 1 + # find unfixed (`pos >= 0`) overflow (`pos >= nrows - 1`) + instances = list(filter( + lambda i: hasattr(i, "pos") and last <= i.pos, + cls._instances)) + # set first found to current `pos` + if instances: + inst = min(instances, key=lambda i: i.pos) + inst.clear(nolock=True) + inst.pos = abs(instance.pos) + +
+[docs] + @classmethod + def write(cls, s, file=None, end="\n", nolock=False): + """Print a message via tqdm (without overlap with bars).""" + fp = file if file is not None else sys.stdout + with cls.external_write_mode(file=file, nolock=nolock): + # Write the message + fp.write(s) + fp.write(end)
+ + +
+[docs] + @classmethod + @contextmanager + def external_write_mode(cls, file=None, nolock=False): + """ + Disable tqdm within context and refresh tqdm when exits. + Useful when writing to standard output stream + """ + fp = file if file is not None else sys.stdout + + try: + if not nolock: + cls.get_lock().acquire() + # Clear all bars + inst_cleared = [] + for inst in getattr(cls, '_instances', []): + # Clear instance if in the target output file + # or if write output + tqdm output are both either + # sys.stdout or sys.stderr (because both are mixed in terminal) + if hasattr(inst, "start_t") and (inst.fp == fp or all( + f in (sys.stdout, sys.stderr) for f in (fp, inst.fp))): + inst.clear(nolock=True) + inst_cleared.append(inst) + yield + # Force refresh display of bars we cleared + for inst in inst_cleared: + inst.refresh(nolock=True) + finally: + if not nolock: + cls._lock.release()
+ + +
+[docs] + @classmethod + def set_lock(cls, lock): + """Set the global lock.""" + cls._lock = lock
+ + +
+[docs] + @classmethod + def get_lock(cls): + """Get the global lock. Construct it if it does not exist.""" + if not hasattr(cls, '_lock'): + cls._lock = TqdmDefaultWriteLock() + return cls._lock
+ + +
+[docs] + @classmethod + def pandas(cls, **tqdm_kwargs): + """ + Registers the current `tqdm` class with + pandas.core. + ( frame.DataFrame + | series.Series + | groupby.(generic.)DataFrameGroupBy + | groupby.(generic.)SeriesGroupBy + ).progress_apply + + A new instance will be created every time `progress_apply` is called, + and each instance will automatically `close()` upon completion. + + Parameters + ---------- + tqdm_kwargs : arguments for the tqdm instance + + Examples + -------- + >>> import pandas as pd + >>> import numpy as np + >>> from tqdm import tqdm + >>> from tqdm.gui import tqdm as tqdm_gui + >>> + >>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6))) + >>> tqdm.pandas(ncols=50) # can use tqdm_gui, optional kwargs, etc + >>> # Now you can use `progress_apply` instead of `apply` + >>> df.groupby(0).progress_apply(lambda x: x**2) + + References + ---------- + <https://stackoverflow.com/questions/18603270/\ + progress-indicator-during-pandas-operations-python> + """ + from warnings import catch_warnings, simplefilter + + from pandas.core.frame import DataFrame + from pandas.core.series import Series + try: + with catch_warnings(): + simplefilter("ignore", category=FutureWarning) + from pandas import Panel + except ImportError: # pandas>=1.2.0 + Panel = None + Rolling, Expanding = None, None + try: # pandas>=1.0.0 + from pandas.core.window.rolling import _Rolling_and_Expanding + except ImportError: + try: # pandas>=0.18.0 + from pandas.core.window import _Rolling_and_Expanding + except ImportError: # pandas>=1.2.0 + try: # pandas>=1.2.0 + from pandas.core.window.expanding import Expanding + from pandas.core.window.rolling import Rolling + _Rolling_and_Expanding = Rolling, Expanding + except ImportError: # pragma: no cover + _Rolling_and_Expanding = None + try: # pandas>=0.25.0 + from pandas.core.groupby.generic import SeriesGroupBy # , NDFrameGroupBy + from pandas.core.groupby.generic import DataFrameGroupBy + except ImportError: # pragma: no cover + try: # pandas>=0.23.0 + from pandas.core.groupby.groupby import DataFrameGroupBy, SeriesGroupBy + except ImportError: + from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy + try: # pandas>=0.23.0 + from pandas.core.groupby.groupby import GroupBy + except ImportError: # pragma: no cover + from pandas.core.groupby import GroupBy + + try: # pandas>=0.23.0 + from pandas.core.groupby.groupby import PanelGroupBy + except ImportError: + try: + from pandas.core.groupby import PanelGroupBy + except ImportError: # pandas>=0.25.0 + PanelGroupBy = None + + tqdm_kwargs = tqdm_kwargs.copy() + deprecated_t = [tqdm_kwargs.pop('deprecated_t', None)] + + def inner_generator(df_function='apply'): + def inner(df, func, *args, **kwargs): + """ + Parameters + ---------- + df : (DataFrame|Series)[GroupBy] + Data (may be grouped). + func : function + To be applied on the (grouped) data. + **kwargs : optional + Transmitted to `df.apply()`. + """ + + # Precompute total iterations + total = tqdm_kwargs.pop("total", getattr(df, 'ngroups', None)) + if total is None: # not grouped + if df_function == 'applymap': + total = df.size + elif isinstance(df, Series): + total = len(df) + elif (_Rolling_and_Expanding is None or + not isinstance(df, _Rolling_and_Expanding)): + # DataFrame or Panel + axis = kwargs.get('axis', 0) + if axis == 'index': + axis = 0 + elif axis == 'columns': + axis = 1 + # when axis=0, total is shape[axis1] + total = df.size // df.shape[axis] + + # Init bar + if deprecated_t[0] is not None: + t = deprecated_t[0] + deprecated_t[0] = None + else: + t = cls(total=total, **tqdm_kwargs) + + if len(args) > 0: + # *args intentionally not supported (see #244, #299) + TqdmDeprecationWarning( + "Except func, normal arguments are intentionally" + + " not supported by" + + " `(DataFrame|Series|GroupBy).progress_apply`." + + " Use keyword arguments instead.", + fp_write=getattr(t.fp, 'write', sys.stderr.write)) + + try: # pandas>=1.3.0 + from pandas.core.common import is_builtin_func + except ImportError: + is_builtin_func = df._is_builtin_func + try: + func = is_builtin_func(func) + except TypeError: + pass + + # Define bar updating wrapper + def wrapper(*args, **kwargs): + # update tbar correctly + # it seems `pandas apply` calls `func` twice + # on the first column/row to decide whether it can + # take a fast or slow code path; so stop when t.total==t.n + t.update(n=1 if not t.total or t.n < t.total else 0) + return func(*args, **kwargs) + + # Apply the provided function (in **kwargs) + # on the df using our wrapper (which provides bar updating) + try: + return getattr(df, df_function)(wrapper, **kwargs) + finally: + t.close() + + return inner + + # Monkeypatch pandas to provide easy methods + # Enable custom tqdm progress in pandas! + Series.progress_apply = inner_generator() + SeriesGroupBy.progress_apply = inner_generator() + Series.progress_map = inner_generator('map') + SeriesGroupBy.progress_map = inner_generator('map') + + DataFrame.progress_apply = inner_generator() + DataFrameGroupBy.progress_apply = inner_generator() + DataFrame.progress_applymap = inner_generator('applymap') + DataFrame.progress_map = inner_generator('map') + DataFrameGroupBy.progress_map = inner_generator('map') + + if Panel is not None: + Panel.progress_apply = inner_generator() + if PanelGroupBy is not None: + PanelGroupBy.progress_apply = inner_generator() + + GroupBy.progress_apply = inner_generator() + GroupBy.progress_aggregate = inner_generator('aggregate') + GroupBy.progress_transform = inner_generator('transform') + + if Rolling is not None and Expanding is not None: + Rolling.progress_apply = inner_generator() + Expanding.progress_apply = inner_generator() + elif _Rolling_and_Expanding is not None: + _Rolling_and_Expanding.progress_apply = inner_generator()
+ + + # override defaults via env vars + @envwrap("TQDM_", is_method=True, types={'total': float, 'ncols': int, 'miniters': float, + 'position': int, 'nrows': int}) + def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None, + ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None, + ascii=None, disable=False, unit='it', unit_scale=False, + dynamic_ncols=False, smoothing=0.3, bar_format=None, initial=0, + position=None, postfix=None, unit_divisor=1000, write_bytes=False, + lock_args=None, nrows=None, colour=None, delay=0.0, gui=False, + **kwargs): + """see tqdm.tqdm for arguments""" + if file is None: + file = sys.stderr + + if write_bytes: + # Despite coercing unicode into bytes, py2 sys.std* streams + # should have bytes written to them. + file = SimpleTextIOWrapper( + file, encoding=getattr(file, 'encoding', None) or 'utf-8') + + file = DisableOnWriteError(file, tqdm_instance=self) + + if disable is None and hasattr(file, "isatty") and not file.isatty(): + disable = True + + if total is None and iterable is not None: + try: + total = len(iterable) + except (TypeError, AttributeError): + total = None + if total == float("inf"): + # Infinite iterations, behave same as unknown + total = None + + if disable: + self.iterable = iterable + self.disable = disable + with self._lock: + self.pos = self._get_free_pos(self) + self._instances.remove(self) + self.n = initial + self.total = total + self.leave = leave + return + + if kwargs: + self.disable = True + with self._lock: + self.pos = self._get_free_pos(self) + self._instances.remove(self) + raise ( + TqdmDeprecationWarning( + "`nested` is deprecated and automated.\n" + "Use `position` instead for manual control.\n", + fp_write=getattr(file, 'write', sys.stderr.write)) + if "nested" in kwargs else + TqdmKeyError("Unknown argument(s): " + str(kwargs))) + + # Preprocess the arguments + if ( + (ncols is None or nrows is None) and (file in (sys.stderr, sys.stdout)) + ) or dynamic_ncols: # pragma: no cover + if dynamic_ncols: + dynamic_ncols = _screen_shape_wrapper() + if dynamic_ncols: + ncols, nrows = dynamic_ncols(file) + else: + _dynamic_ncols = _screen_shape_wrapper() + if _dynamic_ncols: + _ncols, _nrows = _dynamic_ncols(file) + if ncols is None: + ncols = _ncols + if nrows is None: + nrows = _nrows + + if miniters is None: + miniters = 0 + dynamic_miniters = True + else: + dynamic_miniters = False + + if mininterval is None: + mininterval = 0 + + if maxinterval is None: + maxinterval = 0 + + if ascii is None: + ascii = not _supports_unicode(file) + + if bar_format and ascii is not True and not _is_ascii(ascii): + # Convert bar format into unicode since terminal uses unicode + bar_format = str(bar_format) + + if smoothing is None: + smoothing = 0 + + # Store the arguments + self.iterable = iterable + self.desc = desc or '' + self.total = total + self.leave = leave + self.fp = file + self.ncols = ncols + self.nrows = nrows + self.mininterval = mininterval + self.maxinterval = maxinterval + self.miniters = miniters + self.dynamic_miniters = dynamic_miniters + self.ascii = ascii + self.disable = disable + self.unit = unit + self.unit_scale = unit_scale + self.unit_divisor = unit_divisor + self.initial = initial + self.lock_args = lock_args + self.delay = delay + self.gui = gui + self.dynamic_ncols = dynamic_ncols + self.smoothing = smoothing + self._ema_dn = EMA(smoothing) + self._ema_dt = EMA(smoothing) + self._ema_miniters = EMA(smoothing) + self.bar_format = bar_format + self.postfix = None + self.colour = colour + self._time = time + if postfix: + try: + self.set_postfix(refresh=False, **postfix) + except TypeError: + self.postfix = postfix + + # Init the iterations counters + self.last_print_n = initial + self.n = initial + + # if nested, at initial sp() call we replace '\r' by '\n' to + # not overwrite the outer progress bar + with self._lock: + # mark fixed positions as negative + self.pos = self._get_free_pos(self) if position is None else -position + + if not gui: + # Initialize the screen printer + self.sp = self.status_printer(self.fp) + if delay <= 0: + self.refresh(lock_args=self.lock_args) + + # Init the time counter + self.last_print_t = self._time() + # NB: Avoid race conditions by setting start_t at the very end of init + self.start_t = self.last_print_t + + def __bool__(self): + if self.total is not None: + return self.total > 0 + if self.iterable is None: + raise TypeError('bool() undefined when iterable == total == None') + return bool(self.iterable) + + def __len__(self): + return ( + self.total if self.iterable is None + else self.iterable.shape[0] if hasattr(self.iterable, "shape") + else len(self.iterable) if hasattr(self.iterable, "__len__") + else self.iterable.__length_hint__() if hasattr(self.iterable, "__length_hint__") + else getattr(self, "total", None)) + + def __reversed__(self): + try: + orig = self.iterable + except AttributeError: + raise TypeError("'tqdm' object is not reversible") + else: + self.iterable = reversed(self.iterable) + return self.__iter__() + finally: + self.iterable = orig + + def __contains__(self, item): + contains = getattr(self.iterable, '__contains__', None) + return contains(item) if contains is not None else item in self.__iter__() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + try: + self.close() + except AttributeError: + # maybe eager thread cleanup upon external error + if (exc_type, exc_value, traceback) == (None, None, None): + raise + warn("AttributeError ignored", TqdmWarning, stacklevel=2) + + def __del__(self): + self.close() + + def __str__(self): + return self.format_meter(**self.format_dict) + + @property + def _comparable(self): + return abs(getattr(self, "pos", 1 << 31)) + + def __hash__(self): + return id(self) + + def __iter__(self): + """Backward-compatibility to use: for x in tqdm(iterable)""" + + # Inlining instance variables as locals (speed optimisation) + iterable = self.iterable + + # If the bar is disabled, then just walk the iterable + # (note: keep this check outside the loop for performance) + if self.disable: + for obj in iterable: + yield obj + return + + mininterval = self.mininterval + last_print_t = self.last_print_t + last_print_n = self.last_print_n + min_start_t = self.start_t + self.delay + n = self.n + time = self._time + + try: + for obj in iterable: + yield obj + # Update and possibly print the progressbar. + # Note: does not call self.update(1) for speed optimisation. + n += 1 + + if n - last_print_n >= self.miniters: + cur_t = time() + dt = cur_t - last_print_t + if dt >= mininterval and cur_t >= min_start_t: + self.update(n - last_print_n) + last_print_n = self.last_print_n + last_print_t = self.last_print_t + finally: + self.n = n + self.close() + +
+[docs] + def update(self, n=1): + """ + Manually update the progress bar, useful for streams + such as reading files. + E.g.: + >>> t = tqdm(total=filesize) # Initialise + >>> for current_buffer in stream: + ... ... + ... t.update(len(current_buffer)) + >>> t.close() + The last line is highly recommended, but possibly not necessary if + `t.update()` will be called in such a way that `filesize` will be + exactly reached and printed. + + Parameters + ---------- + n : int or float, optional + Increment to add to the internal counter of iterations + [default: 1]. If using float, consider specifying `{n:.3f}` + or similar in `bar_format`, or specifying `unit_scale`. + + Returns + ------- + out : bool or None + True if a `display()` was triggered. + """ + if self.disable: + return + + if n < 0: + self.last_print_n += n # for auto-refresh logic to work + self.n += n + + # check counter first to reduce calls to time() + if self.n - self.last_print_n >= self.miniters: + cur_t = self._time() + dt = cur_t - self.last_print_t + if dt >= self.mininterval and cur_t >= self.start_t + self.delay: + cur_t = self._time() + dn = self.n - self.last_print_n # >= n + if self.smoothing and dt and dn: + # EMA (not just overall average) + self._ema_dn(dn) + self._ema_dt(dt) + self.refresh(lock_args=self.lock_args) + if self.dynamic_miniters: + # If no `miniters` was specified, adjust automatically to the + # maximum iteration rate seen so far between two prints. + # e.g.: After running `tqdm.update(5)`, subsequent + # calls to `tqdm.update()` will only cause an update after + # at least 5 more iterations. + if self.maxinterval and dt >= self.maxinterval: + self.miniters = dn * (self.mininterval or self.maxinterval) / dt + elif self.smoothing: + # EMA miniters update + self.miniters = self._ema_miniters( + dn * (self.mininterval / dt if self.mininterval and dt + else 1)) + else: + # max iters between two prints + self.miniters = max(self.miniters, dn) + + # Store old values for next call + self.last_print_n = self.n + self.last_print_t = cur_t + return True
+ + +
+[docs] + def close(self): + """Cleanup and (if leave=False) close the progressbar.""" + if self.disable: + return + + # Prevent multiple closures + self.disable = True + + # decrement instance pos and remove from internal set + pos = abs(self.pos) + self._decr_instances(self) + + if self.last_print_t < self.start_t + self.delay: + # haven't ever displayed; nothing to clear + return + + # GUI mode + if getattr(self, 'sp', None) is None: + return + + # annoyingly, _supports_unicode isn't good enough + def fp_write(s): + self.fp.write(str(s)) + + try: + fp_write('') + except ValueError as e: + if 'closed' in str(e): + return + raise # pragma: no cover + + leave = pos == 0 if self.leave is None else self.leave + + with self._lock: + if leave: + # stats for overall rate (no weighted average) + self._ema_dt = lambda: None + self.display(pos=0) + fp_write('\n') + else: + # clear previous display + if self.display(msg='', pos=pos) and not pos: + fp_write('\r')
+ + +
+[docs] + def clear(self, nolock=False): + """Clear current bar display.""" + if self.disable: + return + + if not nolock: + self._lock.acquire() + pos = abs(self.pos) + if pos < (self.nrows or 20): + self.moveto(pos) + self.sp('') + self.fp.write('\r') # place cursor back at the beginning of line + self.moveto(-pos) + if not nolock: + self._lock.release()
+ + +
+[docs] + def refresh(self, nolock=False, lock_args=None): + """ + Force refresh the display of this bar. + + Parameters + ---------- + nolock : bool, optional + If `True`, does not lock. + If [default: `False`]: calls `acquire()` on internal lock. + lock_args : tuple, optional + Passed to internal lock's `acquire()`. + If specified, will only `display()` if `acquire()` returns `True`. + """ + if self.disable: + return + + if not nolock: + if lock_args: + if not self._lock.acquire(*lock_args): + return False + else: + self._lock.acquire() + self.display() + if not nolock: + self._lock.release() + return True
+ + +
+[docs] + def unpause(self): + """Restart tqdm timer from last print time.""" + if self.disable: + return + cur_t = self._time() + self.start_t += cur_t - self.last_print_t + self.last_print_t = cur_t
+ + +
+[docs] + def reset(self, total=None): + """ + Resets to 0 iterations for repeated use. + + Consider combining with `leave=True`. + + Parameters + ---------- + total : int or float, optional. Total to use for the new bar. + """ + self.n = 0 + if total is not None: + self.total = total + if self.disable: + return + self.last_print_n = 0 + self.last_print_t = self.start_t = self._time() + self._ema_dn = EMA(self.smoothing) + self._ema_dt = EMA(self.smoothing) + self._ema_miniters = EMA(self.smoothing) + self.refresh()
+ + +
+[docs] + def set_description(self, desc=None, refresh=True): + """ + Set/modify description of the progress bar. + + Parameters + ---------- + desc : str, optional + refresh : bool, optional + Forces refresh [default: True]. + """ + self.desc = desc + ': ' if desc else '' + if refresh: + self.refresh()
+ + +
+[docs] + def set_description_str(self, desc=None, refresh=True): + """Set/modify description without ': ' appended.""" + self.desc = desc or '' + if refresh: + self.refresh()
+ + +
+[docs] + def set_postfix(self, ordered_dict=None, refresh=True, **kwargs): + """ + Set/modify postfix (additional stats) + with automatic formatting based on datatype. + + Parameters + ---------- + ordered_dict : dict or OrderedDict, optional + refresh : bool, optional + Forces refresh [default: True]. + kwargs : dict, optional + """ + # Sort in alphabetical order to be more deterministic + postfix = OrderedDict([] if ordered_dict is None else ordered_dict) + for key in sorted(kwargs.keys()): + postfix[key] = kwargs[key] + # Preprocess stats according to datatype + for key in postfix.keys(): + # Number: limit the length of the string + if isinstance(postfix[key], Number): + postfix[key] = self.format_num(postfix[key]) + # Else for any other type, try to get the string conversion + elif not isinstance(postfix[key], str): + postfix[key] = str(postfix[key]) + # Else if it's a string, don't need to preprocess anything + # Stitch together to get the final postfix + self.postfix = ', '.join(key + '=' + postfix[key].strip() + for key in postfix.keys()) + if refresh: + self.refresh()
+ + +
+[docs] + def set_postfix_str(self, s='', refresh=True): + """ + Postfix without dictionary expansion, similar to prefix handling. + """ + self.postfix = str(s) + if refresh: + self.refresh()
+ + +
+[docs] + def moveto(self, n): + # TODO: private method + self.fp.write('\n' * n + _term_move_up() * -n) + getattr(self.fp, 'flush', lambda: None)()
+ + + @property + def format_dict(self): + """Public API for read-only member access.""" + if self.disable and not hasattr(self, 'unit'): + return defaultdict(lambda: None, { + 'n': self.n, 'total': self.total, 'elapsed': 0, 'unit': 'it'}) + if self.dynamic_ncols: + self.ncols, self.nrows = self.dynamic_ncols(self.fp) + return { + 'n': self.n, 'total': self.total, + 'elapsed': self._time() - self.start_t if hasattr(self, 'start_t') else 0, + 'ncols': self.ncols, 'nrows': self.nrows, 'prefix': self.desc, + 'ascii': self.ascii, 'unit': self.unit, 'unit_scale': self.unit_scale, + 'rate': self._ema_dn() / self._ema_dt() if self._ema_dt() else None, + 'bar_format': self.bar_format, 'postfix': self.postfix, + 'unit_divisor': self.unit_divisor, 'initial': self.initial, + 'colour': self.colour} + +
+[docs] + def display(self, msg=None, pos=None): + """ + Use `self.sp` to display `msg` in the specified `pos`. + + Consider overloading this function when inheriting to use e.g.: + `self.some_frontend(**self.format_dict)` instead of `self.sp`. + + Parameters + ---------- + msg : str, optional. What to display (default: `repr(self)`). + pos : int, optional. Position to `moveto` + (default: `abs(self.pos)`). + """ + if pos is None: + pos = abs(self.pos) + + nrows = self.nrows or 20 + if pos >= nrows - 1: + if pos >= nrows: + return False + if msg or msg is None: # override at `nrows - 1` + msg = " ... (more hidden) ..." + + if not hasattr(self, "sp"): + raise TqdmDeprecationWarning( + "Please use `tqdm.gui.tqdm(...)`" + " instead of `tqdm(..., gui=True)`\n", + fp_write=getattr(self.fp, 'write', sys.stderr.write)) + + if pos: + self.moveto(pos) + self.sp(self.__str__() if msg is None else msg) + if pos: + self.moveto(-pos) + return True
+ + +
+[docs] + @classmethod + @contextmanager + def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs): + """ + stream : file-like object. + method : str, "read" or "write". The result of `read()` and + the first argument of `write()` should have a `len()`. + + >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj: + ... while True: + ... chunk = fobj.read(chunk_size) + ... if not chunk: + ... break + """ + with cls(total=total, **tqdm_kwargs) as t: + if bytes: + t.unit = "B" + t.unit_scale = True + t.unit_divisor = 1024 + yield CallbackIOWrapper(t.update, stream, method)
+
+ + + +
+[docs] +def trange(*args, **kwargs): + """Shortcut for tqdm(range(*args), **kwargs).""" + return tqdm(range(*args), **kwargs)
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/_sources/index.rst.txt b/docs/_build/html/_sources/index.rst.txt new file mode 100644 index 00000000..75b5c770 --- /dev/null +++ b/docs/_build/html/_sources/index.rst.txt @@ -0,0 +1,23 @@ +.. ldp documentation master file, created by + sphinx-quickstart on Thu Oct 24 14:50:30 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to ldp's documentation! +=============================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + modules + + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/_build/html/_sources/ldp.agent.rst.txt b/docs/_build/html/_sources/ldp.agent.rst.txt new file mode 100644 index 00000000..146fe429 --- /dev/null +++ b/docs/_build/html/_sources/ldp.agent.rst.txt @@ -0,0 +1,69 @@ +ldp.agent package +================= + +Submodules +---------- + +ldp.agent.agent module +---------------------- + +.. automodule:: ldp.agent.agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.agent\_client module +------------------------------ + +.. automodule:: ldp.agent.agent_client + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.interactive\_agent module +----------------------------------- + +.. automodule:: ldp.agent.interactive_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.memory\_agent module +------------------------------ + +.. automodule:: ldp.agent.memory_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.react\_agent module +----------------------------- + +.. automodule:: ldp.agent.react_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.simple\_agent module +------------------------------ + +.. automodule:: ldp.agent.simple_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.tree\_of\_thoughts\_agent module +------------------------------------------ + +.. automodule:: ldp.agent.tree_of_thoughts_agent + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.agent + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/ldp.alg.optimizer.rst.txt b/docs/_build/html/_sources/ldp.alg.optimizer.rst.txt new file mode 100644 index 00000000..f05f2c58 --- /dev/null +++ b/docs/_build/html/_sources/ldp.alg.optimizer.rst.txt @@ -0,0 +1,45 @@ +ldp.alg.optimizer package +========================= + +Submodules +---------- + +ldp.alg.optimizer.ape module +---------------------------- + +.. automodule:: ldp.alg.optimizer.ape + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.optimizer.memory module +------------------------------- + +.. automodule:: ldp.alg.optimizer.memory + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.optimizer.opt module +---------------------------- + +.. automodule:: ldp.alg.optimizer.opt + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.optimizer.replay\_buffers module +---------------------------------------- + +.. automodule:: ldp.alg.optimizer.replay_buffers + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.alg.optimizer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/ldp.alg.rst.txt b/docs/_build/html/_sources/ldp.alg.rst.txt new file mode 100644 index 00000000..621e6817 --- /dev/null +++ b/docs/_build/html/_sources/ldp.alg.rst.txt @@ -0,0 +1,77 @@ +ldp.alg package +=============== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + ldp.alg.optimizer + +Submodules +---------- + +ldp.alg.algorithms module +------------------------- + +.. automodule:: ldp.alg.algorithms + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.beam\_search module +--------------------------- + +.. automodule:: ldp.alg.beam_search + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.callbacks module +------------------------ + +.. automodule:: ldp.alg.callbacks + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.datasets module +----------------------- + +.. automodule:: ldp.alg.datasets + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.rollout module +---------------------- + +.. automodule:: ldp.alg.rollout + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.runners module +---------------------- + +.. automodule:: ldp.alg.runners + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.tree\_search module +--------------------------- + +.. automodule:: ldp.alg.tree_search + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.alg + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/ldp.graph.modules.rst.txt b/docs/_build/html/_sources/ldp.graph.modules.rst.txt new file mode 100644 index 00000000..28b36540 --- /dev/null +++ b/docs/_build/html/_sources/ldp.graph.modules.rst.txt @@ -0,0 +1,45 @@ +ldp.graph.modules package +========================= + +Submodules +---------- + +ldp.graph.modules.llm\_call module +---------------------------------- + +.. automodule:: ldp.graph.modules.llm_call + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.modules.react module +------------------------------ + +.. automodule:: ldp.graph.modules.react + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.modules.reflect module +-------------------------------- + +.. automodule:: ldp.graph.modules.reflect + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.modules.thought module +-------------------------------- + +.. automodule:: ldp.graph.modules.thought + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.graph.modules + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/ldp.graph.rst.txt b/docs/_build/html/_sources/ldp.graph.rst.txt new file mode 100644 index 00000000..9fc73995 --- /dev/null +++ b/docs/_build/html/_sources/ldp.graph.rst.txt @@ -0,0 +1,85 @@ +ldp.graph package +================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + ldp.graph.modules + +Submodules +---------- + +ldp.graph.async\_torch module +----------------------------- + +.. automodule:: ldp.graph.async_torch + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.common\_ops module +---------------------------- + +.. automodule:: ldp.graph.common_ops + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.gradient\_estimators module +------------------------------------- + +.. automodule:: ldp.graph.gradient_estimators + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.loss\_ops module +-------------------------- + +.. automodule:: ldp.graph.loss_ops + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.memory module +----------------------- + +.. automodule:: ldp.graph.memory + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.op\_utils module +-------------------------- + +.. automodule:: ldp.graph.op_utils + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.ops module +-------------------- + +.. automodule:: ldp.graph.ops + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.torch\_ops module +--------------------------- + +.. automodule:: ldp.graph.torch_ops + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.graph + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/ldp.llms.rst.txt b/docs/_build/html/_sources/ldp.llms.rst.txt new file mode 100644 index 00000000..31d1b865 --- /dev/null +++ b/docs/_build/html/_sources/ldp.llms.rst.txt @@ -0,0 +1,37 @@ +ldp.llms package +================ + +Submodules +---------- + +ldp.llms.chat module +-------------------- + +.. automodule:: ldp.llms.chat + :members: + :undoc-members: + :show-inheritance: + +ldp.llms.embeddings module +-------------------------- + +.. automodule:: ldp.llms.embeddings + :members: + :undoc-members: + :show-inheritance: + +ldp.llms.prompts module +----------------------- + +.. automodule:: ldp.llms.prompts + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.llms + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/ldp.rst.txt b/docs/_build/html/_sources/ldp.rst.txt new file mode 100644 index 00000000..df50fc31 --- /dev/null +++ b/docs/_build/html/_sources/ldp.rst.txt @@ -0,0 +1,56 @@ +ldp package +=========== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + ldp.agent + ldp.alg + ldp.graph + ldp.llms + +Submodules +---------- + +ldp.data\_structures module +--------------------------- + +.. automodule:: ldp.data_structures + :members: + :undoc-members: + :show-inheritance: + +ldp.main module +--------------- + +.. automodule:: ldp.main + :members: + :undoc-members: + :show-inheritance: + +ldp.shims module +---------------- + +.. automodule:: ldp.shims + :members: + :undoc-members: + :show-inheritance: + +ldp.utils module +---------------- + +.. automodule:: ldp.utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/modules.rst.txt b/docs/_build/html/_sources/modules.rst.txt new file mode 100644 index 00000000..f473f842 --- /dev/null +++ b/docs/_build/html/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +ldp +=== + +.. toctree:: + :maxdepth: 4 + + ldp diff --git a/docs/_build/html/_static/alabaster.css b/docs/_build/html/_static/alabaster.css new file mode 100644 index 00000000..e3174bf9 --- /dev/null +++ b/docs/_build/html/_static/alabaster.css @@ -0,0 +1,708 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar { + max-height: 100%; + overflow-y: auto; +} + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 160px; +} + +div.sphinxsidebar .search > div { + display: table-cell; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Hide ugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css new file mode 100644 index 00000000..e5179b7a --- /dev/null +++ b/docs/_build/html/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: inherit; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_build/html/_static/custom.css b/docs/_build/html/_static/custom.css new file mode 100644 index 00000000..2a924f1d --- /dev/null +++ b/docs/_build/html/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/docs/_build/html/_static/doctools.js b/docs/_build/html/_static/doctools.js new file mode 100644 index 00000000..4d67807d --- /dev/null +++ b/docs/_build/html/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/docs/_build/html/_static/documentation_options.js b/docs/_build/html/_static/documentation_options.js new file mode 100644 index 00000000..7e4c114f --- /dev/null +++ b/docs/_build/html/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/docs/_build/html/_static/file.png b/docs/_build/html/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/docs/_build/html/_static/file.png differ diff --git a/docs/_build/html/_static/groundwork.css b/docs/_build/html/_static/groundwork.css new file mode 100644 index 00000000..57363052 --- /dev/null +++ b/docs/_build/html/_static/groundwork.css @@ -0,0 +1,720 @@ +/* + * flasky.css_t + * ~~~~~~~~~~~~ + * + * :copyright: Copyright 2010 by Armin Ronacher. Modifications by Kenneth Reitz. + * :license: Flask Design License, see LICENSE for details. + */ + + + + + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font: 400 16px Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif; + /*font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro'; + font-size: 17px; */ + line-height: normal; + background-color: #333; + color: #333; + margin: 0; + padding: 0; + text-shadow: 0 1px 3px rgba(0,0,0,0.5); +} + +strong { + font-weight: bold; +} + +div.document { + width: 1024px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #444; + border-radius: 5px; + color: #ddd; + padding: 15px 30px 15px 30px; + box-shadow: 0 3px 10px rgba(0,0,0,0.3); +} + +img.floatingflask { + padding: 0 0 10px 10px; + float: right; +} + +div.footer { + width: 1024px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +div.related { + display: none; +} + +div.sphinxsidebar a { + color: #FFCC00; + text-decoration: none; + border-bottom: none; +} +div.sphinxsidebar a:hover { + color: #ff9900; +} + +div.sphinxsidebar a:hover, +div.sphinxsidebar a:visited, +div.sphinxsidebar a:focus { + border-bottom: none; +} + +div.sphinxsidebar { + margin: 0; + position: fixed; + overflow: auto; + height: auto; + font-size: 14px; + line-height: 1.5; +} + +div.sphinxsidebarwrapper { + padding: 18px 0 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 -20px; + text-align: center; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + /*font-family: 'Garamond', 'Georgia', serif;*/ + font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif; + color: #ddd; + font-size: 20px; + font-weight: normal; + padding: 0; + /*border-bottom: 1px solid #fff;*/ + + background-color: #444; + border-radius: 5px 0 0 0px; + padding-left: 5px; + border: 1px solid #444; + margin-top: 10px; + box-shadow: 0 3px 10px rgba(0,0,0,0.3); + margin-left: -10px; + /* Needed, if siebar is not sticky. Otherwise shadows moves over body element*/ + clip-path: inset(-10px -0px -10px -10px); +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #ddd; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 0; + padding: 0; + color: #ddd; +} + +div.sphinxsidebar input { + /*border: 1px solid #ccc;*/ + border: 1px solid #333; + font-family: 'Georgia', serif; + font-size: 1em; + color: #ddd; + width: 170px; + border-radius: 5px; + padding: 6px 12px; + box-shadow: inset 0 1px 10px rgba(0,0,0,0.3), 0 1px 0 rgba(255,255,255,0.1), 0 0px 0 rgba(0,0,0,0.5); + background-color: #2b2b2b; +} + +div.need-tobediscussed { + background-color: #0a4a63 !important; +} + +/*span.needs-type {*/ + /*border: 1px solid #444;*/ + /*border-radius: 5px;*/ + /*padding: 3px 5px;*/ +/*}*/ + +/*div.need-implementation span.needs-type {*/ + /*!*background-color: #ffdd00 !important;*!*/ + /*border: 1px solid #ffdd00*/ +/*}*/ + +div.need-status-closed span.needs-status { + background-color:darkgreen; +} + +div.need-status-open span.needs-status { + background-color:firebrick; +} + +div.need-status-tbd span.needs-status { + background-color:orange; +} + +div.need-technicaldebt span.needs-type { + background-color:red; +} + +/* need part table layout */ +tr.need_part td { + background-color: #555; + padding-left: 30px !important; +} + +/* using more space for whole page */ +div.document { + width: auto; + margin: 30px auto 0 auto; + max-width: 98%; +} +div.body { + min-width: 450px; + max-width: 100%; +} + +span.need-part a { + font-size: 0.75em; +} +span.need-part { + border-bottom: 1px solid #888; +} + +/* Code block design inside needs */ +div.need pre { + margin: 0; +} + +/* Better need title and ID layout*/ +span.needs-id { + font-size: 120% !important; + color: #ffcc00 !important; + float:right +} +span.needs-title { + font-weight: bold; + font-size: 1.3em; +} + +div.needs_meta div.headline { + margin-bottom: 5px; + border-bottom: 1px solid #555; +} +div.needs_meta.line-block{ + margin: 0; +} + +/* Need headline color design*/ +div.needs_meta div.headline { + margin: -5px -10px 5px -10px; + border-bottom: 1px solid #555; + border-radius: 3px 3px 0 0; + padding: 5px 10px 0px 10px; +} + +div.story div.headline { + background-color: #39024e80; +} + +div.spec div.headline { + background-color: #00beff33; +} + +div.impl div.headline { + background-color: #ff000a33; +} + +div.test div.headline { + background-color: #2ed15233; +} +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #FFCC00; + text-decoration: none; +} + +a:hover { + color: #ff9900; + text-decoration: none; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif; + /*font-family: 'Garamond', 'Georgia', serif;*/ + font-weight: normal; + /* margin: 30px 0px 10px 0px; */ + margin: 10px 0px 00px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #ffcc00; + padding: 0 4px; + text-decoration: none; + text-shadow: none; +} + +a.headerlink:hover { + color: #ff9900; + background: none; + text-shadow: none; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + background: none; + margin: 20px -30px; + padding: 10px 30px; +} + +div.admonition tt.xref, div.admonition a tt { + border-bottom: 1px solid #fafafa; +} + +dd div.admonition { + margin-left: -60px; + padding-left: 60px; +} + +div.admonition p.admonition-title { + font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif; + /* font-family: 'Garamond', 'Georgia', serif; */ + /* font-weight: normal;/* + font-weight: bold; + /* font-size: 24px; */ + font-size: 18px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + /*background-color: white;*/ + background-color: #444; + text-shadow: none; + color: #fff; +} + +dt:target, .highlight { + background: #333; +} + +div.note { + background-color: #555; + border: none; +} + +div.warning { + background-color: #7f1212; + border: none; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: inherit; + border: none; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt { + font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +img.screenshot { +} + +tt.descname, tt.descclassname { + font-size: 0.95em; +} + +tt.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #eee; + /* -webkit-box-shadow: 2px 2px 4px #eee; */ + /* box-shadow: 2px 2px 4px #eee; */ +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #eee; + background: #fdfdfd; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.footnote td.label { + width: 0px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #2b2b2b; + padding: 7px 30px; + margin: 15px -30px; + line-height: 1.3em; + box-shadow: inset 0 1px 10px rgba(0,0,0,0.3),0 1px 0 rgba(255,255,255,0.1),0 -1px 0 rgba(0,0,0,0.5); +} + +dl pre, blockquote pre, li pre { + margin-left: -60px; + padding-left: 60px; +} + +dl dl pre { + margin-left: -90px; + padding-left: 90px; +} + +tt { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid white; +} + +a.reference { + text-decoration: none; + border-bottom: none; +} + +a.reference:hover { + border-bottom: none; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt { + background: #EEE; +} + +@media screen and (max-width: 600px) { + + .github_fork { + display: none; + } + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 30; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + +} + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* API layout */ + +code.descname { + color : #ffffff; +} + +/* Pygmets overwrites */ +.highlight .nf { color: #ffcc00 !important; } /* function name */ +.highlight .nc { color: #ffcc00 !important; } /* class name */ +.highlight .kn { color: #918a6f !important; } /* import name */ +.highlight .bp { color: #ffffff !important; } /* self, name */ +.highlight .k { color: #918a6f !important; } /* class, def name */ +.highlight .o { color: #ffffff !important; } /* function name */ +.highlight .nb { color: #ffffff !important; } /* super, print name */ +.highlight .go { color: #aaaaaa !important; } /* super, print name */ + + +/* +Needed for readthedocs.io, because it adding its own css, which destroy our images. +See https://github.com/rtfd/readthedocs.org/issues/2348 +*/ +/* img { + width: auto !important; +}*/ + + +div.sidebar { + background-color: #2b2b2b; + border: none; + margin: 0 -30px 0 0; + box-shadow: inset 0 1px 10px rgba(0,0,0,0.3),0 1px 0 rgba(255,255,255,0.1),0 -1px 0 rgba(0,0,0,0.5); + border-radius: 10px 0 0 10px; + padding: 10px 20px 0 20px; + text-align: justify; +} + + +div.sidebar div.topic { + background-color: transparent; + border: none; + margin-top: -20px; +} +} + +div.sidebar div.topic ul { + margin: 5px 0 5px 15px; +} + +div.sidebar div.topic p.topic-title { + display: none; +} + +table.indextable tr.cap { + background-color: transparent !important; +} + +div.figure p.caption { + text-align: center +} + +table.highlighttable pre { + margin: 0; +} + +table.highlighttable { + /* margin: 0; */ + width: 100%; + border-spacing: 0px; + margin: 0 -30px 0 -30px; + overflow: auto; +} + +div.highlight-python, div.highlight-jinja { + +} + +div.highlight-json .nt { + color: #ff9900; +} + +table.highlighttable td { + padding: 0; +} + +div.linenodiv { + background-color: #2b2b2b; + padding: 0; +} + +td.linenos pre { + padding: 7px 5px; +} +td.code div.highlight pre { + width: 717px; + overflow: hidden; +} + +.highlight .hll { + background-color: #353535 !important; +} + +p.plantuml object { + width: 100% !important; + height: 100% !important; + +} + +.highlighted { + background-color: transparent; + color: #0e84b5; + +} + +/* Sidebar TOC: make the current chapter bold */ +.current.reference.internal { + font-weight: bold; +} \ No newline at end of file diff --git a/docs/_build/html/_static/gw_logo.png b/docs/_build/html/_static/gw_logo.png new file mode 100644 index 00000000..233c46db Binary files /dev/null and b/docs/_build/html/_static/gw_logo.png differ diff --git a/docs/_build/html/_static/language_data.js b/docs/_build/html/_static/language_data.js new file mode 100644 index 00000000..367b8ed8 --- /dev/null +++ b/docs/_build/html/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/docs/_build/html/_static/minus.png b/docs/_build/html/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/docs/_build/html/_static/minus.png differ diff --git a/docs/_build/html/_static/nameko.css b/docs/_build/html/_static/nameko.css new file mode 100644 index 00000000..9d3ed06b --- /dev/null +++ b/docs/_build/html/_static/nameko.css @@ -0,0 +1,530 @@ +/* + * nameko.css_t + * ~~~~~~~~~~~~~~ + * + * Sphinx Nameko Theme + * + * Forked from https://github.com/ignacysokolowski/sphinx-readable-theme + * + * :copyright: Copyright 2013 Ignacy Sokolowski; 2015 Lifealike, Ltd. DBA onefinestay + * :license: MIT, see LICENSE for details. + * + */ + + + +@import url('basic.css'); + +/* -- page layout --------------------------------------------------------- */ + +body { + font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; + margin: 0; + padding: 0; + background-color: rgb(252, 252, 252); +} + +h1, h2, h3, h4 { + color: #2a2730; + font-weight: 700; + font-family: "Lora","Times",serif; + clear: both; +} + +div.document { + margin: 10px auto 0 auto; + max-width: 940px; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: rgb(252, 252, 252); + color: #3e4349; + padding: 0 30px 30px 30px; +} + +div.footer { + color: #555; + font-size: 14px; + margin: 20px auto 30px auto; + text-align: right; + max-width: 880px; +} + +div.footer a { + color: #444; + text-decoration: underline; +} + +div.related { + padding: 10px 10px; + width: auto; +} + +div.sphinxsidebar { + float: left; + font-size: 14px; + line-height: 1.5em; + margin-left: -100%; + width: 230px; +} + +div.sphinxsidebarwrapper { + font-size: 14px; + line-height: 1.5em; + padding: 10px 0 10px 10px; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + color: #333; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 1.1em; +} + +div.sphinxsidebar h3 a { + color: #333; +} + +div.sphinxsidebar p { + color: #888; +} + +div.sphinxsidebar p.searchtip { + line-height: 1.4em; +} + +div.sphinxsidebar ul { + color: #000; + margin: 10px 0 20px; + padding: 0; +} + +div.sphinxsidebar a { + color: #444; +} + +div.sphinxsidebar a:hover { + color: #d00; +} + +div.sphinxsidebar input { + border: 1px solid #ccc; + font-family: sans-serif; + font-size: 1em; +} + +/* -- body styles --------------------------------------------------------- */ + +a { + color: #900; + text-decoration: none; +} + +a:visited { + color: #700; +} + +a:hover { + color: #d00; + text-decoration: underline; +} + +hr { + border: 1px solid #b1b4b6; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { font-weight: normal; } + +div.body h1, +div.body h2, +div.body h3, +div.body h4 { color: #212224; } +div.body h5 { color: #000; } +div.body h6 { color: #777; } + +div.body h1 { margin: 0 0 10px 0; } +div.body h2, +div.body h3 { margin: 30px 0px 10px 0px; } +div.body h4, +div.body h5, +div.body h6 { margin: 20px 0px 10px 0px; } + +div.body h1 { padding: 0 0 10px 0; } +div.body h2, +div.body h3 { padding: 10px 0 10px 0; } +div.body h4 { padding: 10px 0 10px 0; } +div.body h5, +div.body h6 { padding: 10px 0 0 0; } + +div.body h1, +div.body h2, +div.body h3 { border-bottom: 1px solid #ddd; } +div.body h4 { border-bottom: 1px solid #e5e5e5; } + +div.body h1 { font-size: 230%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 130%; } +div.body h4 { font-size: 110%; } +div.body h5 { font-size: 105%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: #fff; +} + +div.body ul { + list-style: disc; + margin: 1em 0; + padding-left: 1.3em; +} + +div.body ul ul, div.body ol ul { + margin: .2em 0; + padding-left: 1.2em; +} + +div.body ul li { + padding: 2px 0; +} + +div.body ul.search li { + padding: 5px 0 5px 20px; +} + +div.body ol { + counter-reset: li; + margin-left: 0; + padding-left: 0; +} + +div.body ol ol { + margin: .2em 0; +} + +div.body ol > li { + list-style: none; + margin: 0 0 0 1.9em; + padding: 2px 1px; + position: relative; +} + +div.body ol > li:before { + content: counter(li) "."; + counter-increment: li; + top: -2px; + left: -1.9em; + width: 1.9em; + padding: 4px 0; + position: absolute; + text-align: left; +} + +div.body p, +div.body dd, +div.body li { + line-height: 1.4em; +} + +div.sidebar, div.topic { + background-color: #f6f7f9; + border: 1px solid #cdcdd1; + padding: 0; + margin: 0 0 1em 1.5em; +} + +div.topic { + margin: 0; +} + +div.sidebar p.sidebar-title, div.topic p.topic-title { + background-color: #cdcdd1; + padding: 8px; +} + +div.sidebar p, div.topic p { + font-size: 0.9em; + padding: 10px 20px 0px 20px; +} + +div.admonition { + background-color: #f6f7f9; + border: 1px solid #cdcdd1; + padding: 0px 12px 12px 12px; + font-size: 0.9em; +} + +p.admonition-title { + display: block; + background-color: #cdcdd1; + margin: -12px -12px 12px -12px; + padding: 6px 12px; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.attention, div.caution, div.seealso { + background-color: #fef9e9; + border: 1px solid #fbe091; +} + +div.attention p.admonition-title, +div.caution p.admonition-title, +div.seealso p.admonition-title { + background-color: #fbe091; +} + +div.danger, div.error, div.warning { + border: 1px solid #FEA1A2; + background-color: #FEE4E4; +} + +div.danger p.admonition-title, +div.error p.admonition-title, +div.warning p.admonition-title { + background-color: #FEA1A2; +} + +div.note, div.important, div.hint, div.tip { + border: 1px solid #daebea; + background-color: #F7FAFA; +} + +div.note p.admonition-title, +div.important p.admonition-title, +div.hint p.admonition-title, +div.tip p.admonition-title { + background-color: #daebea; +} + +div.highlight { + background-color: #fff; +} + +pre { + background-color: #f6f7f9; + border: 1px solid #9aa2ab; + color: #222; + font-size: 0.75em; + line-height: 1.5em; + margin: 1.5em 0 1.5em 0; + padding: 10px; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +tt, code, code.xref { + padding: 2px; + background-color: #fff; + border: 1px solid #daebea; + font-size: 0.75em; +} + +tt.descname, code.descname { + font-size: 0.95em; +} + +tt.xref, a tt, code.xref, a code { + font-weight: normal; +} + +dl.class, dl.function { + margin-bottom: 50px; +} + +dl.function > dt, +dl.attribute > dt, +dl.classmethod > dt, +dl.method > dt, +dl.class > dt, +dl.exception > dt { + background-color: #f5f5f5; + margin: 25px 0 10px 0; + padding: 1px 10px; +} + +dl.function code.descname, +dl.attribute code.descname, +dl.classmethod code.descname, +dl.method code.descname, +dl.class code.descname, +dl.exception code.descname { + border: none; +} + +table.docutils { + width: 100%; + font-size: 0.9em; +} + +table.docutils.footnote { + width: auto; +} + +table.docutils thead, +table.docutils tfoot { + background: #f5f5f5; +} + +table.docutils thead tr th { + color: #000; + font-weight: normal; + padding: 7px 5px; + vertical-align: middle; +} + +table.docutils tbody tr th, +table.docutils tbody tr td { + border-bottom: 0; + border-top: solid 1px #ddd; + padding: 7px 5px; + vertical-align: top; +} +table.docutils tbody tr:last-child th, +table.docutils tbody tr:last-child td { + border-bottom: solid 1px #ddd; +} + +table.docutils thead tr td p, +table.docutils tfoot tr td p, +table.docutils tbody tr td p, +table.docutils thead tr td ul, +table.docutils tfoot tr td ul, +table.docutils tbody tr td ul, +table.docutils thead tr td ol, +table.docutils tfoot tr td ol, +table.docutils tbody tr td ol { + margin: 0 0 .5em; +} +table.docutils thead tr td p.last, +table.docutils tfoot tr td p.last, +table.docutils tbody tr td p.last, +table.docutils thead tr td ul.last, +table.docutils tfoot tr td ul.last, +table.docutils tbody tr td ul.last, +table.docutils thead tr td ol.last, +table.docutils tfoot tr td ol.last, +table.docutils tbody tr td ol.last { + margin-bottom: 0; +} + +code.descname { + font-size: 0.8em; +} + +span.viewcode-link { + font-size: 0.8em; + line-height: 1.75; +} + +dl em { + font-size: 0.9em; +} + +.viewcode-back { + font-family: Arial, sans-serif; +} + +div.viewcode-block:target { + background-color: #fef9e9; + border-top: 1px solid #fbe091; + border-bottom: 1px solid #fbe091; +} + +@media screen and (max-width: 870px) { + + div.document { + width: auto; + margin: 0; + } + + div.documentwrapper { + float: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0 20px 30px 20px; + } + + div.footer { + background-color: #333; + color: #888; + margin: 0; + padding: 10px 20px 20px; + text-align: left; + width: auto; + } + + div.footer a { + color: #bbb; + } + + div.footer a:hover { + color: #fff; + } + + div.sphinxsidebar { + background-color: #333; + color: #fff; + float: none; + margin: 0; + padding: 10px 20px; + width: auto; + } + + div.sphinxsidebar h3, + div.sphinxsidebar h4, + div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar ul { + color: #999; + } + + div.sphinxsidebar a { + color: #aaa; + } + + div.sphinxsidebar a:hover { + color: #fff; + } + +} \ No newline at end of file diff --git a/docs/_build/html/_static/plus.png b/docs/_build/html/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/docs/_build/html/_static/plus.png differ diff --git a/docs/_build/html/_static/pygments.css b/docs/_build/html/_static/pygments.css new file mode 100644 index 00000000..07454c6b --- /dev/null +++ b/docs/_build/html/_static/pygments.css @@ -0,0 +1,83 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #004461; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #582800 } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902 } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #745334 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #990000 } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #004461 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #888888 } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +.highlight .mb { color: #990000 } /* Literal.Number.Bin */ +.highlight .mf { color: #990000 } /* Literal.Number.Float */ +.highlight .mh { color: #990000 } /* Literal.Number.Hex */ +.highlight .mi { color: #990000 } /* Literal.Number.Integer */ +.highlight .mo { color: #990000 } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_build/html/_static/searchtools.js b/docs/_build/html/_static/searchtools.js new file mode 100644 index 00000000..92da3f8b --- /dev/null +++ b/docs/_build/html/_static/searchtools.js @@ -0,0 +1,619 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/docs/_build/html/_static/small_groundwork.css b/docs/_build/html/_static/small_groundwork.css new file mode 100644 index 00000000..298de27e --- /dev/null +++ b/docs/_build/html/_static/small_groundwork.css @@ -0,0 +1,102 @@ +/* + * small_flask.css_t + * ~~~~~~~~~~~~~~~~~ + * + * :copyright: Copyright 2010 by Armin Ronacher. + * :license: Flask Design License, see LICENSE for details. + */ + +body { + margin: 0; + padding: 0 10px 0 10px; +} + +.github_fork { + display: none; +} + +div.document { + margin: 10px; +} + +div.documentwrapper { + float: none; +} + +div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: white; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, +div.sphinxsidebar h3 a { + color: white; +} + +div.sphinxsidebar a { + color: #aaa; +} + +div.sphinxsidebar p.logo { + display: none; +} + +div.document { + width: 100%; + margin: 0; +} + +div.related { + display: block; + margin: 0; + padding: 10px 0 20px 0; +} + +div.related ul, +div.related ul li { + margin: 0; + padding: 0; +} + +div.footer { + display: none; +} + +div.bodywrapper { + margin: 0; +} + +div.body { + min-height: 0; + padding: 10px; +} + +.rtd_doc_footer { + display: none; +} + +.document { + width: auto; +} + +.footer { + width: auto; +} + +.footer { + width: auto; +} + +pre { + margin: 15px -10px !important; +} + +div.admonition { + margin: 20px -10px !important; +} + diff --git a/docs/_build/html/_static/sphinx_highlight.js b/docs/_build/html/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/docs/_build/html/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html new file mode 100644 index 00000000..d800722b --- /dev/null +++ b/docs/_build/html/genindex.html @@ -0,0 +1,3106 @@ + + + + + + + Index — ldp documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | X + | Z + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

J

+ + + +
+ +

L

+ + + +
    +
  • + ldp + +
  • +
  • + ldp.agent + +
  • +
  • + ldp.agent.agent + +
  • +
  • + ldp.agent.agent_client + +
  • +
  • + ldp.agent.interactive_agent + +
  • +
  • + ldp.agent.memory_agent + +
  • +
  • + ldp.agent.react_agent + +
  • +
  • + ldp.agent.simple_agent + +
  • +
  • + ldp.agent.tree_of_thoughts_agent + +
  • +
  • + ldp.alg + +
  • +
  • + ldp.alg.algorithms + +
  • +
  • + ldp.alg.beam_search + +
  • +
  • + ldp.alg.callbacks + +
  • +
  • + ldp.alg.datasets + +
  • +
  • + ldp.alg.optimizer + +
  • +
  • + ldp.alg.optimizer.ape + +
  • +
  • + ldp.alg.optimizer.memory + +
  • +
  • + ldp.alg.optimizer.opt + +
  • +
  • + ldp.alg.optimizer.replay_buffers + +
  • +
  • + ldp.alg.rollout + +
  • +
  • + ldp.alg.runners + +
  • +
  • + ldp.alg.tree_search + +
  • +
  • + ldp.data_structures + +
  • +
  • + ldp.graph + +
  • +
  • + ldp.graph.async_torch + +
  • +
  • + ldp.graph.common_ops + +
  • +
  • + ldp.graph.gradient_estimators + +
  • +
  • + ldp.graph.loss_ops + +
  • +
  • + ldp.graph.memory + +
  • +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

X

+ + +
+ +

Z

+ + +
+ + + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html new file mode 100644 index 00000000..d21f6c0a --- /dev/null +++ b/docs/_build/html/index.html @@ -0,0 +1,158 @@ + + + + + + + + Welcome to ldp’s documentation! — ldp documentation + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ldp.agent.html b/docs/_build/html/ldp.agent.html new file mode 100644 index 00000000..0b2db7d8 --- /dev/null +++ b/docs/_build/html/ldp.agent.html @@ -0,0 +1,1378 @@ + + + + + + + + ldp.agent package — ldp documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp.agent package

+
+

Submodules

+
+
+

ldp.agent.agent module

+
+
+class ldp.agent.agent.Agent[source]
+

Bases: ABC, Generic[TAgentState]

+
+
+classmethod from_name(name: str, **kwargs) Agent[source]
+
+ +
+
+abstract async get_asv(agent_state: TAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], TAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+abstract async init_state(tools: list[Tool]) TAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+named_ops() Iterable[tuple[str, Op]][source]
+

Analogous to torch.nn.Module.named_parameters().

+
+ +
+ +
+
+class ldp.agent.agent.AgentConfig(*, agent_type: str, agent_kwargs: dict[str, JsonValue] = None)[source]
+

Bases: BaseModel

+

Configuration for specifying the type of agent i.e. the subclass of Agent above.

+
+
+agent_kwargs: dict[str, JsonValue]
+
+ +
+
+agent_type: str
+
+ +
+
+construct_agent() Agent[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'agent_kwargs': FieldInfo(annotation=dict[str, JsonValue], required=False, default_factory=dict, description="Keyword arguments to pass to the agent's constructor."), 'agent_type': FieldInfo(annotation=str, required=True, description='The type of agent to be used. This should be a subclass of Agent above.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+
+

ldp.agent.agent_client module

+
+
+class ldp.agent.agent_client.HTTPAgentClient(*args, **kwargs)[source]
+

Bases: Agent[TSerializableAgentState]

+

Interact with an Agent running in a server via POST requests.

+
+
+async get_asv(agent_state: TSerializableAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], TSerializableAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+async init_state(tools: list[Tool]) TSerializableAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+ +
+
+ldp.agent.agent_client.make_simple_agent_server(agent: Agent[SimpleAgentState], render_docs: bool = False) FastAPI[source]
+

Make a FastAPI app designed to work with the above HTTPAgentClient.

+

Here’s how this works: +1. There is an entity orchestrating an Agent’s interactions with an Environment.

+
+

A simple example of this is an integration test that sequentially calls +Agent.get_asv and Environment.step.

+
+
    +
  1. That entity is given the above HTTPAgentClient. Any Agent.init_state or +Agent.get_asv calls the orchestration entity makes are actually +POST requests under the hood. The agent’s “brains” aren’t local.

  2. +
  3. Remotely, this server code is running, and is where the actual Agent logic lives. +An example of this is a remote server containing GPU(s).

  4. +
+
+ +
+
+

ldp.agent.interactive_agent module

+
+
+class ldp.agent.interactive_agent.InteractiveAgent(*args, **kwargs)[source]
+

Bases: Agent[SimpleAgentState]

+

An “agent” that provides an interface for human users to interact with environments.

+
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+async init_state(tools: list[Tool]) SimpleAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+ +
+
+

ldp.agent.memory_agent module

+

This module defines the MemoryAgent class, which extends a base agent model with memory.

+

capabilities. The MemoryAgent can pick and invoke tools based on the stored and retrieved +memories, formatted using specified prompts. A memory is typically a set of previous trajectories

+
+
+class ldp.agent.memory_agent.MemoryAgent(*args, llm_model: dict[str, ~typing.Any] = {'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, sys_prompt: str | None = None, prompt: str = '<episode-memories>\n<description>\nThese are relevant memories from previous attempts at similar tasks, along with the action taken and the discounted cumulative reward from that action. A negative reward is failure, a positive reward is success.\n</description>{memories}</episode-memories>\n\nConsidering the memories, choose the next action.', query_factory: ~collections.abc.Callable[[~collections.abc.Iterable[~aviary.message.Message]], ~collections.abc.Awaitable[str]] = <function _default_query_factory>, memory_prompt: str = '<memory><obs>{input}</obs><action>{output}</action><reward>{value}</reward></memory>', num_memories: int = 3)[source]
+

Bases: SimpleAgent

+

Simple agent that can pick and invoke tools with memory.

+

NOTE: the MemoryAgent does not maintain an explicit value estimate, +it simply supplies previous trajectories via the prompt. +As such, the value estimate vhat will always be zero.

+
+
+async default_query_factory() str
+
+ +
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+memory_prompt: str
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, description='Starting configuration for the LLM model. Trainable.'), 'memory_prompt': FieldInfo(annotation=str, required=False, default='<memory><obs>{input}</obs><action>{output}</action><reward>{value}</reward></memory>', description='Prompt for formatting an individual memory. Use XML instead of JSON to avoid potential escaping issues.'), 'num_memories': FieldInfo(annotation=int, required=False, default=3, description='Number of memories to retrieve from MemoryOp'), 'prompt': FieldInfo(annotation=str, required=False, default='<episode-memories>\n<description>\nThese are relevant memories from previous attempts at similar tasks, along with the action taken and the discounted cumulative reward from that action. A negative reward is failure, a positive reward is success.\n</description>{memories}</episode-memories>\n\nConsidering the memories, choose the next action.', description='Prompt that includes the memories.'), 'query_factory': FieldInfo(annotation=Callable[list, Awaitable[str]], required=False, default=<function _default_query_factory>, description="Async function to generate a Memory query string from messages. It's async so this can involve an LLM completion if desired.", exclude=True), 'sys_prompt': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Opt-in system prompt. If one is passed, the system prompt is not set up to be trainable, because this class is meant to be quite simple as far as possible hyperparameters.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+num_memories: int
+
+ +
+
+prompt: str
+
+ +
+
+query_factory: Callable[[Iterable[Message]], Awaitable[str]]
+
+ +
+ +
+
+

ldp.agent.react_agent module

+
+
+class ldp.agent.react_agent.ReActAgent(*args, llm_model: dict[str, Any] = {'logprobs': True, 'model': 'gpt-4o-2024-08-06', 'temperature': 0.1, 'top_logprobs': 1}, sys_prompt: str = 'Answer the following questions as best you can. You have access to the following tools:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: comma separated list of inputs to action as python tuple\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\n\nExample:\n\nThought: I need to use the get_weather tool\nAction: get_weather\nAction Input: "New York", 7\nObservation: The 7 day forecast for New York is [...]', tool_description_method: ToolDescriptionMethods = ToolDescriptionMethods.STR)[source]
+

Bases: BaseModel, Agent[SimpleAgentState]

+

An Act or ReAct Agent built to work with chat models.

+

Paper: https://arxiv.org/abs/2210.03629

+

The ReAct style is like so, and note Act style has no ‘Thought: ‘ entries: +System:

+
+

Answer the following questions as best you can. You have access to the following tools:

+
+

{tools}

+

Use the following format:

+

Thought: you should always think about what to do +Action: the action to take, should be one of [{tool_names}] +Action Input: the input to the action +Observation: the result of the action +… (this Thought/Action/Action Input/Observation can repeat N times)

+
+
+
+
User:

{questions}

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
User:

Observation:

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
+

+

One notable design decision is that ReAct’s state does not necessarily +track ToolRequestMessage. Recall that aviary is in a partially observable +domain, meaning we don’t need to have perfect symmetry with Environments. +Instead, ReActAgent’s state stores a ReAct-style message history, where the +messages are plain Message (and not a ToolRequestMessage).

+
+
+static after_retry_failure_log(retry_state: RetryCallState)[source]
+
+ +
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+async init_state(tools: list[Tool]) SimpleAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+llm_model: dict[str, Any]
+
+ +
+
+classmethod make_act_agent(**kwargs) Self[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1, 'logprobs': True, 'top_logprobs': 1}, description='Starting configuration for the LLM model.'), 'sys_prompt': FieldInfo(annotation=str, required=False, default='Answer the following questions as best you can. You have access to the following tools:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: comma separated list of inputs to action as python tuple\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\n\nExample:\n\nThought: I need to use the get_weather tool\nAction: get_weather\nAction Input: "New York", 7\nObservation: The 7 day forecast for New York is [...]', description='Learnable system prompt template, defaults to ReAct.'), 'tool_description_method': FieldInfo(annotation=ToolDescriptionMethods, required=False, default=<ToolDescriptionMethods.STR: 'describe_str'>, description="Method used to describe the tools, defaults to 'str' description.")}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+sys_prompt: str
+
+ +
+
+tool_description_method: ToolDescriptionMethods
+
+ +
+ +
+
+

ldp.agent.simple_agent module

+
+
+class ldp.agent.simple_agent.SimpleAgent(*args, llm_model: dict[str, Any] = {'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, sys_prompt: str | None = None)[source]
+

Bases: BaseModel, Agent[SimpleAgentState]

+

Simple agent that can pick and invoke tools with a language model.

+

It does not have a system prompt because it’s meant to be lightweight.

+
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+async init_state(tools: list[Tool]) SimpleAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+llm_model: dict[str, Any]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, description='Starting configuration for the LLM model. Trainable.'), 'sys_prompt': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Opt-in system prompt. If one is passed, the system prompt is not set up to be trainable, because this class is meant to be quite simple as far as possible hyperparameters.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+sys_prompt: str | None
+
+ +
+ +
+
+class ldp.agent.simple_agent.SimpleAgentState(*, tools: list[Tool] = None, messages: list[ToolRequestMessage | ToolResponseMessage | Message] = None)[source]
+

Bases: BaseModel

+

Simple bucket for an Agent to access tools and store messages.

+
+
+get_next_state(obs: list[Message] | None = None, tools: list[Tool] | None = None, **kwargs) Self[source]
+

Get the next agent state without mutating the optional prior state.

+

Do not mutate self here, just read from it.

+
+
Parameters:
+
    +
  • obs – Optional observation messages to use in creating the next state.

  • +
  • tools – Optional list of tools available to the agent. If unspecified, these +should be pulled from the prior_state.

  • +
  • kwargs – Additional keyword arguments to pass to this class’s constructor.

  • +
+
+
Returns:
+

The next agent state (which is not an in-place change to self).

+
+
+
+ +
+
+messages: list[ToolRequestMessage | ToolResponseMessage | Message]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'messages': FieldInfo(annotation=list[Union[ToolRequestMessage, ToolResponseMessage, Message]], required=False, default_factory=list), 'tools': FieldInfo(annotation=list[Tool], required=False, default_factory=list)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+tools: list[Tool]
+
+ +
+ +
+
+

ldp.agent.tree_of_thoughts_agent module

+

Module for the Tree of Thoughts agent.

+

This module defines the Tree of Thoughts agent which uses a language model to generate and evaluate possible +steps in a puzzle or problem-solving environment. The agent employs a tree search mechanism to explore different +solutions and selects the most promising ones based on evaluations.

+

This module is based on the following paper: https://openreview.net/forum?id=5Xc1ecxO1h

+

Note: TreeofThoughtsAgent is currently tested as a baseline agent for Game of 24. It does not yet support tool calls +that operate on the intermediate reasoning steps. This would probably entail a redefinition of the POMDP to +undertake intermediate reasoning steps as environment steps.

+
+
+class ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent(*args, llm_model: dict[str, ~typing.Any] = {'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, value_prompt_func: ~collections.abc.Callable[[str, str], str] = <function TreeofThoughtsAgent.<lambda>>, proposal_prompt_func: ~collections.abc.Callable[[str, str], str] = <function TreeofThoughtsAgent.<lambda>>)[source]
+

Bases: BaseModel, Agent[SimpleAgentState]

+

Tree of Thoughts Agent.

+

This agent uses a tree search mechanism combined with an LLM to generate and evaluate +possible steps in a problem-solving environment. It is designed to explore different solutions +and select the most promising ones based on a heuristic evaluation function.

+
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message], eval_function: Callable[[str, list[str]], float], n_steps: int = 0, n_select_samples: int = 0) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Generate and evaluate possible steps in the problem-solving process.

+
+
Parameters:
+
    +
  • agent_state – The current state of the agent.

  • +
  • obs – The observations provided to the agent.

  • +
  • eval_function – Function to evaluate the generated paths in the tree.

  • +
  • n_steps – Number of steps to generate. Defaults to 0. Dictated by the environment.

  • +
  • n_select_samples – Number of tree nodes to select to explore in each step. Defaults to 0.

  • +
+
+
Returns:
+

The result of the operation, the new state of the agent, and the number representing the value (0).

+
+
+
+ +
+
+async init_state(tools: list[Tool]) SimpleAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+llm_model: dict[str, Any]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, description='Starting configuration for the LLM model.'), 'proposal_prompt_func': FieldInfo(annotation=Callable[list, str], required=False, default=<function TreeofThoughtsAgent.<lambda>>, description='Function to format proposal prompt template.'), 'value_prompt_func': FieldInfo(annotation=Callable[list, str], required=False, default=<function TreeofThoughtsAgent.<lambda>>, description='Function to format value prompt template.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+proposal_prompt_func: Callable[[str, str], str]
+
+ +
+
+value_prompt_func: Callable[[str, str], str]
+
+ +
+ +
+
+

Module contents

+
+
+class ldp.agent.Agent[source]
+

Bases: ABC, Generic[TAgentState]

+
+
+classmethod from_name(name: str, **kwargs) Agent[source]
+
+ +
+
+abstract async get_asv(agent_state: TAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], TAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+abstract async init_state(tools: list[Tool]) TAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+named_ops() Iterable[tuple[str, Op]][source]
+

Analogous to torch.nn.Module.named_parameters().

+
+ +
+ +
+
+class ldp.agent.AgentConfig(*, agent_type: str, agent_kwargs: dict[str, JsonValue] = None)[source]
+

Bases: BaseModel

+

Configuration for specifying the type of agent i.e. the subclass of Agent above.

+
+
+agent_kwargs: dict[str, JsonValue]
+
+ +
+
+agent_type: str
+
+ +
+
+construct_agent() Agent[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'agent_kwargs': FieldInfo(annotation=dict[str, JsonValue], required=False, default_factory=dict, description="Keyword arguments to pass to the agent's constructor."), 'agent_type': FieldInfo(annotation=str, required=True, description='The type of agent to be used. This should be a subclass of Agent above.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+
+class ldp.agent.DefaultLLMModelNames(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: StrEnum

+

Defaults for LLM models, pin exact versions for performance stability.

+
+
+OPENAI = 'gpt-4o-2024-08-06'
+
+ +
+ +
+
+class ldp.agent.HTTPAgentClient(*args, **kwargs)[source]
+

Bases: Agent[TSerializableAgentState]

+

Interact with an Agent running in a server via POST requests.

+
+
+async get_asv(agent_state: TSerializableAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], TSerializableAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+async init_state(tools: list[Tool]) TSerializableAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+ +
+
+class ldp.agent.MemoryAgent(*args, llm_model: dict[str, ~typing.Any] = {'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, sys_prompt: str | None = None, prompt: str = '<episode-memories>\n<description>\nThese are relevant memories from previous attempts at similar tasks, along with the action taken and the discounted cumulative reward from that action. A negative reward is failure, a positive reward is success.\n</description>{memories}</episode-memories>\n\nConsidering the memories, choose the next action.', query_factory: ~collections.abc.Callable[[~collections.abc.Iterable[~aviary.message.Message]], ~collections.abc.Awaitable[str]] = <function _default_query_factory>, memory_prompt: str = '<memory><obs>{input}</obs><action>{output}</action><reward>{value}</reward></memory>', num_memories: int = 3)[source]
+

Bases: SimpleAgent

+

Simple agent that can pick and invoke tools with memory.

+

NOTE: the MemoryAgent does not maintain an explicit value estimate, +it simply supplies previous trajectories via the prompt. +As such, the value estimate vhat will always be zero.

+
+
+async default_query_factory() str
+
+ +
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+llm_model: dict[str, Any]
+
+ +
+
+memory_prompt: str
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, description='Starting configuration for the LLM model. Trainable.'), 'memory_prompt': FieldInfo(annotation=str, required=False, default='<memory><obs>{input}</obs><action>{output}</action><reward>{value}</reward></memory>', description='Prompt for formatting an individual memory. Use XML instead of JSON to avoid potential escaping issues.'), 'num_memories': FieldInfo(annotation=int, required=False, default=3, description='Number of memories to retrieve from MemoryOp'), 'prompt': FieldInfo(annotation=str, required=False, default='<episode-memories>\n<description>\nThese are relevant memories from previous attempts at similar tasks, along with the action taken and the discounted cumulative reward from that action. A negative reward is failure, a positive reward is success.\n</description>{memories}</episode-memories>\n\nConsidering the memories, choose the next action.', description='Prompt that includes the memories.'), 'query_factory': FieldInfo(annotation=Callable[list, Awaitable[str]], required=False, default=<function _default_query_factory>, description="Async function to generate a Memory query string from messages. It's async so this can involve an LLM completion if desired.", exclude=True), 'sys_prompt': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Opt-in system prompt. If one is passed, the system prompt is not set up to be trainable, because this class is meant to be quite simple as far as possible hyperparameters.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+num_memories: int
+
+ +
+
+prompt: str
+
+ +
+
+query_factory: Callable[[Iterable[Message]], Awaitable[str]]
+
+ +
+
+sys_prompt: str | None
+
+ +
+ +
+
+class ldp.agent.ReActAgent(*args, llm_model: dict[str, Any] = {'logprobs': True, 'model': 'gpt-4o-2024-08-06', 'temperature': 0.1, 'top_logprobs': 1}, sys_prompt: str = 'Answer the following questions as best you can. You have access to the following tools:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: comma separated list of inputs to action as python tuple\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\n\nExample:\n\nThought: I need to use the get_weather tool\nAction: get_weather\nAction Input: "New York", 7\nObservation: The 7 day forecast for New York is [...]', tool_description_method: ToolDescriptionMethods = ToolDescriptionMethods.STR)[source]
+

Bases: BaseModel, Agent[SimpleAgentState]

+

An Act or ReAct Agent built to work with chat models.

+

Paper: https://arxiv.org/abs/2210.03629

+

The ReAct style is like so, and note Act style has no ‘Thought: ‘ entries: +System:

+
+

Answer the following questions as best you can. You have access to the following tools:

+
+

{tools}

+

Use the following format:

+

Thought: you should always think about what to do +Action: the action to take, should be one of [{tool_names}] +Action Input: the input to the action +Observation: the result of the action +… (this Thought/Action/Action Input/Observation can repeat N times)

+
+
+
+
User:

{questions}

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
User:

Observation:

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
+

+

One notable design decision is that ReAct’s state does not necessarily +track ToolRequestMessage. Recall that aviary is in a partially observable +domain, meaning we don’t need to have perfect symmetry with Environments. +Instead, ReActAgent’s state stores a ReAct-style message history, where the +messages are plain Message (and not a ToolRequestMessage).

+
+
+static after_retry_failure_log(retry_state: RetryCallState)[source]
+
+ +
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+async init_state(tools: list[Tool]) SimpleAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+llm_model: dict[str, Any]
+
+ +
+
+classmethod make_act_agent(**kwargs) Self[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1, 'logprobs': True, 'top_logprobs': 1}, description='Starting configuration for the LLM model.'), 'sys_prompt': FieldInfo(annotation=str, required=False, default='Answer the following questions as best you can. You have access to the following tools:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: comma separated list of inputs to action as python tuple\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\n\nExample:\n\nThought: I need to use the get_weather tool\nAction: get_weather\nAction Input: "New York", 7\nObservation: The 7 day forecast for New York is [...]', description='Learnable system prompt template, defaults to ReAct.'), 'tool_description_method': FieldInfo(annotation=ToolDescriptionMethods, required=False, default=<ToolDescriptionMethods.STR: 'describe_str'>, description="Method used to describe the tools, defaults to 'str' description.")}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+sys_prompt: str
+
+ +
+
+tool_description_method: ToolDescriptionMethods
+
+ +
+ +
+
+class ldp.agent.SimpleAgent(*args, llm_model: dict[str, Any] = {'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, sys_prompt: str | None = None)[source]
+

Bases: BaseModel, Agent[SimpleAgentState]

+

Simple agent that can pick and invoke tools with a language model.

+

It does not have a system prompt because it’s meant to be lightweight.

+
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message]) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Get new action, state, and value given state and observation messages.

+

NOTE: the method’s name has action listed before state to help you realize it’s +a new state.

+
+
Parameters:
+
    +
  • agent_state – Optional current agent state, pass None if irrelevant. +This can be something like agent memory.

  • +
  • obs – Most recent list of observation messages from the environment’s steps. +If more observations than the most recent list are necessary, track them +in the agent state.

  • +
+
+
Returns:
+

+
Three-tuple of new action, new agent state, and estimated value. The

agent_state is returned as a copy so that you can safely mutate it +without affecting the original. The estimated value is the agent’s +estimate of the future rewards given the input state and observations, +and is used for RL training. If estimated value doesn’t matter, just +return 0. The value could also come from a Q-value evaluated at the +action chosen by the agent.

+
+
+

+
+
+
+ +
+
+async init_state(tools: list[Tool]) SimpleAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+llm_model: dict[str, Any]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, description='Starting configuration for the LLM model. Trainable.'), 'sys_prompt': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Opt-in system prompt. If one is passed, the system prompt is not set up to be trainable, because this class is meant to be quite simple as far as possible hyperparameters.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+sys_prompt: str | None
+
+ +
+ +
+
+class ldp.agent.SimpleAgentState(*, tools: list[Tool] = None, messages: list[ToolRequestMessage | ToolResponseMessage | Message] = None)[source]
+

Bases: BaseModel

+

Simple bucket for an Agent to access tools and store messages.

+
+
+get_next_state(obs: list[Message] | None = None, tools: list[Tool] | None = None, **kwargs) Self[source]
+

Get the next agent state without mutating the optional prior state.

+

Do not mutate self here, just read from it.

+
+
Parameters:
+
    +
  • obs – Optional observation messages to use in creating the next state.

  • +
  • tools – Optional list of tools available to the agent. If unspecified, these +should be pulled from the prior_state.

  • +
  • kwargs – Additional keyword arguments to pass to this class’s constructor.

  • +
+
+
Returns:
+

The next agent state (which is not an in-place change to self).

+
+
+
+ +
+
+messages: list[ToolRequestMessage | ToolResponseMessage | Message]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'messages': FieldInfo(annotation=list[Union[ToolRequestMessage, ToolResponseMessage, Message]], required=False, default_factory=list), 'tools': FieldInfo(annotation=list[Tool], required=False, default_factory=list)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+tools: list[Tool]
+
+ +
+ +
+
+class ldp.agent.TreeofThoughtsAgent(*args, llm_model: dict[str, ~typing.Any] = {'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, value_prompt_func: ~collections.abc.Callable[[str, str], str] = <function TreeofThoughtsAgent.<lambda>>, proposal_prompt_func: ~collections.abc.Callable[[str, str], str] = <function TreeofThoughtsAgent.<lambda>>)[source]
+

Bases: BaseModel, Agent[SimpleAgentState]

+

Tree of Thoughts Agent.

+

This agent uses a tree search mechanism combined with an LLM to generate and evaluate +possible steps in a problem-solving environment. It is designed to explore different solutions +and select the most promising ones based on a heuristic evaluation function.

+
+
+async get_asv(agent_state: SimpleAgentState, obs: list[Message], eval_function: Callable[[str, list[str]], float], n_steps: int = 0, n_select_samples: int = 0) tuple[OpResult[ToolRequestMessage], SimpleAgentState, float][source]
+

Generate and evaluate possible steps in the problem-solving process.

+
+
Parameters:
+
    +
  • agent_state – The current state of the agent.

  • +
  • obs – The observations provided to the agent.

  • +
  • eval_function – Function to evaluate the generated paths in the tree.

  • +
  • n_steps – Number of steps to generate. Defaults to 0. Dictated by the environment.

  • +
  • n_select_samples – Number of tree nodes to select to explore in each step. Defaults to 0.

  • +
+
+
Returns:
+

The result of the operation, the new state of the agent, and the number representing the value (0).

+
+
+
+ +
+
+async init_state(tools: list[Tool]) SimpleAgentState[source]
+

Initializes the first agent state with the provided tools.

+
+ +
+
+llm_model: dict[str, Any]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'frozen': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-4o-2024-08-06', 'temperature': 0.1}, description='Starting configuration for the LLM model.'), 'proposal_prompt_func': FieldInfo(annotation=Callable[list, str], required=False, default=<function TreeofThoughtsAgent.<lambda>>, description='Function to format proposal prompt template.'), 'value_prompt_func': FieldInfo(annotation=Callable[list, str], required=False, default=<function TreeofThoughtsAgent.<lambda>>, description='Function to format value prompt template.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+proposal_prompt_func: Callable[[str, str], str]
+
+ +
+
+value_prompt_func: Callable[[str, str], str]
+
+ +
+ +
+
+ldp.agent.make_simple_agent_server(agent: Agent[SimpleAgentState], render_docs: bool = False) FastAPI[source]
+

Make a FastAPI app designed to work with the above HTTPAgentClient.

+

Here’s how this works: +1. There is an entity orchestrating an Agent’s interactions with an Environment.

+
+

A simple example of this is an integration test that sequentially calls +Agent.get_asv and Environment.step.

+
+
    +
  1. That entity is given the above HTTPAgentClient. Any Agent.init_state or +Agent.get_asv calls the orchestration entity makes are actually +POST requests under the hood. The agent’s “brains” aren’t local.

  2. +
  3. Remotely, this server code is running, and is where the actual Agent logic lives. +An example of this is a remote server containing GPU(s).

  4. +
+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ldp.alg.html b/docs/_build/html/ldp.alg.html new file mode 100644 index 00000000..e958d537 --- /dev/null +++ b/docs/_build/html/ldp.alg.html @@ -0,0 +1,1627 @@ + + + + + + + + ldp.alg package — ldp documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp.alg package

+
+

Subpackages

+
+ +
+
+
+

Submodules

+
+
+

ldp.alg.algorithms module

+
+
+ldp.alg.algorithms.to_network(op_result: OpResult, max_label_height: int | None = None, max_label_width: int | None = None, G: MultiDiGraph | None = None) MultiDiGraph[source]
+

Populate a NetworkX graph from the input op result’s computation graph.

+

How to export Graphviz .dot file: nx.drawing.nx_pydot.write_dot(G, “file.dot”) +How to render with Graphviz: nx.drawing.nx_pydot.to_pydot(G).write_png(“file.png”) +Online Graphviz renderer: https://dreampuf.github.io/GraphvizOnline/

+
+
Parameters:
+
    +
  • op_result – Starting op result to recurse parent op calls and results.

  • +
  • max_label_height – Optional max label height (lines).

  • +
  • max_label_width – Optional max label width (chars).

  • +
  • G – Optional graph to add nodes/edges to. Allows this to be a recursive function.

  • +
+
+
Returns:
+

Populated a NetworkX multi-edge directed graph.

+
+
+
+ +
+ +
+

ldp.alg.callbacks module

+
+
+class ldp.alg.callbacks.Callback[source]
+

Bases: object

+

Base class for callbacks used by RolloutManager/Evaluator/OnlineTrainer.

+

Pseudocode to demonstrate how callback methods are invoked (marked as *):

+
+
RolloutManager.sample_trajectories():

env.reset() +callback.after_env_reset() * +agent.init_state() +callback.after_agent_init_state() * +while not done:

+
+

callback.before_transition() * +agent.get_asv() +callback.after_agent_get_asv() * +env.step() +callback.after_env_step() * +callback.after_transition() *

+
+
+
Evaluator.evaluate / OnlineTrainer._eval_loop():

callback.before_eval_loop() * +for batch in eval_dataset:

+
+

rollout_manager.sample_trajectories() +callback.after_eval_step() *

+
+

callback.after_eval_loop() *

+
+
OfflineTrainer / OnlineTrainer.train():
+
for batch in train_dataset:

rollout_manager.sample_trajectories() # if online +optimizer.aggregate() +if updating_optimizer:

+
+

optimizer.update() +callback.after_update() *

+
+

callback.after_train_step() *

+
+
+
+
+
+
+async after_agent_get_asv(traj_id: str, action: OpResult[ToolRequestMessage], next_agent_state: Any, value: float) None[source]
+

Invoked by runners after agent.get_asv().

+
+ +
+
+async after_agent_init_state(traj_id: str, init_state: Any) None[source]
+

Invoked by runners after agent.init_state().

+
+ +
+
+async after_env_reset(traj_id: str, obs: list[Message], tools: list[Tool]) None[source]
+

Invoked by runners after env.reset().

+
+ +
+
+async after_env_step(traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool) None[source]
+

Invoked by runners after env.step().

+
+ +
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_eval_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by Evaluator and OnlineTrainer after each evaluation step.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+
+async after_transition(traj_id: str, agent: Agent, env: Environment, transition: Transition) None[source]
+

Invoked by runners after each transition.

+
+ +
+
+async after_update() None[source]
+

Invoked by OnlineTrainer after each optimizer.update() call.

+
+ +
+
+async before_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer before the evaluation loop.

+
+ +
+
+async before_transition(traj_id: str, agent: Agent, env: Environment, agent_state: Any, obs: list[Message]) None[source]
+

Invoked by runners before each transition and after agent and env reset.

+
+ +
+ +
+
+class ldp.alg.callbacks.ClearContextCallback(op_names: Iterable[str] | None = None)[source]
+

Bases: Callback

+
+
+async after_eval_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by Evaluator and OnlineTrainer after each evaluation step.

+
+ +
+
+async after_update() None[source]
+

Invoked by OnlineTrainer after each optimizer.update() call.

+
+ +
+ +
+
+class ldp.alg.callbacks.ComputeTrajectoryMetricsMixin[source]
+

Bases: object

+

Mixin for TaskDataset classes to enable them to compute metrics.

+
+
+compute_trajectory_metrics(trajectories: Sequence[Trajectory]) dict[str, list[float]][source]
+
+ +
+
+tools_to_track: Collection[str | Tool] = {}
+
+ +
+ +
+
+class ldp.alg.callbacks.LoggingCallback(train_dataset: TaskDataset | None = None, eval_dataset: TaskDataset | None = None, metrics_to_log: Collection[str] | None = None)[source]
+

Bases: MeanMetricsCallback

+

Custom callback for logging filtered metrics (e.g., pass rates) to the console.

+

This callback extends the MeanMetricsCallback and allows logging of user-specified metrics +after each training step and after the evaluation loop. It calculates the specified metrics +(e.g., pass rates) from the trajectories and logs the results.

+
+
+async after_eval_loop() None[source]
+

Log metrics and pass rate after the evaluation loop.

+

This method is called after the evaluation loop finishes, calculating and logging +the evaluation metrics and pass rate.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Log metrics and pass rate after each training step.

+

This method is called after every training step, calculating and logging +the training metrics and pass rate.

+
+
Parameters:
+

trajectories – A sequence of trajectories from the training step.

+
+
+
+ +
+ +
+
+class ldp.alg.callbacks.MeanMetricsCallback(*args, **kwargs)[source]
+

Bases: TrajectoryMetricsCallback

+

Take a mean of all metrics.

+
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+
+property eval_means: dict[str, float]
+
+ +
+
+property train_means: dict[str, float]
+
+ +
+ +
+
+class ldp.alg.callbacks.RolloutDebugDumpCallback(output_dir: PathLike | str)[source]
+

Bases: Callback

+

Dump JSONL files for each agent and environment step to a directory.

+
+
+async after_agent_get_asv(traj_id: str, action: OpResult[ToolRequestMessage], next_agent_state: Any, value: float) None[source]
+

Invoked by runners after agent.get_asv().

+
+ +
+
+async after_env_step(traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool) None[source]
+

Invoked by runners after env.step().

+
+ +
+
+async before_transition(traj_id: str, agent: Agent, env: Environment, agent_state, obs: list[Message]) None[source]
+

Invoked by runners before each transition and after agent and env reset.

+
+ +
+ +
+
+class ldp.alg.callbacks.TerminalPrintingCallback[source]
+

Bases: Callback

+

Callback that prints action, observation, and timing information to the terminal.

+
+
+async after_agent_get_asv(traj_id: str, action: OpResult[ToolRequestMessage], next_agent_state: Any, value: float) None[source]
+

Invoked by runners after agent.get_asv().

+
+ +
+
+async after_env_step(traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool) None[source]
+

Invoked by runners after env.step().

+
+ +
+
+async before_transition(traj_id: str, agent: Agent, env: Environment, agent_state: Any, obs: list[Message]) None[source]
+

Start the timer before each transition.

+
+ +
+ +
+
+class ldp.alg.callbacks.TrajectoryFileCallback(output_dir: PathLike | str)[source]
+

Bases: Callback

+

Callback that writes trajectories to a file.

+
+
+async after_transition(traj_id: str, agent: Agent, env: Environment, transition: Transition) None[source]
+

Invoked by runners after each transition.

+
+ +
+
+async before_transition(traj_id: str, agent: Agent, env: Environment, agent_state: Any, obs: list[Message]) None[source]
+

Invoked by runners before each transition and after agent and env reset.

+
+ +
+
+cleanup() None[source]
+
+ +
+ +
+
+class ldp.alg.callbacks.TrajectoryMetricsCallback(train_dataset: TaskDataset | None = None, eval_dataset: TaskDataset | None = None, track_tool_usage: bool = False)[source]
+

Bases: Callback

+

Compute metrics that are defined by task datasets.

+

NOTE: evaluation portion’s after_eval_step/loop() is not concurrency safe because +trajectories should be stored in the order of after_eval_step() calls.

+
+
+async after_env_reset(traj_id: str, obs: list[Message], tools: list[Tool]) None[source]
+

Invoked by runners after env.reset().

+
+ +
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_eval_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by Evaluator and OnlineTrainer after each evaluation step.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+ +
+
+class ldp.alg.callbacks.WandBLoggingCallback(*args, **kwargs)[source]
+

Bases: TrajectoryMetricsCallback

+
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+ +
+
+

ldp.alg.datasets module

+
+
+class ldp.alg.datasets.DummyTaskDataset[source]
+

Bases: DummyTaskDataset, ComputeTrajectoryMetricsMixin

+
+ +
+
+

ldp.alg.rollout module

+
+
+exception ldp.alg.rollout.AgentError(original_exc: Exception)[source]
+

Bases: CaughtError

+
+
+exc_type = 'agent'
+
+ +
+ +
+
+exception ldp.alg.rollout.CaughtError(original_exc: Exception)[source]
+

Bases: Exception

+

Base class for reraised exceptions when catching is enabled.

+
+
+exc_type = 'undefined'
+
+ +
+ +
+
+exception ldp.alg.rollout.EnvError(original_exc: Exception)[source]
+

Bases: CaughtError

+
+
+exc_type = 'env'
+
+ +
+ +
+
+class ldp.alg.rollout.RolloutManager(agent: Agent, catch_agent_failures: bool = True, catch_env_failures: bool = True, callbacks: Sequence[Callback] | None = None, concurrency_limit: int | None = None)[source]
+

Bases: object

+
+
+async sample_trajectories(environment_factory: Callable[[], TEnv], batch_size: int = 1, max_steps: int | None = None) list[tuple[Trajectory, TEnv]][source]
+
+async sample_trajectories(environments: Sequence[Environment], max_steps: int | None = None) list[Trajectory]
+
+ +
+ +
+
+ldp.alg.rollout.reraise_exc_as(reraise: type[CaughtError], enabled: bool) Iterator[None][source]
+
+ +
+
+

ldp.alg.runners module

+
+
+class ldp.alg.runners.Evaluator(config: EvaluatorConfig, agent: Agent, dataset: TaskDataset, callbacks: Sequence[Callback] | None = None)[source]
+

Bases: object

+
+
+async evaluate(**kwargs)
+
+ +
+
+async run(**kwargs) None[source]
+

Run the agent over the provided dataset.

+

This method does not set training mode, so it can be used to collect +trajectories for offline training.

+
+ +
+ +
+
+class ldp.alg.runners.EvaluatorConfig(*, batch_size: int = 1, num_eval_iterations: int | None = None, max_rollout_steps: int | None = None, catch_agent_failures: bool = True, catch_env_failures: bool = True, clear_ctx_at_each_iter: bool = False)[source]
+

Bases: BaseModel

+
+
+batch_size: int
+
+ +
+
+catch_agent_failures: bool
+
+ +
+
+catch_env_failures: bool
+
+ +
+
+clear_ctx_at_each_iter: bool
+
+ +
+
+make_rollout_manager(agent: Agent, callbacks: Sequence[Callback]) RolloutManager[source]
+
+ +
+
+max_rollout_steps: int | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=False, default=1), 'catch_agent_failures': FieldInfo(annotation=bool, required=False, default=True), 'catch_env_failures': FieldInfo(annotation=bool, required=False, default=True), 'clear_ctx_at_each_iter': FieldInfo(annotation=bool, required=False, default=False), 'max_rollout_steps': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'num_eval_iterations': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description='Number of eval iterations. If not provided, will exhaust the dataset. If 0, will not run the eval loop. ')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+num_eval_iterations: int | None
+
+ +
+ +
+
+class ldp.alg.runners.OfflineTrainer(config: OfflineTrainerConfig, agent: Agent, optimizer: Optimizer, train_trajectories: list[Trajectory], callbacks: Sequence[Callback] | None = None)[source]
+

Bases: object

+
+
+async train() None[source]
+
+ +
+ +
+
+class ldp.alg.runners.OfflineTrainerConfig(*, batch_size: int, update_every: int = 1, clear_ctx_at_each_iter: bool = False)[source]
+

Bases: BaseModel

+
+
+batch_size: int
+
+ +
+
+clear_ctx_at_each_iter: bool
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=True), 'clear_ctx_at_each_iter': FieldInfo(annotation=bool, required=False, default=False), 'update_every': FieldInfo(annotation=int, required=False, default=1, description='Number of training iterations to run before updating the model.', metadata=[Ge(ge=1)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+update_every: int
+
+ +
+ +
+
+class ldp.alg.runners.OnlineTrainer(config: OnlineTrainerConfig, agent: Agent, optimizer: Optimizer, train_dataset: TaskDataset, eval_dataset: TaskDataset | None = None, callbacks: Sequence[Callback] | None = None)[source]
+

Bases: object

+
+
+async evaluate(**kwargs)
+
+ +
+
+async train() None[source]
+
+ +
+ +
+
+class ldp.alg.runners.OnlineTrainerConfig(*, batch_size: int, num_eval_iterations: int | None = None, max_rollout_steps: int | None = None, catch_agent_failures: bool = True, catch_env_failures: bool = True, clear_ctx_at_each_iter: bool = False, num_train_iterations: int, num_rollouts_per_env: int = 1, update_every: int = 1, eval_every: int | None = None, eval_before: bool = True)[source]
+

Bases: EvaluatorConfig

+
+
+batch_size: int
+
+ +
+
+clear_ctx_at_each_iter: bool
+
+ +
+
+eval_before: bool
+
+ +
+
+eval_every: int | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=True), 'catch_agent_failures': FieldInfo(annotation=bool, required=False, default=True), 'catch_env_failures': FieldInfo(annotation=bool, required=False, default=True), 'clear_ctx_at_each_iter': FieldInfo(annotation=bool, required=False, default=False), 'eval_before': FieldInfo(annotation=bool, required=False, default=True, description='If True (default), evaluate on the validation set before kicking off training.'), 'eval_every': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description='If set, will repeatedly evaluate on the validation set after this many iterations. If unset (default), no evaluation is performed.'), 'max_rollout_steps': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'num_eval_iterations': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description='Number of eval iterations. If not provided, will exhaust the dataset. If 0, will not run the eval loop. '), 'num_rollouts_per_env': FieldInfo(annotation=int, required=False, default=1, description='Number of rollouts to execute for each environment per training iteration.'), 'num_train_iterations': FieldInfo(annotation=int, required=True, description='Number of iterations (at one batch per iteration) to process during training, and setting to 0 skips training.', metadata=[Ge(ge=0)]), 'update_every': FieldInfo(annotation=int, required=False, default=1, description='Number of training iterations between optimizer update calls.', metadata=[Ge(ge=1)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+num_rollouts_per_env: int
+
+ +
+
+num_train_iterations: int
+
+ +
+
+update_every: int
+
+ +
+ +
+ +
+

Module contents

+
+
+class ldp.alg.Beam(traj, env)[source]
+

Bases: NamedTuple

+
+
+env: Environment
+

Alias for field number 1

+
+ +
+
+traj: Trajectory
+

Alias for field number 0

+
+ +
+ +
+
+class ldp.alg.BeamSearchRollout(agent: Agent, beam_width: int, samples_per_beam: int, env_clone_fn: Callable[[TEnv], Awaitable[TEnv]], agent_clone_fn: Callable[[TAgentState], TAgentState], scoring_fn: Callable[[Trajectory], Awaitable[float]], replay_actions_on_clone: bool = False, callbacks: Sequence[Callback] | None = None, catch_agent_failures: bool = True, catch_env_failures: bool = True, verbose: bool = False)[source]
+

Bases: object

+
+
+async sample_trajectories(environments: Sequence[Environment], max_steps: int | None = None) list[Trajectory][source]
+
+ +
+ +
+
+class ldp.alg.Callback[source]
+

Bases: object

+

Base class for callbacks used by RolloutManager/Evaluator/OnlineTrainer.

+

Pseudocode to demonstrate how callback methods are invoked (marked as *):

+
+
RolloutManager.sample_trajectories():

env.reset() +callback.after_env_reset() * +agent.init_state() +callback.after_agent_init_state() * +while not done:

+
+

callback.before_transition() * +agent.get_asv() +callback.after_agent_get_asv() * +env.step() +callback.after_env_step() * +callback.after_transition() *

+
+
+
Evaluator.evaluate / OnlineTrainer._eval_loop():

callback.before_eval_loop() * +for batch in eval_dataset:

+
+

rollout_manager.sample_trajectories() +callback.after_eval_step() *

+
+

callback.after_eval_loop() *

+
+
OfflineTrainer / OnlineTrainer.train():
+
for batch in train_dataset:

rollout_manager.sample_trajectories() # if online +optimizer.aggregate() +if updating_optimizer:

+
+

optimizer.update() +callback.after_update() *

+
+

callback.after_train_step() *

+
+
+
+
+
+
+async after_agent_get_asv(traj_id: str, action: OpResult[ToolRequestMessage], next_agent_state: Any, value: float) None[source]
+

Invoked by runners after agent.get_asv().

+
+ +
+
+async after_agent_init_state(traj_id: str, init_state: Any) None[source]
+

Invoked by runners after agent.init_state().

+
+ +
+
+async after_env_reset(traj_id: str, obs: list[Message], tools: list[Tool]) None[source]
+

Invoked by runners after env.reset().

+
+ +
+
+async after_env_step(traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool) None[source]
+

Invoked by runners after env.step().

+
+ +
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_eval_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by Evaluator and OnlineTrainer after each evaluation step.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+
+async after_transition(traj_id: str, agent: Agent, env: Environment, transition: Transition) None[source]
+

Invoked by runners after each transition.

+
+ +
+
+async after_update() None[source]
+

Invoked by OnlineTrainer after each optimizer.update() call.

+
+ +
+
+async before_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer before the evaluation loop.

+
+ +
+
+async before_transition(traj_id: str, agent: Agent, env: Environment, agent_state: Any, obs: list[Message]) None[source]
+

Invoked by runners before each transition and after agent and env reset.

+
+ +
+ +
+
+class ldp.alg.ClearContextCallback(op_names: Iterable[str] | None = None)[source]
+

Bases: Callback

+
+
+async after_eval_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by Evaluator and OnlineTrainer after each evaluation step.

+
+ +
+
+async after_update() None[source]
+

Invoked by OnlineTrainer after each optimizer.update() call.

+
+ +
+ +
+
+class ldp.alg.ComputeTrajectoryMetricsMixin[source]
+

Bases: object

+

Mixin for TaskDataset classes to enable them to compute metrics.

+
+
+compute_trajectory_metrics(trajectories: Sequence[Trajectory]) dict[str, list[float]][source]
+
+ +
+
+tools_to_track: Collection[str | Tool] = {}
+
+ +
+ +
+
+class ldp.alg.Evaluator(config: EvaluatorConfig, agent: Agent, dataset: TaskDataset, callbacks: Sequence[Callback] | None = None)[source]
+

Bases: object

+
+
+async evaluate(**kwargs)
+
+ +
+
+async run(**kwargs) None[source]
+

Run the agent over the provided dataset.

+

This method does not set training mode, so it can be used to collect +trajectories for offline training.

+
+ +
+ +
+
+class ldp.alg.EvaluatorConfig(*, batch_size: int = 1, num_eval_iterations: int | None = None, max_rollout_steps: int | None = None, catch_agent_failures: bool = True, catch_env_failures: bool = True, clear_ctx_at_each_iter: bool = False)[source]
+

Bases: BaseModel

+
+
+batch_size: int
+
+ +
+
+catch_agent_failures: bool
+
+ +
+
+catch_env_failures: bool
+
+ +
+
+clear_ctx_at_each_iter: bool
+
+ +
+
+make_rollout_manager(agent: Agent, callbacks: Sequence[Callback]) RolloutManager[source]
+
+ +
+
+max_rollout_steps: int | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=False, default=1), 'catch_agent_failures': FieldInfo(annotation=bool, required=False, default=True), 'catch_env_failures': FieldInfo(annotation=bool, required=False, default=True), 'clear_ctx_at_each_iter': FieldInfo(annotation=bool, required=False, default=False), 'max_rollout_steps': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'num_eval_iterations': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description='Number of eval iterations. If not provided, will exhaust the dataset. If 0, will not run the eval loop. ')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+num_eval_iterations: int | None
+
+ +
+ +
+
+class ldp.alg.LoggingCallback(train_dataset: TaskDataset | None = None, eval_dataset: TaskDataset | None = None, metrics_to_log: Collection[str] | None = None)[source]
+

Bases: MeanMetricsCallback

+

Custom callback for logging filtered metrics (e.g., pass rates) to the console.

+

This callback extends the MeanMetricsCallback and allows logging of user-specified metrics +after each training step and after the evaluation loop. It calculates the specified metrics +(e.g., pass rates) from the trajectories and logs the results.

+
+
+async after_eval_loop() None[source]
+

Log metrics and pass rate after the evaluation loop.

+

This method is called after the evaluation loop finishes, calculating and logging +the evaluation metrics and pass rate.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Log metrics and pass rate after each training step.

+

This method is called after every training step, calculating and logging +the training metrics and pass rate.

+
+
Parameters:
+

trajectories – A sequence of trajectories from the training step.

+
+
+
+ +
+ +
+
+class ldp.alg.MeanMetricsCallback(*args, **kwargs)[source]
+

Bases: TrajectoryMetricsCallback

+

Take a mean of all metrics.

+
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+
+property eval_means: dict[str, float]
+
+ +
+
+property train_means: dict[str, float]
+
+ +
+ +
+
+class ldp.alg.OfflineTrainer(config: OfflineTrainerConfig, agent: Agent, optimizer: Optimizer, train_trajectories: list[Trajectory], callbacks: Sequence[Callback] | None = None)[source]
+

Bases: object

+
+
+async train() None[source]
+
+ +
+ +
+
+class ldp.alg.OfflineTrainerConfig(*, batch_size: int, update_every: int = 1, clear_ctx_at_each_iter: bool = False)[source]
+

Bases: BaseModel

+
+
+batch_size: int
+
+ +
+
+clear_ctx_at_each_iter: bool
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=True), 'clear_ctx_at_each_iter': FieldInfo(annotation=bool, required=False, default=False), 'update_every': FieldInfo(annotation=int, required=False, default=1, description='Number of training iterations to run before updating the model.', metadata=[Ge(ge=1)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+update_every: int
+
+ +
+ +
+
+class ldp.alg.OnlineTrainer(config: OnlineTrainerConfig, agent: Agent, optimizer: Optimizer, train_dataset: TaskDataset, eval_dataset: TaskDataset | None = None, callbacks: Sequence[Callback] | None = None)[source]
+

Bases: object

+
+
+async evaluate(**kwargs)
+
+ +
+
+async train() None[source]
+
+ +
+ +
+
+class ldp.alg.OnlineTrainerConfig(*, batch_size: int, num_eval_iterations: int | None = None, max_rollout_steps: int | None = None, catch_agent_failures: bool = True, catch_env_failures: bool = True, clear_ctx_at_each_iter: bool = False, num_train_iterations: int, num_rollouts_per_env: int = 1, update_every: int = 1, eval_every: int | None = None, eval_before: bool = True)[source]
+

Bases: EvaluatorConfig

+
+
+batch_size: int
+
+ +
+
+catch_agent_failures: bool
+
+ +
+
+catch_env_failures: bool
+
+ +
+
+clear_ctx_at_each_iter: bool
+
+ +
+
+eval_before: bool
+
+ +
+
+eval_every: int | None
+
+ +
+
+max_rollout_steps: int | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=True), 'catch_agent_failures': FieldInfo(annotation=bool, required=False, default=True), 'catch_env_failures': FieldInfo(annotation=bool, required=False, default=True), 'clear_ctx_at_each_iter': FieldInfo(annotation=bool, required=False, default=False), 'eval_before': FieldInfo(annotation=bool, required=False, default=True, description='If True (default), evaluate on the validation set before kicking off training.'), 'eval_every': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description='If set, will repeatedly evaluate on the validation set after this many iterations. If unset (default), no evaluation is performed.'), 'max_rollout_steps': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'num_eval_iterations': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description='Number of eval iterations. If not provided, will exhaust the dataset. If 0, will not run the eval loop. '), 'num_rollouts_per_env': FieldInfo(annotation=int, required=False, default=1, description='Number of rollouts to execute for each environment per training iteration.'), 'num_train_iterations': FieldInfo(annotation=int, required=True, description='Number of iterations (at one batch per iteration) to process during training, and setting to 0 skips training.', metadata=[Ge(ge=0)]), 'update_every': FieldInfo(annotation=int, required=False, default=1, description='Number of training iterations between optimizer update calls.', metadata=[Ge(ge=1)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+num_eval_iterations: int | None
+
+ +
+
+num_rollouts_per_env: int
+
+ +
+
+num_train_iterations: int
+
+ +
+
+update_every: int
+
+ +
+ +
+
+class ldp.alg.RolloutDebugDumpCallback(output_dir: PathLike | str)[source]
+

Bases: Callback

+

Dump JSONL files for each agent and environment step to a directory.

+
+
+async after_agent_get_asv(traj_id: str, action: OpResult[ToolRequestMessage], next_agent_state: Any, value: float) None[source]
+

Invoked by runners after agent.get_asv().

+
+ +
+
+async after_env_step(traj_id: str, obs: list[Message], reward: float, done: bool, trunc: bool) None[source]
+

Invoked by runners after env.step().

+
+ +
+
+async before_transition(traj_id: str, agent: Agent, env: Environment, agent_state, obs: list[Message]) None[source]
+

Invoked by runners before each transition and after agent and env reset.

+
+ +
+ +
+
+class ldp.alg.RolloutManager(agent: Agent, catch_agent_failures: bool = True, catch_env_failures: bool = True, callbacks: Sequence[Callback] | None = None, concurrency_limit: int | None = None)[source]
+

Bases: object

+
+
+async sample_trajectories(environment_factory: Callable[[], TEnv], batch_size: int = 1, max_steps: int | None = None) list[tuple[Trajectory, TEnv]][source]
+
+async sample_trajectories(environments: Sequence[Environment], max_steps: int | None = None) list[Trajectory]
+
+ +
+ +
+
+class ldp.alg.TrajectoryFileCallback(output_dir: PathLike | str)[source]
+

Bases: Callback

+

Callback that writes trajectories to a file.

+
+
+async after_transition(traj_id: str, agent: Agent, env: Environment, transition: Transition) None[source]
+

Invoked by runners after each transition.

+
+ +
+
+async before_transition(traj_id: str, agent: Agent, env: Environment, agent_state: Any, obs: list[Message]) None[source]
+

Invoked by runners before each transition and after agent and env reset.

+
+ +
+
+cleanup() None[source]
+
+ +
+ +
+
+class ldp.alg.TrajectoryMetricsCallback(train_dataset: TaskDataset | None = None, eval_dataset: TaskDataset | None = None, track_tool_usage: bool = False)[source]
+

Bases: Callback

+

Compute metrics that are defined by task datasets.

+

NOTE: evaluation portion’s after_eval_step/loop() is not concurrency safe because +trajectories should be stored in the order of after_eval_step() calls.

+
+
+async after_env_reset(traj_id: str, obs: list[Message], tools: list[Tool]) None[source]
+

Invoked by runners after env.reset().

+
+ +
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_eval_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by Evaluator and OnlineTrainer after each evaluation step.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+ +
+
+class ldp.alg.TreeSearchRollout(agent: Agent, branching_factor: int, env_clone_fn: Callable[[TEnv], Awaitable[TEnv]] | Callable[[TEnv], TEnv], catch_agent_failures: bool = True, catch_env_failures: bool = True, callbacks: Sequence[Callback] | None = None, concurrency_limit: int | None = None, target_reward: float | None = None)[source]
+

Bases: RolloutManager

+
+
+async sample_tree(env: TEnv, max_depth: int | None) TransitionTree[source]
+
+ +
+
+async sample_trees(environments: Sequence[TEnv], max_depth: int | None = None) list[TransitionTree][source]
+
+ +
+ +
+
+class ldp.alg.WandBLoggingCallback(*args, **kwargs)[source]
+

Bases: TrajectoryMetricsCallback

+
+
+async after_eval_loop() None[source]
+

Invoked by Evaluator and OnlineTrainer after the evaluation loop.

+
+ +
+
+async after_train_step(trajectories: Sequence[Trajectory]) None[source]
+

Invoked by OnlineTrainer after each training step.

+
+ +
+ +
+
+ldp.alg.to_network(op_result: OpResult, max_label_height: int | None = None, max_label_width: int | None = None, G: MultiDiGraph | None = None) MultiDiGraph[source]
+

Populate a NetworkX graph from the input op result’s computation graph.

+

How to export Graphviz .dot file: nx.drawing.nx_pydot.write_dot(G, “file.dot”) +How to render with Graphviz: nx.drawing.nx_pydot.to_pydot(G).write_png(“file.png”) +Online Graphviz renderer: https://dreampuf.github.io/GraphvizOnline/

+
+
Parameters:
+
    +
  • op_result – Starting op result to recurse parent op calls and results.

  • +
  • max_label_height – Optional max label height (lines).

  • +
  • max_label_width – Optional max label width (chars).

  • +
  • G – Optional graph to add nodes/edges to. Allows this to be a recursive function.

  • +
+
+
Returns:
+

Populated a NetworkX multi-edge directed graph.

+
+
+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ldp.alg.optimizer.html b/docs/_build/html/ldp.alg.optimizer.html new file mode 100644 index 00000000..ba4cb2ad --- /dev/null +++ b/docs/_build/html/ldp.alg.optimizer.html @@ -0,0 +1,968 @@ + + + + + + + + ldp.alg.optimizer package — ldp documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp.alg.optimizer package

+
+

Submodules

+
+
+

ldp.alg.optimizer.ape module

+
+
+class ldp.alg.optimizer.ape.APEOpt(*, max_examples: int | None = 50, system_prompt: str = 'We are optimizing prompts for a language model. The model sees a prompt, an input, and then generates an output.', query_prompt: str = 'Here are correct example outputs that the language model and prompt should produce:\n{good_examples}\n\nThe current prompt is: "{prompt}"\n\nWhich resulted in the following incorrect input, output, and {score}:\n{examples}\n\nRevise the current prompt to improve the outputs. Your proposed prompt should be concise, correct, and specify the desired output format.', llm: LLMModel = None, prompt_op: PromptOp, llm_call_op: LLMCallOp, score_fn: APEScoreFn = APEScoreFn.REWARD, good_reward_threshold: float | None = None, reward_discount: float = 1.0, examples: list[Example] = None, good_examples: list[Example] = None, steps: int = 0, trace: list[str] = None)[source]
+

Bases: BaseModel, Optimizer

+

Basic optimizer that acts as an Automatic Prompt Engineer (APE).

+

Paper: https://openreview.net/pdf?id=92gvk82DE-

+

Details: +- This implements the “forward mode generation” strategy. +- The score function used is the gradient (float) at the output of the

+
+

PromptOp being optimized. A zero gradient means the prompt was “good”, +and a non-zero gradient means we can learn from the prompt.

+
+
    +
  • +
    Possible improvements include:
      +
    • Extending the score function to the LLM result’s logprobs

    • +
    • Iterating with Monte Carlo Search

    • +
    • Use of memory for further example augmentation

    • +
    +
    +
    +
  • +
+
+
+aggregate_trajectory(trajectory: Trajectory) None[source]
+

Aggregate transitions from a single trajectory to construct training samples.

+
+ +
+
+examples: list[Example]
+
+ +
+
+classmethod from_agent(agent: ReActAgent, **kwargs) Self[source]
+
+ +
+
+good_examples: list[Example]
+
+ +
+
+good_reward_threshold: float | None
+
+ +
+
+llm: LLMModel
+
+ +
+
+llm_call_op: LLMCallOp
+
+ +
+
+max_examples: int | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'examples': FieldInfo(annotation=list[Example], required=False, default_factory=list), 'good_examples': FieldInfo(annotation=list[Example], required=False, default_factory=list), 'good_reward_threshold': FieldInfo(annotation=Union[float, NoneType], required=False, default=None, description='If using reward as the score_fn, then a good example is defined by reward>=good_reward_threshold.'), 'llm': FieldInfo(annotation=LLMModel, required=False, default_factory=LLMModel, description='LLM used to update the prompt inside the PromptOp. The paper mentions that larger models produce better prompt proposals.'), 'llm_call_op': FieldInfo(annotation=LLMCallOp, required=True, description='LLMCallOp to be optimized.'), 'max_examples': FieldInfo(annotation=Union[int, NoneType], required=False, default=50, description='Max number of examples to include in the below query_prompt, or None for no limit. The paper mentions that more examples produce better prompt proposals.'), 'prompt_op': FieldInfo(annotation=PromptOp, required=True, description='PromptOp to be optimized.'), 'query_prompt': FieldInfo(annotation=str, required=False, default='Here are correct example outputs that the language model and prompt should produce:\n{good_examples}\n\nThe current prompt is: "{prompt}"\n\nWhich resulted in the following incorrect input, output, and {score}:\n{examples}\n\nRevise the current prompt to improve the outputs. Your proposed prompt should be concise, correct, and specify the desired output format.'), 'reward_discount': FieldInfo(annotation=float, required=False, default=1.0), 'score_fn': FieldInfo(annotation=APEScoreFn, required=False, default=<APEScoreFn.REWARD: 'reward'>), 'steps': FieldInfo(annotation=int, required=False, default=0), 'system_prompt': FieldInfo(annotation=str, required=False, default='We are optimizing prompts for a language model. The model sees a prompt, an input, and then generates an output.'), 'trace': FieldInfo(annotation=list[str], required=False, default_factory=list, description='History of prompts used.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(_APEOpt__context: Any) None[source]
+

Override this method to perform additional initialization after __init__ and model_construct. +This is useful if you want to do some validation that requires the entire model to be initialized.

+
+ +
+
+prompt_op: PromptOp
+
+ +
+
+query_prompt: str
+
+ +
+
+reward_discount: float
+
+ +
+
+score_fn: APEScoreFn
+
+ +
+
+steps: int
+
+ +
+
+system_prompt: str
+
+ +
+
+trace: list[str]
+
+ +
+
+async update() None[source]
+

Update the model based on the aggregated samples.

+
+ +
+
+validate_score_fn()[source]
+
+ +
+ +
+
+class ldp.alg.optimizer.ape.APEScoreFn(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: StrEnum

+
+
+GRADIENT = 'gradient'
+
+ +
+
+REWARD = 'reward'
+
+ +
+ +
+
+class ldp.alg.optimizer.ape.Example(*, input: JsonValue, output: JsonValue, score: float)[source]
+

Bases: BaseModel

+
+
+input: JsonValue
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'input': FieldInfo(annotation=JsonValue, required=True), 'output': FieldInfo(annotation=JsonValue, required=True), 'score': FieldInfo(annotation=float, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+output: JsonValue
+
+ +
+
+score: float
+
+ +
+ +
+
+class ldp.alg.optimizer.ape.OutputPrompt(*, prompt: str)[source]
+

Bases: BaseModel

+
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'prompt': FieldInfo(annotation=str, required=True, description='Prompt for language model')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+prompt: str
+
+ +
+ +
+
+ldp.alg.optimizer.ape.get_formatted_variables(s: str) set[str][source]
+

Returns the set of variables implied by the format string.

+
+ +
+
+

ldp.alg.optimizer.memory module

+
+
+class ldp.alg.optimizer.memory.MemoryFactory(*args, **kwargs)[source]
+

Bases: Protocol

+
+ +
+
+class ldp.alg.optimizer.memory.MemoryOpt(*, memory_op: ~ldp.graph.common_ops.MemoryOp, output_op: ~ldp.graph.ops.Op, reward_discount: float = 1.0, memory_factory: ~ldp.alg.optimizer.memory.MemoryFactory = <function _default_memory_factory>, memory_template: str = 'Input: {input}\nOutput: {output}\nReward: {value}', steps: int = 0, example_buffer: list[tuple[~ldp.graph.op_utils.CallID, ~ldp.graph.op_utils.CallID, float, JsonValue]] = None)[source]
+

Bases: BaseModel, Optimizer

+

Trainer for memory agents. By default it is a minimizer.

+

This optimizer simply adds memories to the MemoryOp using a memory factory.

+
+
+aggregate_trajectory(trajectory: Trajectory) None[source]
+

Aggregate transitions from a single trajectory to construct training samples.

+
+ +
+
+async default_memory_factory(output_op: Op[TOutput], memory_template: str, example_buffer: Iterable[tuple[CallID, CallID, float, JsonValue]]) list[Memory]
+
+ +
+
+example_buffer: list[tuple[CallID, CallID, float, JsonValue]]
+
+ +
+
+classmethod from_agent(agent: MemoryAgent, **kwargs) Self[source]
+
+ +
+
+memory_factory: MemoryFactory
+
+ +
+
+memory_op: MemoryOp
+
+ +
+
+memory_template: str
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'example_buffer': FieldInfo(annotation=list[tuple[CallID, CallID, float, JsonValue]], required=False, default_factory=list), 'memory_factory': FieldInfo(annotation=MemoryFactory, required=False, default=<function _default_memory_factory>, description="Async function to make Memories from an example buffer. It's async so this can involve an LLM completion if desired.", exclude=True), 'memory_op': FieldInfo(annotation=MemoryOp, required=True), 'memory_template': FieldInfo(annotation=str, required=False, default='Input: {input}\nOutput: {output}\nReward: {value}', description="Template for a Memory's string representation."), 'output_op': FieldInfo(annotation=Op, required=True), 'reward_discount': FieldInfo(annotation=float, required=False, default=1.0), 'steps': FieldInfo(annotation=int, required=False, default=0)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+output_op: Op
+
+ +
+
+reward_discount: float
+
+ +
+
+steps: int
+
+ +
+
+async update() None[source]
+

Create new memories from the example buffer and add them to MemoryOp.

+
+ +
+ +
+
+class ldp.alg.optimizer.memory.PositiveMemoryOpt(*, memory_op: ~ldp.graph.common_ops.MemoryOp, output_op: ~ldp.graph.ops.Op, reward_discount: float = 1.0, memory_factory: ~ldp.alg.optimizer.memory.MemoryFactory = <function _default_memory_factory>, memory_template: str = 'Input: {input}\nOutput: {output}\nReward: {value}', steps: int = 0, example_buffer: list[tuple[~ldp.graph.op_utils.CallID, ~ldp.graph.op_utils.CallID, float, JsonValue]] = None)[source]
+

Bases: MemoryOpt

+
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'example_buffer': FieldInfo(annotation=list[tuple[CallID, CallID, float, JsonValue]], required=False, default_factory=list), 'memory_factory': FieldInfo(annotation=MemoryFactory, required=False, default=<function _default_memory_factory>, description="Async function to make Memories from an example buffer. It's async so this can involve an LLM completion if desired.", exclude=True), 'memory_op': FieldInfo(annotation=MemoryOp, required=True), 'memory_template': FieldInfo(annotation=str, required=False, default='Input: {input}\nOutput: {output}\nReward: {value}', description="Template for a Memory's string representation."), 'output_op': FieldInfo(annotation=Op, required=True), 'reward_discount': FieldInfo(annotation=float, required=False, default=1.0), 'steps': FieldInfo(annotation=int, required=False, default=0)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+
+

ldp.alg.optimizer.opt module

+
+
+class ldp.alg.optimizer.opt.ChainedOptimizer(*optimizers: Optimizer)[source]
+

Bases: Optimizer

+

An optimizer that runs a sequence of sub-optimizers in the order they are provided.

+
+
+aggregate(trajectories: Iterable[Trajectory], show_pbar: bool = False) None[source]
+

Aggregate trajectories to construct training samples.

+
+ +
+
+async update() None[source]
+

Update the model based on the aggregated samples.

+
+ +
+ +
+
+class ldp.alg.optimizer.opt.Optimizer[source]
+

Bases: ABC

+

Base class for all optimizers.

+
+
+aggregate(trajectories: Iterable[Trajectory], show_pbar: bool = False) None[source]
+

Aggregate trajectories to construct training samples.

+
+ +
+
+abstract aggregate_trajectory(trajectory: Trajectory) None[source]
+

Aggregate transitions from a single trajectory to construct training samples.

+
+ +
+
+abstract async update() None[source]
+

Update the model based on the aggregated samples.

+
+ +
+ +
+
+

ldp.alg.optimizer.replay_buffers module

+
+
+class ldp.alg.optimizer.replay_buffers.CircularReplayBuffer(initlist=None)[source]
+

Bases: UserList[dict]

+
+
+batched_iter(batch_size: int, shuffle: bool = True, infinite: bool = False)[source]
+
+ +
+
+resize(size: int)[source]
+
+ +
+ +
+
+

Module contents

+
+
+class ldp.alg.optimizer.APEOpt(*, max_examples: int | None = 50, system_prompt: str = 'We are optimizing prompts for a language model. The model sees a prompt, an input, and then generates an output.', query_prompt: str = 'Here are correct example outputs that the language model and prompt should produce:\n{good_examples}\n\nThe current prompt is: "{prompt}"\n\nWhich resulted in the following incorrect input, output, and {score}:\n{examples}\n\nRevise the current prompt to improve the outputs. Your proposed prompt should be concise, correct, and specify the desired output format.', llm: LLMModel = None, prompt_op: PromptOp, llm_call_op: LLMCallOp, score_fn: APEScoreFn = APEScoreFn.REWARD, good_reward_threshold: float | None = None, reward_discount: float = 1.0, examples: list[Example] = None, good_examples: list[Example] = None, steps: int = 0, trace: list[str] = None)[source]
+

Bases: BaseModel, Optimizer

+

Basic optimizer that acts as an Automatic Prompt Engineer (APE).

+

Paper: https://openreview.net/pdf?id=92gvk82DE-

+

Details: +- This implements the “forward mode generation” strategy. +- The score function used is the gradient (float) at the output of the

+
+

PromptOp being optimized. A zero gradient means the prompt was “good”, +and a non-zero gradient means we can learn from the prompt.

+
+
    +
  • +
    Possible improvements include:
      +
    • Extending the score function to the LLM result’s logprobs

    • +
    • Iterating with Monte Carlo Search

    • +
    • Use of memory for further example augmentation

    • +
    +
    +
    +
  • +
+
+
+aggregate_trajectory(trajectory: Trajectory) None[source]
+

Aggregate transitions from a single trajectory to construct training samples.

+
+ +
+
+examples: list[Example]
+
+ +
+
+classmethod from_agent(agent: ReActAgent, **kwargs) Self[source]
+
+ +
+
+good_examples: list[Example]
+
+ +
+
+good_reward_threshold: float | None
+
+ +
+
+llm: LLMModel
+
+ +
+
+llm_call_op: LLMCallOp
+
+ +
+
+max_examples: int | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'examples': FieldInfo(annotation=list[Example], required=False, default_factory=list), 'good_examples': FieldInfo(annotation=list[Example], required=False, default_factory=list), 'good_reward_threshold': FieldInfo(annotation=Union[float, NoneType], required=False, default=None, description='If using reward as the score_fn, then a good example is defined by reward>=good_reward_threshold.'), 'llm': FieldInfo(annotation=LLMModel, required=False, default_factory=LLMModel, description='LLM used to update the prompt inside the PromptOp. The paper mentions that larger models produce better prompt proposals.'), 'llm_call_op': FieldInfo(annotation=LLMCallOp, required=True, description='LLMCallOp to be optimized.'), 'max_examples': FieldInfo(annotation=Union[int, NoneType], required=False, default=50, description='Max number of examples to include in the below query_prompt, or None for no limit. The paper mentions that more examples produce better prompt proposals.'), 'prompt_op': FieldInfo(annotation=PromptOp, required=True, description='PromptOp to be optimized.'), 'query_prompt': FieldInfo(annotation=str, required=False, default='Here are correct example outputs that the language model and prompt should produce:\n{good_examples}\n\nThe current prompt is: "{prompt}"\n\nWhich resulted in the following incorrect input, output, and {score}:\n{examples}\n\nRevise the current prompt to improve the outputs. Your proposed prompt should be concise, correct, and specify the desired output format.'), 'reward_discount': FieldInfo(annotation=float, required=False, default=1.0), 'score_fn': FieldInfo(annotation=APEScoreFn, required=False, default=<APEScoreFn.REWARD: 'reward'>), 'steps': FieldInfo(annotation=int, required=False, default=0), 'system_prompt': FieldInfo(annotation=str, required=False, default='We are optimizing prompts for a language model. The model sees a prompt, an input, and then generates an output.'), 'trace': FieldInfo(annotation=list[str], required=False, default_factory=list, description='History of prompts used.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(_APEOpt__context: Any) None[source]
+

Override this method to perform additional initialization after __init__ and model_construct. +This is useful if you want to do some validation that requires the entire model to be initialized.

+
+ +
+
+prompt_op: PromptOp
+
+ +
+
+query_prompt: str
+
+ +
+
+reward_discount: float
+
+ +
+
+score_fn: APEScoreFn
+
+ +
+
+steps: int
+
+ +
+
+system_prompt: str
+
+ +
+
+trace: list[str]
+
+ +
+
+async update() None[source]
+

Update the model based on the aggregated samples.

+
+ +
+
+validate_score_fn()[source]
+
+ +
+ +
+
+class ldp.alg.optimizer.APEScoreFn(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: StrEnum

+
+
+GRADIENT = 'gradient'
+
+ +
+
+REWARD = 'reward'
+
+ +
+ +
+
+class ldp.alg.optimizer.ChainedOptimizer(*optimizers: Optimizer)[source]
+

Bases: Optimizer

+

An optimizer that runs a sequence of sub-optimizers in the order they are provided.

+
+
+aggregate(trajectories: Iterable[Trajectory], show_pbar: bool = False) None[source]
+

Aggregate trajectories to construct training samples.

+
+ +
+
+async update() None[source]
+

Update the model based on the aggregated samples.

+
+ +
+ +
+
+class ldp.alg.optimizer.MemoryFactory(*args, **kwargs)[source]
+

Bases: Protocol

+
+ +
+
+class ldp.alg.optimizer.MemoryOpt(*, memory_op: ~ldp.graph.common_ops.MemoryOp, output_op: ~ldp.graph.ops.Op, reward_discount: float = 1.0, memory_factory: ~ldp.alg.optimizer.memory.MemoryFactory = <function _default_memory_factory>, memory_template: str = 'Input: {input}\nOutput: {output}\nReward: {value}', steps: int = 0, example_buffer: list[tuple[~ldp.graph.op_utils.CallID, ~ldp.graph.op_utils.CallID, float, JsonValue]] = None)[source]
+

Bases: BaseModel, Optimizer

+

Trainer for memory agents. By default it is a minimizer.

+

This optimizer simply adds memories to the MemoryOp using a memory factory.

+
+
+aggregate_trajectory(trajectory: Trajectory) None[source]
+

Aggregate transitions from a single trajectory to construct training samples.

+
+ +
+
+async default_memory_factory(output_op: Op[TOutput], memory_template: str, example_buffer: Iterable[tuple[CallID, CallID, float, JsonValue]]) list[Memory]
+
+ +
+
+example_buffer: list[tuple[CallID, CallID, float, JsonValue]]
+
+ +
+
+classmethod from_agent(agent: MemoryAgent, **kwargs) Self[source]
+
+ +
+
+memory_factory: MemoryFactory
+
+ +
+
+memory_op: MemoryOp
+
+ +
+
+memory_template: str
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'example_buffer': FieldInfo(annotation=list[tuple[CallID, CallID, float, JsonValue]], required=False, default_factory=list), 'memory_factory': FieldInfo(annotation=MemoryFactory, required=False, default=<function _default_memory_factory>, description="Async function to make Memories from an example buffer. It's async so this can involve an LLM completion if desired.", exclude=True), 'memory_op': FieldInfo(annotation=MemoryOp, required=True), 'memory_template': FieldInfo(annotation=str, required=False, default='Input: {input}\nOutput: {output}\nReward: {value}', description="Template for a Memory's string representation."), 'output_op': FieldInfo(annotation=Op, required=True), 'reward_discount': FieldInfo(annotation=float, required=False, default=1.0), 'steps': FieldInfo(annotation=int, required=False, default=0)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+output_op: Op
+
+ +
+
+reward_discount: float
+
+ +
+
+steps: int
+
+ +
+
+async update() None[source]
+

Create new memories from the example buffer and add them to MemoryOp.

+
+ +
+ +
+
+class ldp.alg.optimizer.Optimizer[source]
+

Bases: ABC

+

Base class for all optimizers.

+
+
+aggregate(trajectories: Iterable[Trajectory], show_pbar: bool = False) None[source]
+

Aggregate trajectories to construct training samples.

+
+ +
+
+abstract aggregate_trajectory(trajectory: Trajectory) None[source]
+

Aggregate transitions from a single trajectory to construct training samples.

+
+ +
+
+abstract async update() None[source]
+

Update the model based on the aggregated samples.

+
+ +
+ +
+
+class ldp.alg.optimizer.OptimizerConfig(*, optimizer_type: str | None = None, optimizer_kwargs: dict[str, Any] = None)[source]
+

Bases: BaseModel

+
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'optimizer_kwargs': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'optimizer_type': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+optimizer_kwargs: dict[str, Any]
+
+ +
+
+optimizer_type: str | None
+
+ +
+ +
+
+class ldp.alg.optimizer.PositiveMemoryOpt(*, memory_op: ~ldp.graph.common_ops.MemoryOp, output_op: ~ldp.graph.ops.Op, reward_discount: float = 1.0, memory_factory: ~ldp.alg.optimizer.memory.MemoryFactory = <function _default_memory_factory>, memory_template: str = 'Input: {input}\nOutput: {output}\nReward: {value}', steps: int = 0, example_buffer: list[tuple[~ldp.graph.op_utils.CallID, ~ldp.graph.op_utils.CallID, float, JsonValue]] = None)[source]
+

Bases: MemoryOpt

+
+
+example_buffer: list[tuple[CallID, CallID, float, JsonValue]]
+
+ +
+
+memory_factory: MemoryFactory
+
+ +
+
+memory_op: MemoryOp
+
+ +
+
+memory_template: str
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'example_buffer': FieldInfo(annotation=list[tuple[CallID, CallID, float, JsonValue]], required=False, default_factory=list), 'memory_factory': FieldInfo(annotation=MemoryFactory, required=False, default=<function _default_memory_factory>, description="Async function to make Memories from an example buffer. It's async so this can involve an LLM completion if desired.", exclude=True), 'memory_op': FieldInfo(annotation=MemoryOp, required=True), 'memory_template': FieldInfo(annotation=str, required=False, default='Input: {input}\nOutput: {output}\nReward: {value}', description="Template for a Memory's string representation."), 'output_op': FieldInfo(annotation=Op, required=True), 'reward_discount': FieldInfo(annotation=float, required=False, default=1.0), 'steps': FieldInfo(annotation=int, required=False, default=0)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+output_op: Op
+
+ +
+
+reward_discount: float
+
+ +
+
+steps: int
+
+ +
+ +
+
+ldp.alg.optimizer.default_optimizer_factory(agent: Agent, optimizer_cls: str | type[Optimizer] | None = None, **optimizer_kwargs) Optimizer[source]
+

A method that constructs a default optimizer for commonly-used agents.

+
+
Parameters:
+
    +
  • agent – Agent to construct the optimizer for.

  • +
  • optimizer_cls – The optimizer class to use. If not specified, we will try a +default based on the provided agent.

  • +
  • optimizer_kwargs – Arguments forwarded to optimizer_cls.

  • +
+
+
Returns:
+

Instantiated optimizer.

+
+
+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ldp.graph.html b/docs/_build/html/ldp.graph.html new file mode 100644 index 00000000..6f382f9d --- /dev/null +++ b/docs/_build/html/ldp.graph.html @@ -0,0 +1,2324 @@ + + + + + + + + ldp.graph package — ldp documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp.graph package

+
+

Subpackages

+ +
+
+

Submodules

+
+
+

ldp.graph.async_torch module

+
+
+class ldp.graph.async_torch.AsyncTorchModule(module: ~torch.nn.modules.module.Module, batch_size: int, max_wait_interval: float, collate_fn: ~collections.abc.Callable = <function default_collate>, decollate_fn: ~collections.abc.Callable = <class 'list'>, module_call_fn: ~collections.abc.Callable = <function AsyncTorchModule.<lambda>>)[source]
+

Bases: AsyncBufferedWorker

+
+ +
+
+ldp.graph.async_torch.async_protect_torch_call(module: ~torch.nn.modules.module.Module, module_call_fn: ~collections.abc.Callable = <function <lambda>>, no_grad: bool = False, autocast_dtype: ~torch.dtype | None = None, autocast_device_type=None) Callable[source]
+
+ +
+
+

ldp.graph.common_ops module

+

This module contains commonly-used Op implementations.

+
+
+class ldp.graph.common_ops.Cacheable(co: Awaitable[TResult])[source]
+

Bases: Generic[TResult]

+
+
+async get_result() TResult | None[source]
+
+ +
+ +
+
+class ldp.graph.common_ops.ConfigOp(*args, **kwargs)[source]
+

Bases: Op[TConfig], Generic[TConfig]

+

An operation that contains a configuration object.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward() TConfig[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.common_ops.EmbeddingOp(*args, **kwargs)[source]
+

Bases: Op

+

A general operation for embedding text using LiteLLM.

+
+
+classmethod backward(ctx: OpCtx, input_args, input_kwargs, grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(string_input: str) ndarray[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.common_ops.FxnOp(*args, **kwargs)[source]
+

Bases: Op[TOutput]

+

Wrap a function for a straight through gradient approximation for all args/kwargs.

+

Basically, consider the fxn as a transform upon the inputs during the forward pass, +and propagating the same gradient for all inputs during the backward pass.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(*args, **kwargs) TOutput[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.common_ops.IdentityOp(*args, **kwargs)[source]
+

Bases: Op[TOutput]

+

An operation that simply returns the input value.

+

NOTE: this op is equivalent to FxnOp(lambda x: x).

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(value: TOutput) TOutput[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.common_ops.LLMCallOp(*args, **kwargs)[source]
+

Bases: Op[Message]

+

An operation for LLM calls interaction.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async compute_logprob(raw_log_p: float | None, temperature: float, model: LLMModel, **model_kwargs) float | None[source]
+

This method computes a Monte Carlo estimate of logprob for a given temperature.

+

It takes as input the logprob at T=1. The derivation is in Section 5.1 of the Aviary notes.

+
+ +
+
+async forward(config: dict, msgs: list[Message], tools: list[Tool] = None, tool_choice: Tool | str | None = LLMModel.TOOL_CHOICE_REQUIRED) ToolRequestMessage[source]
+
+async forward(config: dict, msgs: list[Message], tools: None = None, tool_choice: str | None = LLMModel.TOOL_CHOICE_REQUIRED) Message
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+
+get_examples() list[tuple[LLMResult, float]][source]
+
+ +
+ +
+
+class ldp.graph.common_ops.MemoryOp(*args, **kwargs)[source]
+

Bases: Op[list[Memory]]

+

An operation for managing memory retrieval and storage.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass for memory retrieval - goes back to item.

+
+ +
+
+async forward(query: str, input: str | None = None, matches: int = 3) list[Memory][source]
+

Retrieve relevant memories based on a query.

+
+ +
+ +
+
+class ldp.graph.common_ops.PromptOp(*args, **kwargs)[source]
+

Bases: FxnOp[str]

+

An operation that formats kwargs into a prompt string.

+
+ +
+
+class ldp.graph.common_ops.StopGradOp(*args, **kwargs)[source]
+

Bases: IdentityOp[TOutput]

+

Pass through Op that terminates gradients in the backward pass.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+ +
+
+ldp.graph.common_ops.async_cache(func)[source]
+
+ +
+
+ldp.graph.common_ops.logsumexp(a: ndarray | list[float]) float[source]
+
+ +
+
+

ldp.graph.gradient_estimators module

+

This module defines various gradient estimators that can be patched in during backward passes.

+
+
+class ldp.graph.gradient_estimators.TorchParamBackwardEstimator(module: Module)[source]
+

Bases: object

+

Gradient estimator for TorchOp internal parameters.

+

This estimator computes gradients with respect to the internal parameters of a +torch.nn.Module by calling the backward method of the estimator instead of the default +backward method of TorchOp. Computed gradients are stored in the context of the operation +under the key “grad_params”.

+

Examples

+
>>> torch_module = torch.nn.Sequential(
+...     torch.nn.Linear(4, 4),
+...     torch.nn.Linear(4, 1),
+... )
+>>> torch_op = TorchOp(torch_module)
+>>> estimator = TorchParamBackwardEstimator(torch_module)
+>>> result = await torch_op(torch.randn(4, requires_grad=True))
+>>> result.compute_grads(backward_fns={"TorchOp": estimator.backward})
+
+
+
+

Note

+

This estimator is only compatible with TorchOp operations.

+
+
+
+backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+
+ +
+ +
+
+ldp.graph.gradient_estimators.assign_constant_grads(input_args: list[OpResult[TOutput] | TOutput], input_kwargs: dict[str, OpResult[TOutput] | TOutput], value: Any, descend: bool = True)[source]
+
+ +
+
+ldp.graph.gradient_estimators.assign_default_grads(input_grads: GradInType, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], default_grad_val: float = 0.0) GradInType[source]
+

Sets a default value of default_grad_val for every element in input_grads.

+

Example: +- input_kwargs = {“a”: {“b”: 1, “c”: 2}}, +- input_grad_kwargs = {“a”: {“b”: 0.1}} +Output: input_grads[1] = {“a”: {“b”: 0.1, “c”: default_grad_val}}

+
+
Returns:
+

+
A tuple containing the updated input_grad_args and

input_grad_kwargs with default values assigned where necessary.

+
+
+

+
+
Return type:
+

GradInType

+
+
+
+ +
+
+ldp.graph.gradient_estimators.llm_straight_through_estimator(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Straight-through for an LLM: descend into the config, but not msgs/tools/tool_calls.

+

See LLMCallOp.backward() for more details on this choice. +Don’t bother checking that input_args/input_kwargs have the right structure, +since compute_grads() will raise if not.

+
+ +
+
+ldp.graph.gradient_estimators.stop_grad(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+
+ +
+
+ldp.graph.gradient_estimators.straight_through_estimator(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID, descend: bool = True) GradInType[source]
+
+ +
+
+ldp.graph.gradient_estimators.zero_estimator(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Sets the gradient of all inputs to zero.

+

Note that this is not the same as truncating the compute graph (stop_grad), +since upstream nodes can still optimize their logprobs. The zero estimator +the unbiased choice if we have no information about the gradient.

+
+ +
+
+

ldp.graph.loss_ops module

+

This module contains loss Op implementations.

+
+
+class ldp.graph.loss_ops.MSELossOp(*args, **kwargs)[source]
+

Bases: Op

+
+
+classmethod backward(ctx: OpCtx, input_args, input_kwargs, grad_output: Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V, call_id: CallID) tuple[Sequence[Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V | None], Mapping[str, Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V | None]][source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(prediction: npt.NDArray | torch.Tensor, target: npt.NDArray | torch.Tensor) float | torch.Tensor[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+

ldp.graph.memory module

+
+
+class ldp.graph.memory.Memory(*, query: str, input: str | None = None, output: str, value: float | str, metadata: JsonValue = None, run_id: UUID | None = None, template: str = 'Input: {input}\nOutput: {output}\nValue: {value}')[source]
+

Bases: BaseModel

+

A single memory about an input, output, and value tuple.

+

A memory is a record of an input, output, and resulting value. Typically used +for prompting a language model. Or, it could be about a whole forward pass where +the input is the observation and the output is the action taken. +The query is optionally different and used for +retrieving the memory. For example, it could be much larger because it won’t +be formatted in the resulting prompt.

+
+
+classmethod ensure_query(data: Any) Any[source]
+

Copy input to match the query if input is None.

+
+ +
+
+classmethod from_ops(mem_op: MemoryOp, mem_call_id: CallID, output_op: Op[TOutput], output_call_id: CallID, value: float, **kwargs) Self[source]
+

Create from a MemoryOp, output Op, and their call IDs.

+
+ +
+
+input: str | None
+
+ +
+
+metadata: JsonValue
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'input': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Some input (e.g. prompt to LLM, observation). If None (default), the input is set to match the query.'), 'metadata': FieldInfo(annotation=JsonValue, required=False, default_factory=dict, description='Optional JSON metadata to store with the memory. An example is storing information an optimizer can use at training time.'), 'output': FieldInfo(annotation=str, required=True, description='Some output (e.g. tool selection).'), 'query': FieldInfo(annotation=str, required=True, description='String to be embedded into a retrieval key for a memory index.'), 'run_id': FieldInfo(annotation=Union[UUID, NoneType], required=False, default=None, description='Associate run_id for debugging purposes to trace which forward pass generated the memory.'), 'template': FieldInfo(annotation=str, required=False, default='Input: {input}\nOutput: {output}\nValue: {value}'), 'value': FieldInfo(annotation=Union[float, str], required=True, description="Measure of the output's quality (e.g. loss).")}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+output: str
+
+ +
+
+query: str
+
+ +
+
+run_id: UUID | None
+
+ +
+
+template: str
+
+ +
+
+value: float | str
+
+ +
+ +
+
+class ldp.graph.memory.MemoryModel(*, embedding_model: EmbeddingModel = None, memories: dict[int, Memory] = None)[source]
+

Bases: BaseModel, Generic[TIndex], ABC

+

A collection of memories with retrieval.

+
+
+DEFAULT_MEMORY_MATCHES: ClassVar[int] = 3
+
+ +
+
+async add_memory(memory: Memory) None[source]
+
+ +
+
+embedding_model: EmbeddingModel
+
+ +
+
+classmethod enforce_empty(v: dict) dict[source]
+
+ +
+
+async get_memory(query: str, matches: int = 3) list[Memory][source]
+
+ +
+
+memories: dict[int, Memory]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'embedding_model': FieldInfo(annotation=EmbeddingModel, required=False, default_factory=<lambda>), 'memories': FieldInfo(annotation=dict[int, Memory], required=False, default_factory=dict)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(context: Any, /) None
+

This function is meant to behave like a BaseModel method to initialise private attributes.

+

It takes context as an argument since that’s what pydantic-core passes when calling it.

+
+
Parameters:
+
    +
  • self – The BaseModel instance.

  • +
  • context – The context.

  • +
+
+
+
+ +
+
+safe_access_index() AsyncIterator[TIndex][source]
+

Get the internal Index under the protection of an internal Lock.

+
+ +
+ +
+
+class ldp.graph.memory.MemoryModel(*, embedding_model: EmbeddingModel = None, memories: dict[int, Memory] = None)[source]
+

Bases: BaseModel, Generic[TIndex], ABC

+

A collection of memories with retrieval.

+
+
+DEFAULT_MEMORY_MATCHES: ClassVar[int] = 3
+
+ +
+
+async add_memory(memory: Memory) None[source]
+
+ +
+
+embedding_model: EmbeddingModel
+
+ +
+
+classmethod enforce_empty(v: dict) dict[source]
+
+ +
+
+async get_memory(query: str, matches: int = 3) list[Memory][source]
+
+ +
+
+memories: dict[int, Memory]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'embedding_model': FieldInfo(annotation=EmbeddingModel, required=False, default_factory=<lambda>), 'memories': FieldInfo(annotation=dict[int, Memory], required=False, default_factory=dict)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(context: Any, /) None
+

This function is meant to behave like a BaseModel method to initialise private attributes.

+

It takes context as an argument since that’s what pydantic-core passes when calling it.

+
+
Parameters:
+
    +
  • self – The BaseModel instance.

  • +
  • context – The context.

  • +
+
+
+
+ +
+
+safe_access_index() AsyncIterator[TIndex][source]
+

Get the internal Index under the protection of an internal Lock.

+
+ +
+ +
+
+class ldp.graph.memory.UIndexMemoryModel(*, embedding_model: EmbeddingModel = None, memories: dict[int, Memory] = None)[source]
+

Bases: MemoryModel[Index]

+

Memory model using a U-Search index.

+
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'embedding_model': FieldInfo(annotation=EmbeddingModel, required=False, default_factory=<lambda>), 'memories': FieldInfo(annotation=dict[int, Memory], required=False, default_factory=dict)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(context: Any, /) None
+

We need to both initialize private attributes and call the user-defined model_post_init +method.

+
+ +
+ +
+
+

ldp.graph.op_utils module

+
+
+class ldp.graph.op_utils.CallID(run_id: str | UUID, fwd_id: str | UUID)[source]
+

Bases: BaseModel

+
+
+fwd_id: UUID
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'fwd_id': FieldInfo(annotation=UUID, required=True), 'run_id': FieldInfo(annotation=UUID, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+run_id: UUID
+
+ +
+
+serialize_uuid(value: UUID) str[source]
+
+ +
+
+classmethod validate_uuid(value: UUID | str) UUID[source]
+
+ +
+ +
+
+ldp.graph.op_utils.compute_graph() AsyncIterator[UUID][source]
+

Initialize a compute graph by setting a run ID.

+

If a run ID is already set (i.e. we are already inside a +get_run_id() context), then the existing run ID is returned. +Otherwise, a new UUID is created.

+
+ +
+
+ldp.graph.op_utils.get_call_id() CallID[source]
+

Get the current call ID.

+
+ +
+
+ldp.graph.op_utils.get_run_id() UUID[source]
+

Get the current run ID.

+
+ +
+
+ldp.graph.op_utils.get_training_mode() bool[source]
+

Get the current training mode.

+
+ +
+
+ldp.graph.op_utils.op_call() AsyncIterator[CallID][source]
+

Decorate an op call with a call ID.

+

If a call ID is already set (i.e. we are already inside an op call), +then the existing call ID is returned. +Otherwise, a new UUID is created.

+
+ +
+
+ldp.graph.op_utils.set_training_mode(training_mode: bool) None[source]
+

Set the training mode.

+
+ +
+
+

ldp.graph.ops module

+

This module defines the Op class and its helper classes.

+
+
+class ldp.graph.ops.Op(*args, **kwargs)[source]
+

Bases: ABC, Generic[TOutput]

+

An operation that is ‘differentiable’ and can be used in an optimizer.

+

Think torch.autograd.Function that can also be applied to non-differentiable +operations like prompt template formatting or Python function calls.

+

These form a forward computation graph when composed with other Ops via +__call__. In training mode, this graph is constructed dynamically.

+
+
+abstract classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs, grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+clear_ctx() None[source]
+
+ +
+
+ctx: OpCtx
+
+ +
+
+abstract async forward(*args, **kwargs) TOutput[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+
+get_call_ids(run_ids: Collection[UUID] | None = None) set[CallID][source]
+
+ +
+
+get_input_grads(call_id: CallID) GradInType[source]
+
+ +
+
+name: str
+
+ +
+
+set_name(name: str) None[source]
+
+ +
+ +
+
+class ldp.graph.ops.OpCtx(*, op_name: str, data: dict = None)[source]
+

Bases: BaseModel

+
+
+classmethod clear_contexts(op_names: Iterable[str] | None = None) None[source]
+

Clear the data in all contexts. If op_names is provided, only clear those contexts.

+
+ +
+
+data: dict
+
+ +
+
+get(call_id: ~ldp.graph.op_utils.CallID, key: str, default: ~typing.Any = <object object>) Any[source]
+

Get an attribute with an optional default, emulating dict.get.

+
+ +
+
+get_input_grads(call_id: CallID) GradInType[source]
+
+ +
+
+classmethod get_or_create(op_name: str) OpCtx[source]
+

Return an OpCtx corresponding to the Op with the given name.

+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'data': FieldInfo(annotation=dict, required=False, default_factory=<lambda>, description='Maps run_id -> (fwd_id, key) -> value. data is excluded from model_dump() etc because we do not use Pydantic to persist context information. That should be done via the DB backend instead. OpCtx will serialize op_name, which is enough to rehydrate from the DB.', exclude=True), 'op_name': FieldInfo(annotation=str, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(context: Any, /) None
+

This function is meant to behave like a BaseModel method to initialise private attributes.

+

It takes context as an argument since that’s what pydantic-core passes when calling it.

+
+
Parameters:
+
    +
  • self – The BaseModel instance.

  • +
  • context – The context.

  • +
+
+
+
+ +
+
+op_name: str
+
+ +
+
+update(call_id: CallID, key: str, value: Any)[source]
+
+ +
+ +
+
+class ldp.graph.ops.OpResult(call_id: CallID | Any, op_name: str, op_class_name: str, value: TOutput)[source]
+

Bases: Generic[TOutput]

+

Result of a forward pass, used in the compute graph.

+
+
+compute_grads(grad_output: tree.Structure | None = None, backward_fns: Mapping[str | type, BackwardsType] | None = None) None[source]
+

Compute the gradient of the backward graph in-place.

+

This executes topological traversal. +It is up to the Op to:

+
+
    +
  1. define the backward computation

  2. +
  3. store internal gradients for optimizer updates.

  4. +
+
+
+ +
+
+property ctx: OpCtx
+
+ +
+
+classmethod from_dict(t_output: type[TOutput], dump: dict[str, Any]) OpResult[TOutput][source]
+
+ +
+
+get_compute_graph(backward: bool = True) DiGraph[source]
+

Construct a directed graph of the compute graph that led to this OpResult.

+
+
Parameters:
+

backward – If True (default), constructs the backwards graph in which outputs +point to inputs. If False, constructs the forward call graph. +For most cases (e.g. backprop), backward=True is desirable.

+
+
Returns:
+

A digraph in which nodes are OpResults.

+
+
+
+ +
+
+property grad: tree.Structure | None
+

Returns d ln(P_{compute_graph}) / d self or None if gradients have not been computed.

+
+ +
+
+property inputs: tuple[list[OpResult[TOutput] | TOutput], dict[str, OpResult[TOutput] | TOutput]]
+
+ +
+
+property logprob: float | None
+
+ +
+
+property op_class: type[Op]
+
+ +
+
+property run_id: UUID
+
+ +
+
+to_dict() dict[str, Any][source]
+
+ +
+
+traverse(topological_order: bool = True, filter_fn: ~collections.abc.Callable[[~ldp.graph.ops.OpResult], bool] = <function OpResult.<lambda>>) Iterator[OpResult][source]
+

Traverse the compute graph that led to this OpResult.

+
+
Parameters:
+
    +
  • topological_order – If True, traverse the backwards graph in topological +order. This requires having the whole graph in memory. If False, +traverse the backwards graph in depth-first order. This can be done +lazily and is useful if we are trying to hydrate the graph node-by-node. +Most user-facing cases can leave this as True. Defaults to True.

  • +
  • filter_fn – Will only yield nodes that pass this filter function. Note that +nodes that fail will still be traversed.

  • +
+
+
Yields:
+

An iterator over the nodes of this graph.

+
+
+
+ +
+
+static unwrap_value(result: OpResult[TOutput] | TOutput) TOutput[source]
+
+ +
+ +
+
+ldp.graph.ops.resolve_fully_qualified_name(cls: type) str[source]
+
+ +
+
+

ldp.graph.torch_ops module

+
+
+class ldp.graph.torch_ops.TorchOp(*args, **kwargs)[source]
+

Bases: Op[Tensor]

+

An operation that wraps a PyTorch module.

+
+
+CTX_TENSOR_INPUT_KEY: ClassVar[str] = 'tensor_input'
+
+ +
+
+classmethod backward(ctx: OpCtx, input_args: list[OpResult[TOutput] | TOutput], input_kwargs: dict[str, OpResult[TOutput] | TOutput], grad_output: float | Tensor, call_id: CallID) tuple[Sequence[Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V | None], Mapping[str, Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V | None]][source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(*args, **kwargs: Any) Tensor[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+ldp.graph.torch_ops.store_tensor_inputs(ctx: OpCtx, key: str, tensor_args: Sequence[Tensor], tensor_kwargs: Mapping[str, Tensor], fwd_args: Sequence[Parameter], detach: bool = False) None[source]
+
+ +
+
+

Module contents

+
+
+class ldp.graph.CallID(run_id: str | UUID, fwd_id: str | UUID)[source]
+

Bases: BaseModel

+
+
+fwd_id: UUID
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'fwd_id': FieldInfo(annotation=UUID, required=True), 'run_id': FieldInfo(annotation=UUID, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+run_id: UUID
+
+ +
+
+serialize_uuid(value: UUID) str[source]
+
+ +
+
+classmethod validate_uuid(value: UUID | str) UUID[source]
+
+ +
+ +
+
+class ldp.graph.ConfigOp(*args, **kwargs)[source]
+

Bases: Op[TConfig], Generic[TConfig]

+

An operation that contains a configuration object.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward() TConfig[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.EmbeddingOp(*args, **kwargs)[source]
+

Bases: Op

+

A general operation for embedding text using LiteLLM.

+
+
+classmethod backward(ctx: OpCtx, input_args, input_kwargs, grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(string_input: str) ndarray[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.FxnOp(*args, **kwargs)[source]
+

Bases: Op[TOutput]

+

Wrap a function for a straight through gradient approximation for all args/kwargs.

+

Basically, consider the fxn as a transform upon the inputs during the forward pass, +and propagating the same gradient for all inputs during the backward pass.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(*args, **kwargs) TOutput[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.IdentityOp(*args, **kwargs)[source]
+

Bases: Op[TOutput]

+

An operation that simply returns the input value.

+

NOTE: this op is equivalent to FxnOp(lambda x: x).

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(value: TOutput) TOutput[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.LLMCallOp(*args, **kwargs)[source]
+

Bases: Op[Message]

+

An operation for LLM calls interaction.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async compute_logprob(raw_log_p: float | None, temperature: float, model: LLMModel, **model_kwargs) float | None[source]
+

This method computes a Monte Carlo estimate of logprob for a given temperature.

+

It takes as input the logprob at T=1. The derivation is in Section 5.1 of the Aviary notes.

+
+ +
+
+async forward(config: dict, msgs: list[Message], tools: list[Tool] = None, tool_choice: Tool | str | None = LLMModel.TOOL_CHOICE_REQUIRED) ToolRequestMessage[source]
+
+async forward(config: dict, msgs: list[Message], tools: None = None, tool_choice: str | None = LLMModel.TOOL_CHOICE_REQUIRED) Message
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+
+get_examples() list[tuple[LLMResult, float]][source]
+
+ +
+ +
+
+class ldp.graph.MSELossOp(*args, **kwargs)[source]
+

Bases: Op

+
+
+classmethod backward(ctx: OpCtx, input_args, input_kwargs, grad_output: Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V, call_id: CallID) tuple[Sequence[Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V | None], Mapping[str, Sequence[StructureKV[K, V]] | Mapping[str, StructureKV[K, V]] | V | None]][source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+async forward(prediction: npt.NDArray | torch.Tensor, target: npt.NDArray | torch.Tensor) float | torch.Tensor[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+ +
+
+class ldp.graph.Memory(*, query: str, input: str | None = None, output: str, value: float | str, metadata: JsonValue = None, run_id: UUID | None = None, template: str = 'Input: {input}\nOutput: {output}\nValue: {value}')[source]
+

Bases: BaseModel

+

A single memory about an input, output, and value tuple.

+

A memory is a record of an input, output, and resulting value. Typically used +for prompting a language model. Or, it could be about a whole forward pass where +the input is the observation and the output is the action taken. +The query is optionally different and used for +retrieving the memory. For example, it could be much larger because it won’t +be formatted in the resulting prompt.

+
+
+classmethod ensure_query(data: Any) Any[source]
+

Copy input to match the query if input is None.

+
+ +
+
+classmethod from_ops(mem_op: MemoryOp, mem_call_id: CallID, output_op: Op[TOutput], output_call_id: CallID, value: float, **kwargs) Self[source]
+

Create from a MemoryOp, output Op, and their call IDs.

+
+ +
+
+input: str | None
+
+ +
+
+metadata: JsonValue
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'input': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Some input (e.g. prompt to LLM, observation). If None (default), the input is set to match the query.'), 'metadata': FieldInfo(annotation=JsonValue, required=False, default_factory=dict, description='Optional JSON metadata to store with the memory. An example is storing information an optimizer can use at training time.'), 'output': FieldInfo(annotation=str, required=True, description='Some output (e.g. tool selection).'), 'query': FieldInfo(annotation=str, required=True, description='String to be embedded into a retrieval key for a memory index.'), 'run_id': FieldInfo(annotation=Union[UUID, NoneType], required=False, default=None, description='Associate run_id for debugging purposes to trace which forward pass generated the memory.'), 'template': FieldInfo(annotation=str, required=False, default='Input: {input}\nOutput: {output}\nValue: {value}'), 'value': FieldInfo(annotation=Union[float, str], required=True, description="Measure of the output's quality (e.g. loss).")}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+output: str
+
+ +
+
+query: str
+
+ +
+
+run_id: UUID | None
+
+ +
+
+template: str
+
+ +
+
+value: float | str
+
+ +
+ +
+
+class ldp.graph.MemoryModel(*, embedding_model: EmbeddingModel = None, memories: dict[int, Memory] = None)[source]
+

Bases: BaseModel, Generic[TIndex], ABC

+

A collection of memories with retrieval.

+
+
+DEFAULT_MEMORY_MATCHES: ClassVar[int] = 3
+
+ +
+
+async add_memory(memory: Memory) None[source]
+
+ +
+
+embedding_model: EmbeddingModel
+
+ +
+
+classmethod enforce_empty(v: dict) dict[source]
+
+ +
+
+async get_memory(query: str, matches: int = 3) list[Memory][source]
+
+ +
+
+memories: dict[int, Memory]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'embedding_model': FieldInfo(annotation=EmbeddingModel, required=False, default_factory=<lambda>), 'memories': FieldInfo(annotation=dict[int, Memory], required=False, default_factory=dict)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(context: Any, /) None
+

This function is meant to behave like a BaseModel method to initialise private attributes.

+

It takes context as an argument since that’s what pydantic-core passes when calling it.

+
+
Parameters:
+
    +
  • self – The BaseModel instance.

  • +
  • context – The context.

  • +
+
+
+
+ +
+
+safe_access_index() AsyncIterator[TIndex][source]
+

Get the internal Index under the protection of an internal Lock.

+
+ +
+ +
+
+class ldp.graph.MemoryOp(*args, **kwargs)[source]
+

Bases: Op[list[Memory]]

+

An operation for managing memory retrieval and storage.

+
+
+classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs: dict[str, ResultOrValue], grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass for memory retrieval - goes back to item.

+
+ +
+
+async forward(query: str, input: str | None = None, matches: int = 3) list[Memory][source]
+

Retrieve relevant memories based on a query.

+
+ +
+ +
+
+class ldp.graph.Op(*args, **kwargs)[source]
+

Bases: ABC, Generic[TOutput]

+

An operation that is ‘differentiable’ and can be used in an optimizer.

+

Think torch.autograd.Function that can also be applied to non-differentiable +operations like prompt template formatting or Python function calls.

+

These form a forward computation graph when composed with other Ops via +__call__. In training mode, this graph is constructed dynamically.

+
+
+abstract classmethod backward(ctx: OpCtx, input_args: list[ResultOrValue], input_kwargs, grad_output: tree.Structure, call_id: CallID) GradInType[source]
+

Backward pass of the Op.

+
+
Parameters:
+
    +
  • ctx – Context that was used during the forward pass.

  • +
  • input_args – Variable-length input arguments passed to forward, i.e. +via *args.

  • +
  • input_kwargs – All other arguments passed to forward pass.

  • +
  • grad_output – A list of backpropagated gradients from each consumer +of the output of the forward pass. It is up to the implementation +to decide how to aggregate these gradients (e.g. in most cases summing).

  • +
  • call_id – Call ID of the forward pass.

  • +
+
+
Returns:
+

+
d log(p) / d input for each input to the forward pass.

It should include gradients for all input positional and keyword +arguments. Set to None for gradients that should terminate.

+
+
+

+
+
Return type:
+

grad_input

+
+
+
+ +
+
+clear_ctx() None[source]
+
+ +
+
+ctx: OpCtx
+
+ +
+
+abstract async forward(*args, **kwargs) TOutput[source]
+

Forward pass of the Op. Must accept call_id as an argument.

+
+
Returns:
+

+
Depending on this Op’s purpose, the return may be considered an action

(e.g. a tool call) or it may not (e.g. a loss calculation).

+
+
+

+
+
+
+ +
+
+get_call_ids(run_ids: Collection[UUID] | None = None) set[CallID][source]
+
+ +
+
+get_input_grads(call_id: CallID) GradInType[source]
+
+ +
+
+name: str
+
+ +
+
+set_name(name: str) None[source]
+
+ +
+ +
+
+class ldp.graph.OpCtx(*, op_name: str, data: dict = None)[source]
+

Bases: BaseModel

+
+
+classmethod clear_contexts(op_names: Iterable[str] | None = None) None[source]
+

Clear the data in all contexts. If op_names is provided, only clear those contexts.

+
+ +
+
+data: dict
+
+ +
+
+get(call_id: ~ldp.graph.op_utils.CallID, key: str, default: ~typing.Any = <object object>) Any[source]
+

Get an attribute with an optional default, emulating dict.get.

+
+ +
+
+get_input_grads(call_id: CallID) GradInType[source]
+
+ +
+
+classmethod get_or_create(op_name: str) OpCtx[source]
+

Return an OpCtx corresponding to the Op with the given name.

+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'data': FieldInfo(annotation=dict, required=False, default_factory=<lambda>, description='Maps run_id -> (fwd_id, key) -> value. data is excluded from model_dump() etc because we do not use Pydantic to persist context information. That should be done via the DB backend instead. OpCtx will serialize op_name, which is enough to rehydrate from the DB.', exclude=True), 'op_name': FieldInfo(annotation=str, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+model_post_init(context: Any, /) None
+

This function is meant to behave like a BaseModel method to initialise private attributes.

+

It takes context as an argument since that’s what pydantic-core passes when calling it.

+
+
Parameters:
+
    +
  • self – The BaseModel instance.

  • +
  • context – The context.

  • +
+
+
+
+ +
+
+op_name: str
+
+ +
+
+update(call_id: CallID, key: str, value: Any)[source]
+
+ +
+ +
+
+class ldp.graph.OpResult(call_id: CallID | Any, op_name: str, op_class_name: str, value: TOutput)[source]
+

Bases: Generic[TOutput]

+

Result of a forward pass, used in the compute graph.

+
+
+compute_grads(grad_output: tree.Structure | None = None, backward_fns: Mapping[str | type, BackwardsType] | None = None) None[source]
+

Compute the gradient of the backward graph in-place.

+

This executes topological traversal. +It is up to the Op to:

+
+
    +
  1. define the backward computation

  2. +
  3. store internal gradients for optimizer updates.

  4. +
+
+
+ +
+
+property ctx: OpCtx
+
+ +
+
+classmethod from_dict(t_output: type[TOutput], dump: dict[str, Any]) OpResult[TOutput][source]
+
+ +
+
+get_compute_graph(backward: bool = True) DiGraph[source]
+

Construct a directed graph of the compute graph that led to this OpResult.

+
+
Parameters:
+

backward – If True (default), constructs the backwards graph in which outputs +point to inputs. If False, constructs the forward call graph. +For most cases (e.g. backprop), backward=True is desirable.

+
+
Returns:
+

A digraph in which nodes are OpResults.

+
+
+
+ +
+
+property grad: tree.Structure | None
+

Returns d ln(P_{compute_graph}) / d self or None if gradients have not been computed.

+
+ +
+
+property inputs: tuple[list[OpResult[TOutput] | TOutput], dict[str, OpResult[TOutput] | TOutput]]
+
+ +
+
+property logprob: float | None
+
+ +
+
+property op_class: type[Op]
+
+ +
+
+property run_id: UUID
+
+ +
+
+to_dict() dict[str, Any][source]
+
+ +
+
+traverse(topological_order: bool = True, filter_fn: ~collections.abc.Callable[[~ldp.graph.ops.OpResult], bool] = <function OpResult.<lambda>>) Iterator[OpResult][source]
+

Traverse the compute graph that led to this OpResult.

+
+
Parameters:
+
    +
  • topological_order – If True, traverse the backwards graph in topological +order. This requires having the whole graph in memory. If False, +traverse the backwards graph in depth-first order. This can be done +lazily and is useful if we are trying to hydrate the graph node-by-node. +Most user-facing cases can leave this as True. Defaults to True.

  • +
  • filter_fn – Will only yield nodes that pass this filter function. Note that +nodes that fail will still be traversed.

  • +
+
+
Yields:
+

An iterator over the nodes of this graph.

+
+
+
+ +
+
+static unwrap_value(result: OpResult[TOutput] | TOutput) TOutput[source]
+
+ +
+ +
+
+class ldp.graph.PromptOp(*args, **kwargs)[source]
+

Bases: FxnOp[str]

+

An operation that formats kwargs into a prompt string.

+
+ +
+
+ldp.graph.compute_graph() AsyncIterator[UUID][source]
+

Initialize a compute graph by setting a run ID.

+

If a run ID is already set (i.e. we are already inside a +get_run_id() context), then the existing run ID is returned. +Otherwise, a new UUID is created.

+
+ +
+
+ldp.graph.get_call_id() CallID[source]
+

Get the current call ID.

+
+ +
+
+ldp.graph.get_run_id() UUID[source]
+

Get the current run ID.

+
+ +
+
+ldp.graph.get_training_mode() bool[source]
+

Get the current training mode.

+
+ +
+
+ldp.graph.op_call() AsyncIterator[CallID][source]
+

Decorate an op call with a call ID.

+

If a call ID is already set (i.e. we are already inside an op call), +then the existing call ID is returned. +Otherwise, a new UUID is created.

+
+ +
+
+ldp.graph.set_training_mode(training_mode: bool) None[source]
+

Set the training mode.

+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ldp.graph.modules.html b/docs/_build/html/ldp.graph.modules.html new file mode 100644 index 00000000..da4bbe4d --- /dev/null +++ b/docs/_build/html/ldp.graph.modules.html @@ -0,0 +1,430 @@ + + + + + + + + ldp.graph.modules package — ldp documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp.graph.modules package

+
+

Submodules

+
+
+

ldp.graph.modules.llm_call module

+
+
+class ldp.graph.modules.llm_call.ParsedLLMCallModule(llm_model: dict[str, Any], parser: Callable[[...], TParsedMessage])[source]
+

Bases: Generic[TParsedMessage]

+

Module for a processing-based tool selection, with a learnable configuration.

+
+ +
+
+

ldp.graph.modules.react module

+
+
+class ldp.graph.modules.react.ReActModule(llm_model: dict[str, Any], sys_prompt: str = 'Answer the following questions as best you can. You have access to the following tools:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: comma separated list of inputs to action as python tuple\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\n\nExample:\n\nThought: I need to use the get_weather tool\nAction: get_weather\nAction Input: "New York", 7\nObservation: The 7 day forecast for New York is [...]', tool_description_method: ToolDescriptionMethods = ToolDescriptionMethods.STR)[source]
+

Bases: object

+

An Act or ReAct module built to work with chat models.

+

Paper: https://arxiv.org/abs/2210.03629

+

The ReAct style is like so, and note Act style has no ‘Thought: ‘ entries: +System:

+
+

Answer the following questions as best you can. You have access to the following tools:

+
+

{tools}

+

Use the following format:

+

Thought: you should always think about what to do +Action: the action to take, should be one of [{tool_names}] +Action Input: the input to the action +Observation: the result of the action +… (this Thought/Action/Action Input/Observation can repeat N times)

+
+
+
+
User:

{questions}

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
User:

Observation:

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
+

+
+
+static parse_message(m: Message, tools: list[Tool]) ToolRequestMessage[source]
+
+ +
+ +
+
+class ldp.graph.modules.react.ToolDescriptionMethods(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: StrEnum

+

Possible methods of describing the tools.

+
+
+JSON = 'describe_json'
+
+ +
+
+STR = 'describe_str'
+
+ +
+
+XML = 'describe_xml'
+
+ +
+
+get_prompt_prefix() str[source]
+

Get the prefix to put in front of the prompt.

+
+ +
+ +
+
+ldp.graph.modules.react.parse_message(m: Message, tools: list[Tool]) ToolRequestMessage[source]
+

Parse an Act or ReAct Message into a ToolRequestMessage.

+
+
Parameters:
+
    +
  • m – Input raw message.

  • +
  • tools – Tools used to confirm a valid tool selection

  • +
+
+
Returns:
+

Parsed ToolRequestMessage.

+
+
+
+ +
+
+

ldp.graph.modules.reflect module

+
+
+class ldp.graph.modules.reflect.ReflectModule(start_config: ReflectModuleConfig)[source]
+

Bases: object

+

A module that simply gives an LLM to reflect on an input.

+
+ +
+
+class ldp.graph.modules.reflect.ReflectModuleConfig(*, llm_model: dict[str, Any] = {'model': 'gpt-3.5-turbo'})[source]
+

Bases: BaseModel

+

Configuration for the ReflectModuleConfig.

+
+
+llm_model: dict[str, Any]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-3.5-turbo'}, description='Starting configuration for the LLM model.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+
+

ldp.graph.modules.thought module

+
+
+class ldp.graph.modules.thought.ThoughtModule(llm_model: dict[str, Any], first_sys_prompt: str, second_sys_prompt: str)[source]
+

Bases: object

+
+ +
+
+

Module contents

+

A module is a subgraph of a compute graph that can be exposed like a single node/op.

+

An analogous entity in PyTorch is torch.nn.Module.

+
+
+class ldp.graph.modules.ParsedLLMCallModule(llm_model: dict[str, Any], parser: Callable[[...], TParsedMessage])[source]
+

Bases: Generic[TParsedMessage]

+

Module for a processing-based tool selection, with a learnable configuration.

+
+ +
+
+class ldp.graph.modules.ReActModule(llm_model: dict[str, Any], sys_prompt: str = 'Answer the following questions as best you can. You have access to the following tools:\n\n{tools}\n\nUse the following format:\n\nThought: you should always think about what to do\nAction: the action to take, should be one of [{tool_names}]\nAction Input: comma separated list of inputs to action as python tuple\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\n\nExample:\n\nThought: I need to use the get_weather tool\nAction: get_weather\nAction Input: "New York", 7\nObservation: The 7 day forecast for New York is [...]', tool_description_method: ToolDescriptionMethods = ToolDescriptionMethods.STR)[source]
+

Bases: object

+

An Act or ReAct module built to work with chat models.

+

Paper: https://arxiv.org/abs/2210.03629

+

The ReAct style is like so, and note Act style has no ‘Thought: ‘ entries: +System:

+
+

Answer the following questions as best you can. You have access to the following tools:

+
+

{tools}

+

Use the following format:

+

Thought: you should always think about what to do +Action: the action to take, should be one of [{tool_names}] +Action Input: the input to the action +Observation: the result of the action +… (this Thought/Action/Action Input/Observation can repeat N times)

+
+
+
+
User:

{questions}

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
User:

Observation:

+
+
Assistant:

Thought: +Action: +Action Input:

+
+
+

+
+
+static parse_message(m: Message, tools: list[Tool]) ToolRequestMessage[source]
+
+ +
+ +
+
+class ldp.graph.modules.ReflectModule(start_config: ReflectModuleConfig)[source]
+

Bases: object

+

A module that simply gives an LLM to reflect on an input.

+
+ +
+
+class ldp.graph.modules.ReflectModuleConfig(*, llm_model: dict[str, Any] = {'model': 'gpt-3.5-turbo'})[source]
+

Bases: BaseModel

+

Configuration for the ReflectModuleConfig.

+
+
+llm_model: dict[str, Any]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'llm_model': FieldInfo(annotation=dict[str, Any], required=False, default={'model': 'gpt-3.5-turbo'}, description='Starting configuration for the LLM model.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+
+class ldp.graph.modules.ThoughtModule(llm_model: dict[str, Any], first_sys_prompt: str, second_sys_prompt: str)[source]
+

Bases: object

+
+ +
+
+class ldp.graph.modules.ToolDescriptionMethods(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: StrEnum

+

Possible methods of describing the tools.

+
+
+JSON = 'describe_json'
+
+ +
+
+STR = 'describe_str'
+
+ +
+
+XML = 'describe_xml'
+
+ +
+
+get_prompt_prefix() str[source]
+

Get the prefix to put in front of the prompt.

+
+ +
+ +
+
+ldp.graph.modules.parse_message(m: Message, tools: list[Tool]) ToolRequestMessage[source]
+

Parse an Act or ReAct Message into a ToolRequestMessage.

+
+
Parameters:
+
    +
  • m – Input raw message.

  • +
  • tools – Tools used to confirm a valid tool selection

  • +
+
+
Returns:
+

Parsed ToolRequestMessage.

+
+
+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ldp.html b/docs/_build/html/ldp.html new file mode 100644 index 00000000..eba5d93c --- /dev/null +++ b/docs/_build/html/ldp.html @@ -0,0 +1,2054 @@ + + + + + + + + ldp package — ldp documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp package

+
+

Subpackages

+
+ +
+
+
+

Submodules

+
+
+

ldp.data_structures module

+
+
+class ldp.data_structures.Trajectory(*, traj_id: str | None = None, steps: list[Transition] = None)[source]
+

Bases: BaseModel

+
+
+compute_discounted_returns(discount: float = 1.0) list[float][source]
+

Compute the discounted returns for each step in the trajectory.

+
+ +
+
+property done: bool
+
+ +
+
+property failed: bool
+
+ +
+
+classmethod from_jsonl(filename: str | PathLike) Self[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'steps': FieldInfo(annotation=list[Transition], required=False, default_factory=list), 'traj_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+steps: list[Transition]
+
+ +
+
+to_jsonl(filename: str | PathLike) None[source]
+
+ +
+
+traj_id: str | None
+
+ +
+ +
+
+class ldp.data_structures.Transition(*, timestep: int, agent_state: Any, next_agent_state: Any, observation: list[ToolResponseMessage | Message], next_observation: list[ToolResponseMessage | Message], action: OpResult[ToolRequestMessage] | None = None, reward: float = 0.0, truncated: bool = False, done: bool = False, value: float = 0.0, metadata: dict[str, JsonValue] = None)[source]
+

Bases: BaseModel

+
+
+NO_OBSERVATION: ClassVar[list[Message]] = []
+
+ +
+
+action: OpResult[ToolRequestMessage] | None
+
+ +
+
+agent_state: Any
+
+ +
+
+classmethod construct_action(action: OpResult[ToolRequestMessage] | dict | None) OpResult[ToolRequestMessage] | None[source]
+
+ +
+
+done: bool
+
+ +
+
+property failed: bool
+

Get if an exception was encountered during rollout, for convenience.

+

If True, this transition should not be trained on. +Failed transitions are for debugging purposes.

+
+ +
+
+metadata: dict[str, JsonValue]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_dump_json(*, indent: int | None = None, **kwargs) str[source]
+

Usage docs: https://docs.pydantic.dev/2.8/concepts/serialization/#modelmodel_dump_json

+

Generates a JSON representation of the model using Pydantic’s to_json method.

+
+
Parameters:
+
    +
  • indent – Indentation to use in the JSON output. If None is passed, the output will be compact.

  • +
  • include – Field(s) to include in the JSON output.

  • +
  • exclude – Field(s) to exclude from the JSON output.

  • +
  • context – Additional context to pass to the serializer.

  • +
  • by_alias – Whether to serialize using field aliases.

  • +
  • exclude_unset – Whether to exclude fields that have not been explicitly set.

  • +
  • exclude_defaults – Whether to exclude fields that are set to their default value.

  • +
  • exclude_none – Whether to exclude fields that have a value of None.

  • +
  • round_trip – If True, dumped values should be valid as input for non-idempotent types such as Json[T].

  • +
  • warnings – How to handle serialization errors. False/”none” ignores them, True/”warn” logs errors, +“error” raises a [PydanticSerializationError][pydantic_core.PydanticSerializationError].

  • +
  • serialize_as_any – Whether to serialize fields with duck-typing serialization behavior.

  • +
+
+
Returns:
+

A JSON string representation of the model.

+
+
+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'action': FieldInfo(annotation=Union[OpResult[ToolRequestMessage], NoneType], required=False, default=None, description='Agent.get_asv output. This is a_t in RL terms.'), 'agent_state': FieldInfo(annotation=Any, required=True, description="Agent.get_asv's input. This is `s_t` in RL terms. Note that `s_0` comes from `Agent.init_state()`"), 'done': FieldInfo(annotation=bool, required=False, default=False, description="timestep t's Environment.step output."), 'metadata': FieldInfo(annotation=dict[str, JsonValue], required=False, default_factory=dict), 'next_agent_state': FieldInfo(annotation=Any, required=True, description="Agent.get_asv's output. This is s_t+1 in RL terms."), 'next_observation': FieldInfo(annotation=list[Union[ToolResponseMessage, Message]], required=True, description='Environment.step output. This is o_t+1 in RL terms.'), 'observation': FieldInfo(annotation=list[Union[ToolResponseMessage, Message]], required=True, description="Agent.get_asv's input. This is o_t in RL terms."), 'reward': FieldInfo(annotation=float, required=False, default=0.0, description='Environment.step output. This is r_t in RL terms.'), 'timestep': FieldInfo(annotation=int, required=True, description='Zero-indexed MDP timestep t.'), 'truncated': FieldInfo(annotation=bool, required=False, default=False, description="timestep t's Environment.step output."), 'value': FieldInfo(annotation=float, required=False, default=0.0, description="Value estimate output from timestep t's Agent.get_asv. This is v(s_t) [state value function] or q(s_t, a_t) [state-action value].")}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+next_agent_state: Any
+
+ +
+
+next_observation: list[ToolResponseMessage | Message]
+
+ +
+
+observation: list[ToolResponseMessage | Message]
+
+ +
+
+reward: float
+
+ +
+
+timestep: int
+
+ +
+
+truncated: bool
+
+ +
+
+value: float
+
+ +
+ +
+
+class ldp.data_structures.TransitionTree(root_id: str | UUID)[source]
+

Bases: object

+
+
+add_transition(step_id: str, step: Transition, weight: float = 1.0) None[source]
+

Add a transition to the tree.

+
+
Parameters:
+
    +
  • step_id – A unique identifier for the root node of the tree. +The expected form of the step ID is “{parent step ID}:{step index}”.

  • +
  • step – The transition to add.

  • +
  • weight – Weight of the transition. Defaults to 1.0.

  • +
+
+
+
+ +
+
+assign_mc_value_estimates(discount_factor: float = 1.0) None[source]
+

Assign Monte Carlo state-action value estimates to each transition (in-place).

+
+
Parameters:
+

discount_factor – The discount factor to use when computing cumulative +future rewards.

+
+
+
+ +
+
+get_trajectories() list[Trajectory][source]
+

Return a list of trajectories.

+

Since each path from the root node to a terminal node defines +a unique trajectory, N(terminal node) trajectories will be returned. +The trajectory ID will be set to the ID of the terminal step.

+

Note that we include failed and truncated trajectories; it is up to the +caller to decide what to do them.

+
+
Returns:
+

All trajectories in this tree.

+
+
+
+ +
+
+get_transition(step_id: str) Transition[source]
+
+ +
+
+get_weight(step_id: str) float[source]
+
+ +
+
+merge_identical_nodes(agent_state_hash_fn: ~collections.abc.Callable[[~typing.Any], ~collections.abc.Hashable], observation_hash_fn: ~collections.abc.Callable[[list[~aviary.tools.base.ToolResponseMessage | ~aviary.message.Message]], ~collections.abc.Hashable] = <function join>, next_observation_hash_fn: ~collections.abc.Callable[[list[~aviary.tools.base.ToolResponseMessage | ~aviary.message.Message]], ~collections.abc.Hashable] = <function join>) TransitionTree[source]
+

Merge nodes with identical (state, observation, action)s. Returns a new tree.

+
+
Parameters:
+
    +
  • agent_state_hash_fn – A function that returns a hashable representation +of the agent state of a transition.

  • +
  • observation_hash_fn – A function that returns a hashable representation +of the observation messages of a transition.

  • +
  • next_observation_hash_fn – A function that returns a hashable representation +of the next observation messages of a transition.

  • +
+
+
+
+ +
+ +
+
+

ldp.main module

+
+
+ldp.main.get_or_make_agent(agent: Agent | str | PathLike) Agent[source]
+
+ +
+
+ldp.main.get_or_make_environment(environment: Environment | str, task: str) Environment[source]
+
+ +
+
+async ldp.main.main(task: str, environment: Environment | str, agent: Agent | str | PathLike = 'SimpleAgent')[source]
+
+ +
+
+

ldp.shims module

+
+
+class ldp.shims.tqdm(*_, **__)[source]
+

Bases: Comparable

+

Decorate an iterable object, returning an iterator which acts exactly +like the original iterable, but prints a dynamically updating +progressbar every time a value is requested.

+
+
Parameters:
+
    +
  • iterable (iterable, optional) – Iterable to decorate with a progressbar. +Leave blank to manually manage the updates.

  • +
  • desc (str, optional) – Prefix for the progressbar.

  • +
  • total (int or float, optional) – The number of expected iterations. If unspecified, +len(iterable) is used if possible. If float(“inf”) or as a last +resort, only basic progress statistics are displayed +(no ETA, no progressbar). +If gui is True and this parameter needs subsequent updating, +specify an initial arbitrary large positive number, +e.g. 9e9.

  • +
  • leave (bool, optional) – If [default: True], keeps all traces of the progressbar +upon termination of iteration. +If None, will leave only if position is 0.

  • +
  • file (io.TextIOWrapper or io.StringIO, optional) – Specifies where to output the progress messages +(default: sys.stderr). Uses file.write(str) and file.flush() +methods. For encoding, see write_bytes.

  • +
  • ncols (int, optional) – The width of the entire output message. If specified, +dynamically resizes the progressbar to stay within this bound. +If unspecified, attempts to use environment width. The +fallback is a meter width of 10 and no limit for the counter and +statistics. If 0, will not print any meter (only stats).

  • +
  • mininterval (float, optional) – Minimum progress display update interval [default: 0.1] seconds.

  • +
  • maxinterval (float, optional) – Maximum progress display update interval [default: 10] seconds. +Automatically adjusts miniters to correspond to mininterval +after long display update lag. Only works if dynamic_miniters +or monitor thread is enabled.

  • +
  • miniters (int or float, optional) – Minimum progress display update interval, in iterations. +If 0 and dynamic_miniters, will automatically adjust to equal +mininterval (more CPU efficient, good for tight loops). +If > 0, will skip display of specified number of iterations. +Tweak this and mininterval to get very efficient loops. +If your progress is erratic with both fast and slow iterations +(network, skipping items, etc) you should set miniters=1.

  • +
  • ascii (bool or str, optional) – If unspecified or False, use unicode (smooth blocks) to fill +the meter. The fallback is to use ASCII characters ” 123456789#”.

  • +
  • disable (bool, optional) – Whether to disable the entire progressbar wrapper +[default: False]. If set to None, disable on non-TTY.

  • +
  • unit (str, optional) – String that will be used to define the unit of each iteration +[default: it].

  • +
  • unit_scale (bool or int or float, optional) – If 1 or True, the number of iterations will be reduced/scaled +automatically and a metric prefix following the +International System of Units standard will be added +(kilo, mega, etc.) [default: False]. If any other non-zero +number, will scale total and n.

  • +
  • dynamic_ncols (bool, optional) – If set, constantly alters ncols and nrows to the +environment (allowing for window resizes) [default: False].

  • +
  • smoothing (float, optional) – Exponential moving average smoothing factor for speed estimates +(ignored in GUI mode). Ranges from 0 (average speed) to 1 +(current/instantaneous speed) [default: 0.3].

  • +
  • bar_format (str, optional) –

    Specify a custom bar string formatting. May impact performance. +[default: ‘{l_bar}{bar}{r_bar}’], where +l_bar=’{desc}: {percentage:3.0f}%|’ and +r_bar=’| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ‘

    +
    +

    ’{rate_fmt}{postfix}]’

    +
    +
    +
    Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt,

    percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, +rate, rate_fmt, rate_noinv, rate_noinv_fmt, +rate_inv, rate_inv_fmt, postfix, unit_divisor, +remaining, remaining_s, eta.

    +
    +
    +

    Note that a trailing “: ” is automatically removed after {desc} +if the latter is empty.

    +

  • +
  • initial (int or float, optional) – The initial counter value. Useful when restarting a progress +bar [default: 0]. If using float, consider specifying {n:.3f} +or similar in bar_format, or specifying unit_scale.

  • +
  • position (int, optional) – Specify the line offset to print this bar (starting from 0) +Automatic if unspecified. +Useful to manage multiple bars at once (eg, from threads).

  • +
  • postfix (dict or *, optional) – Specify additional stats to display at the end of the bar. +Calls set_postfix(**postfix) if possible (dict).

  • +
  • unit_divisor (float, optional) – [default: 1000], ignored unless unit_scale is True.

  • +
  • write_bytes (bool, optional) – Whether to write bytes. If (default: False) will write unicode.

  • +
  • lock_args (tuple, optional) – Passed to refresh for intermediate output +(initialisation, iterating, and updating).

  • +
  • nrows (int, optional) – The screen height. If specified, hides nested bars outside this +bound. If unspecified, attempts to use environment height. +The fallback is 20.

  • +
  • colour (str, optional) – Bar colour (e.g. ‘green’, ‘#00ff00’).

  • +
  • delay (float, optional) – Don’t display until [default: 0] seconds have elapsed.

  • +
  • gui (bool, optional) – WARNING: internal parameter - do not use. +Use tqdm.gui.tqdm(…) instead. If set, will attempt to use +matplotlib animations for a graphical output [default: False].

  • +
+
+
Returns:
+

out

+
+
Return type:
+

decorated iterator.

+
+
+
+
+clear(nolock=False)[source]
+

Clear current bar display.

+
+ +
+
+close()[source]
+

Cleanup and (if leave=False) close the progressbar.

+
+ +
+
+display(msg=None, pos=None)[source]
+

Use self.sp to display msg in the specified pos.

+

Consider overloading this function when inheriting to use e.g.: +self.some_frontend(**self.format_dict) instead of self.sp.

+
+
Parameters:
+
    +
  • msg (str, optional. What to display (default: repr(self)).)

  • +
  • pos (int, optional. Position to moveto) – (default: abs(self.pos)).

  • +
+
+
+
+ +
+
+classmethod external_write_mode(file=None, nolock=False)[source]
+

Disable tqdm within context and refresh tqdm when exits. +Useful when writing to standard output stream

+
+ +
+
+property format_dict
+

Public API for read-only member access.

+
+ +
+
+static format_interval(t)[source]
+

Formats a number of seconds as a clock time, [H:]MM:SS

+
+
Parameters:
+

t (int) – Number of seconds.

+
+
Returns:
+

out – [H:]MM:SS

+
+
Return type:
+

str

+
+
+
+ +
+
+static format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False, unit='it', unit_scale=False, rate=None, bar_format=None, postfix=None, unit_divisor=1000, initial=0, colour=None, **extra_kwargs)[source]
+

Return a string-based progress bar given some parameters

+
+
Parameters:
+
    +
  • n (int or float) – Number of finished iterations.

  • +
  • total (int or float) – The expected total number of iterations. If meaningless (None), +only basic progress statistics are displayed (no ETA).

  • +
  • elapsed (float) – Number of seconds passed since start.

  • +
  • ncols (int, optional) – The width of the entire output message. If specified, +dynamically resizes {bar} to stay within this bound +[default: None]. If 0, will not print any bar (only stats). +The fallback is {bar:10}.

  • +
  • prefix (str, optional) – Prefix message (included in total width) [default: ‘’]. +Use as {desc} in bar_format string.

  • +
  • ascii (bool, optional or str, optional) – If not set, use unicode (smooth blocks) to fill the meter +[default: False]. The fallback is to use ASCII characters +” 123456789#”.

  • +
  • unit (str, optional) – The iteration unit [default: ‘it’].

  • +
  • unit_scale (bool or int or float, optional) – If 1 or True, the number of iterations will be printed with an +appropriate SI metric prefix (k = 10^3, M = 10^6, etc.) +[default: False]. If any other non-zero number, will scale +total and n.

  • +
  • rate (float, optional) – Manual override for iteration rate. +If [default: None], uses n/elapsed.

  • +
  • bar_format (str, optional) –

    Specify a custom bar string formatting. May impact performance. +[default: ‘{l_bar}{bar}{r_bar}’], where +l_bar=’{desc}: {percentage:3.0f}%|’ and +r_bar=’| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ‘

    +
    +

    ’{rate_fmt}{postfix}]’

    +
    +
    +
    Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt,

    percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, +rate, rate_fmt, rate_noinv, rate_noinv_fmt, +rate_inv, rate_inv_fmt, postfix, unit_divisor, +remaining, remaining_s, eta.

    +
    +
    +

    Note that a trailing “: ” is automatically removed after {desc} +if the latter is empty.

    +

  • +
  • postfix (*, optional) – Similar to prefix, but placed at the end +(e.g. for additional stats). +Note: postfix is usually a string (not a dict) for this method, +and will if possible be set to postfix = ‘, ‘ + postfix. +However other types are supported (#382).

  • +
  • unit_divisor (float, optional) – [default: 1000], ignored unless unit_scale is True.

  • +
  • initial (int or float, optional) – The initial counter value [default: 0].

  • +
  • colour (str, optional) – Bar colour (e.g. ‘green’, ‘#00ff00’).

  • +
+
+
Returns:
+

out

+
+
Return type:
+

Formatted meter and stats, ready to display.

+
+
+
+ +
+
+static format_num(n)[source]
+

Intelligent scientific notation (.3g).

+
+
Parameters:
+

n (int or float or Numeric) – A Number.

+
+
Returns:
+

out – Formatted number.

+
+
Return type:
+

str

+
+
+
+ +
+
+static format_sizeof(num, suffix='', divisor=1000)[source]
+

Formats a number (greater than unity) with SI Order of Magnitude +prefixes.

+
+
Parameters:
+
    +
  • num (float) – Number ( >= 1) to format.

  • +
  • suffix (str, optional) – Post-postfix [default: ‘’].

  • +
  • divisor (float, optional) – Divisor between prefixes [default: 1000].

  • +
+
+
Returns:
+

out – Number with Order of Magnitude SI unit postfix.

+
+
Return type:
+

str

+
+
+
+ +
+
+classmethod get_lock()[source]
+

Get the global lock. Construct it if it does not exist.

+
+ +
+
+monitor = None
+
+ +
+
+monitor_interval = 10
+
+ +
+
+moveto(n)[source]
+
+ +
+
+classmethod pandas(**tqdm_kwargs)[source]
+
+
Registers the current tqdm class with

pandas.core. +( frame.DataFrame +| series.Series +| groupby.(generic.)DataFrameGroupBy +| groupby.(generic.)SeriesGroupBy +).progress_apply

+
+
+

A new instance will be created every time progress_apply is called, +and each instance will automatically close() upon completion.

+
+
Parameters:
+

tqdm_kwargs (arguments for the tqdm instance)

+
+
+

Examples

+
>>> import pandas as pd
+>>> import numpy as np
+>>> from tqdm import tqdm
+>>> from tqdm.gui import tqdm as tqdm_gui
+>>>
+>>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
+>>> tqdm.pandas(ncols=50)  # can use tqdm_gui, optional kwargs, etc
+>>> # Now you can use `progress_apply` instead of `apply`
+>>> df.groupby(0).progress_apply(lambda x: x**2)
+
+
+

References

+

<https://stackoverflow.com/questions/18603270/ progress-indicator-during-pandas-operations-python>

+
+ +
+
+refresh(nolock=False, lock_args=None)[source]
+

Force refresh the display of this bar.

+
+
Parameters:
+
    +
  • nolock (bool, optional) – If True, does not lock. +If [default: False]: calls acquire() on internal lock.

  • +
  • lock_args (tuple, optional) – Passed to internal lock’s acquire(). +If specified, will only display() if acquire() returns True.

  • +
+
+
+
+ +
+
+reset(total=None)[source]
+

Resets to 0 iterations for repeated use.

+

Consider combining with leave=True.

+
+
Parameters:
+

total (int or float, optional. Total to use for the new bar.)

+
+
+
+ +
+
+set_description(desc=None, refresh=True)[source]
+

Set/modify description of the progress bar.

+
+
Parameters:
+
    +
  • desc (str, optional)

  • +
  • refresh (bool, optional) – Forces refresh [default: True].

  • +
+
+
+
+ +
+
+set_description_str(desc=None, refresh=True)[source]
+

Set/modify description without ‘: ‘ appended.

+
+ +
+
+classmethod set_lock(lock)[source]
+

Set the global lock.

+
+ +
+
+set_postfix(ordered_dict=None, refresh=True, **kwargs)[source]
+

Set/modify postfix (additional stats) +with automatic formatting based on datatype.

+
+
Parameters:
+
    +
  • ordered_dict (dict or OrderedDict, optional)

  • +
  • refresh (bool, optional) – Forces refresh [default: True].

  • +
  • kwargs (dict, optional)

  • +
+
+
+
+ +
+
+set_postfix_str(s='', refresh=True)[source]
+

Postfix without dictionary expansion, similar to prefix handling.

+
+ +
+
+static status_printer(file)[source]
+

Manage the printing and in-place updating of a line of characters. +Note that if the string is longer than a line, then in-place +updating may not work (it will print a new line at each refresh).

+
+ +
+
+unpause()[source]
+

Restart tqdm timer from last print time.

+
+ +
+
+update(n=1)[source]
+

Manually update the progress bar, useful for streams +such as reading files. +E.g.: +>>> t = tqdm(total=filesize) # Initialise +>>> for current_buffer in stream: +… … +… t.update(len(current_buffer)) +>>> t.close() +The last line is highly recommended, but possibly not necessary if +t.update() will be called in such a way that filesize will be +exactly reached and printed.

+
+
Parameters:
+

n (int or float, optional) – Increment to add to the internal counter of iterations +[default: 1]. If using float, consider specifying {n:.3f} +or similar in bar_format, or specifying unit_scale.

+
+
Returns:
+

out – True if a display() was triggered.

+
+
Return type:
+

bool or None

+
+
+
+ +
+
+classmethod wrapattr(stream, method, total=None, bytes=True, **tqdm_kwargs)[source]
+

stream : file-like object. +method : str, “read” or “write”. The result of read() and

+
+

the first argument of write() should have a len().

+
+
>>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj:
+...     while True:
+...         chunk = fobj.read(chunk_size)
+...         if not chunk:
+...             break
+
+
+
+ +
+
+classmethod write(s, file=None, end='\n', nolock=False)[source]
+

Print a message via tqdm (without overlap with bars).

+
+ +
+ +
+
+ldp.shims.trange(*args, **kwargs)[source]
+

Shortcut for tqdm(range(*args), **kwargs).

+
+ +
+
+

ldp.utils module

+
+
+ldp.utils.configure_log_levels() None[source]
+

Configure log levels.

+
+ +
+
+ldp.utils.configure_stdout_logs(level: int | str = 20, fmt: str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s') None[source]
+

Configure root logger to log to stdout.

+
+
Parameters:
+
    +
  • level – Log level to be emitted to stdout.

  • +
  • fmt – Optional format string.

  • +
+
+
+
+ +
+
+ldp.utils.discounted_returns(rewards: list[float], terminated: list[bool], discount: float = 1.0) list[float][source]
+

Calculate the discounted returns for a list of rewards, considering termination flags and a discount factor.

+

The discounted return represents the future discounted rewards from each time step onwards, taking into account +whether an episode has terminated at each step.

+

The discounted return ( G_t ) is given by:

+
+\[ \begin{align}\begin{aligned}G_t = \sum_{k=1}^{\infty} \gamma^{k-1} R_{t+k}\\where: +- \( G_t \) is the discounted return starting from time step \( t \). +- \( \gamma \) is the discount factor. +- \( R_{t+k} \) is the reward received at time step \( t+k \).\end{aligned}\end{align} \]
+

NOTE: this could live in ldp.alg, but it’s here to avoid circular imports.

+
+
Parameters:
+
    +
  • rewards – A list of rewards at each time step.

  • +
  • terminated – A list of boolean flags indicating whether the episode terminated at each time step.

  • +
  • discount – Discount factor to apply to future rewards. Defaults to 1.0 which means no discounting is applied.

  • +
+
+
Returns:
+

+
A list of discounted returns (rewards to go), with each element representing the

total discounted reward from that step onwards.

+
+
+

+
+
+

Example

+
>>> rewards = [1.0, 2.0, 3.0]
+>>> terminated = [False, False, True]
+>>> discounted_returns(rewards, terminated, discount=0.9)
+[5.23, 4.7, 3.0]
+
+
+
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/ldp.llms.html b/docs/_build/html/ldp.llms.html new file mode 100644 index 00000000..1d5dd493 --- /dev/null +++ b/docs/_build/html/ldp.llms.html @@ -0,0 +1,1229 @@ + + + + + + + + ldp.llms package — ldp documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp.llms package

+
+

Submodules

+
+
+

ldp.llms.chat module

+
+
+exception ldp.llms.chat.JSONSchemaValidationError[source]
+

Bases: ValueError

+

Raised when the completion does not match the specified schema.

+
+ +
+
+class ldp.llms.chat.LLMModel(*, name: str = 'unknown', config: dict = {'model': 'gpt-3.5-turbo', 'temperature': 0.1}, encoding: Any | None = None)[source]
+

Bases: MultipleCompletionLLMModel

+
+
+async call(*args, **kwargs) LLMResult[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'config': FieldInfo(annotation=dict, required=False, default={'model': 'gpt-3.5-turbo', 'temperature': 0.1}), 'encoding': FieldInfo(annotation=Union[Any, NoneType], required=False, default=None), 'name': FieldInfo(annotation=str, required=False, default='unknown')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+
+class ldp.llms.chat.LLMResult(*, id: UUID = None, config: dict | None = None, prompt: list[Message] | None = None, messages: list[Message] | None = None, prompt_count: int = 0, completion_count: int = 0, model: str, date: str = None, seconds_to_first_token: float | None = None, seconds_to_last_token: float = 0, logprob: float | None = None, system_fingerprint: str | None = None)[source]
+

Bases: BaseModel

+

A class to hold the result of a LLM completion.

+
+
+completion_count: int
+
+ +
+
+config: dict | None
+
+ +
+
+date: str
+
+ +
+
+get_supported_openai_params() list[str] | None[source]
+

Get the supported OpenAI parameters for the model.

+
+ +
+
+id: UUID
+
+ +
+
+logprob: float | None
+
+ +
+
+messages: list[Message] | None
+
+ +
+
+model: str
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'completion_count': FieldInfo(annotation=int, required=False, default=0, description='Count of completion tokens.'), 'config': FieldInfo(annotation=Union[dict, NoneType], required=False, default=None), 'date': FieldInfo(annotation=str, required=False, default_factory=builtin_function_or_method), 'id': FieldInfo(annotation=UUID, required=False, default_factory=uuid4), 'logprob': FieldInfo(annotation=Union[float, NoneType], required=False, default=None, description='Sum of logprobs in the completion.'), 'messages': FieldInfo(annotation=Union[list[Message], NoneType], required=False, default=None, description='Messages received from the LLM.'), 'model': FieldInfo(annotation=str, required=True), 'prompt': FieldInfo(annotation=Union[list[Message], NoneType], required=False, default=None, description='Messages sent to the LLM.'), 'prompt_count': FieldInfo(annotation=int, required=False, default=0, description='Count of prompt tokens.'), 'seconds_to_first_token': FieldInfo(annotation=Union[float, NoneType], required=False, default=None), 'seconds_to_last_token': FieldInfo(annotation=float, required=False, default=0), 'system_fingerprint': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='System fingerprint received from the LLM.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+prompt: list[Message] | None
+
+ +
+
+property prompt_and_completion_costs: tuple[float, float]
+

Get a two-tuple of prompt tokens cost and completion tokens cost, in USD.

+
+ +
+
+prompt_count: int
+
+ +
+
+property provider: str
+

Get the model provider’s name (e.g. “openai”, “mistral”).

+
+ +
+
+seconds_to_first_token: float | None
+
+ +
+
+seconds_to_last_token: float
+
+ +
+
+system_fingerprint: str | None
+
+ +
+ +
+
+class ldp.llms.chat.MultipleCompletionLLMModel(*, name: str = 'unknown', config: dict = {'model': 'gpt-3.5-turbo', 'temperature': 0.1}, encoding: Any | None = None)[source]
+

Bases: BaseModel

+

Run n completions at once, all starting from the same messages.

+
+
+TOOL_CHOICE_REQUIRED: ClassVar[str] = 'required'
+
+ +
+
+async achat(messages: Iterable[Message], **kwargs) ModelResponse[source]
+
+ +
+
+async achat_iter(messages: Iterable[Message], **kwargs) AsyncGenerator[source]
+
+ +
+
+async call(messages: list[Message], callbacks: list[Callable] | None = None, output_type: type[BaseModel] | None = None, tools: list[Tool] | None = None, tool_choice: Tool | str | None = 'required', **chat_kwargs) list[LLMResult][source]
+
+ +
+
+config: dict
+
+ +
+
+encoding: Any | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'config': FieldInfo(annotation=dict, required=False, default={'model': 'gpt-3.5-turbo', 'temperature': 0.1}), 'encoding': FieldInfo(annotation=Union[Any, NoneType], required=False, default=None), 'name': FieldInfo(annotation=str, required=False, default='unknown')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+
+set_model_name() Self[source]
+
+ +
+ +
+
+ldp.llms.chat.sum_logprobs(choice: Choices) float | None[source]
+

Calculate the sum of the log probabilities of an LLM completion (a Choices object).

+
+
Parameters:
+

choice – A sequence of choices from the completion.

+
+
Returns:
+

The sum of the log probabilities of the choice.

+
+
+
+ +
+
+ldp.llms.chat.validate_json_completion(completion: ModelResponse, output_type: type[BaseModel]) None[source]
+

Validate a completion against a JSON schema.

+
+
Parameters:
+
    +
  • completion – The completion to validate.

  • +
  • output_type – The Pydantic model to validate the completion against.

  • +
+
+
+
+ +
+
+

ldp.llms.embeddings module

+
+
+class ldp.llms.embeddings.EmbeddingModel(*, name: str, dimensions: int | None = None)[source]
+

Bases: ABC, BaseModel

+
+
+dimensions: int | None
+
+ +
+
+async embed_text(text: str) ndarray[source]
+
+ +
+
+abstract async embed_texts(texts: list[str]) list[ndarray][source]
+
+ +
+
+static from_name(embedding: str, **kwargs) EmbeddingModel[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'dimensions': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'name': FieldInfo(annotation=str, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+
+set_mode(mode: EmbeddingModes) None[source]
+

Several embedding models have a ‘mode’ or prompt which affects output.

+
+ +
+ +
+
+class ldp.llms.embeddings.EmbeddingModes(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: StrEnum

+

Enum representing the different modes of an embedding model.

+
+
+DOCUMENT = 'document'
+
+ +
+
+QUERY = 'query'
+
+ +
+ +
+
+class ldp.llms.embeddings.HybridEmbeddingModel(*, name: str = 'hybrid-embed', dimensions: int | None = None, models: list[EmbeddingModel])[source]
+

Bases: EmbeddingModel

+
+
+async embed_texts(texts)[source]
+
+ +
+
+classmethod infer_dimensions(data: dict[str, Any]) dict[str, Any][source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'dimensions': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'models': FieldInfo(annotation=list[EmbeddingModel], required=True), 'name': FieldInfo(annotation=str, required=False, default='hybrid-embed')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+models: list[EmbeddingModel]
+
+ +
+
+name: str
+
+ +
+ +
+
+class ldp.llms.embeddings.LiteEmbeddingModel(*, name: str = 'text-embedding-3-small', dimensions: int | None = None, batch_size: int = 16, embed_kwargs: dict[str, Any] = None)[source]
+

Bases: EmbeddingModel

+
+
+batch_size: int
+
+ +
+
+dimensions: int | None
+
+ +
+
+embed_kwargs: dict[str, Any]
+
+ +
+
+async embed_texts(texts: list[str]) list[ndarray][source]
+
+ +
+
+classmethod infer_dimensions(data: dict[str, Any]) dict[str, Any][source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=False, default=16), 'dimensions': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description="The length an embedding will have. If left unspecified, we attempt to infer an un-truncated length via LiteLLM's internal model map. If this inference fails, the embedding will be un-truncated."), 'embed_kwargs': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict, description='Extra kwargs to pass to litellm.aembedding.'), 'name': FieldInfo(annotation=str, required=False, default='text-embedding-3-small')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+ +
+
+class ldp.llms.embeddings.SparseEmbeddingModel(*, name: str = 'sparse', dimensions: int = 256, enc: Encoding = None)[source]
+

Bases: EmbeddingModel

+

This is a very simple keyword search model - probably best to be mixed with others.

+
+
+dimensions: int
+
+ +
+
+async embed_texts(texts) list[ndarray][source]
+
+ +
+
+enc: Encoding
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'dimensions': FieldInfo(annotation=int, required=False, default=256), 'enc': FieldInfo(annotation=Encoding, required=False, default_factory=<lambda>), 'name': FieldInfo(annotation=str, required=False, default='sparse')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+ +
+
+

ldp.llms.prompts module

+

This module provides utility functions for appending and prepending system messages.

+
+
+ldp.llms.prompts.append_to_messages(messages: list[Message], new_message: Message) list[Message][source]
+

Appends a message to a list of messages, returning that in-place modified list.

+

Examples

+
>>> messages = [Message(content="Hello")]
+>>> modified_messages = append_to_messages(messages, Message(content="New"))
+>>> modified_messages
+[Message(role='user', content='Hello'), Message(role='user', content='New')]
+>>> id(messages) == id(modified_messages)
+True
+
+
+
+ +
+
+ldp.llms.prompts.append_to_sys(user_content: str, sys_content: str | None = None) list[Message][source]
+

Appends a user message to a list of messages, optionally including a system message.

+
+
Parameters:
+
    +
  • user_content – The content of the user message.

  • +
  • sys_content – Optional content for the system message. Defaults to None.

  • +
+
+
Returns:
+

A list of messages including the optional system message and the user message.

+
+
+

Examples

+
>>> append_to_sys("Hello, world!")
+[Message(role='user', content='Hello, world!')]
+
+
+
>>> append_to_sys("Hello, world!", "System initialized.")
+[Message(role='system', content='System initialized.'), Message(role='user', content='Hello, world!')]
+
+
+
+ +
+
+ldp.llms.prompts.indent_xml(xml_string, indent_size=2)[source]
+
+ +
+
+ldp.llms.prompts.prepend_sys(messages: Collection, sys_content: str) list[Message][source]
+

Prepends a system message to a list of messages.

+
+
Parameters:
+
    +
  • messages – The list of existing messages.

  • +
  • sys_content – The content of the system message to be prepended.

  • +
+
+
Returns:
+

A new list of messages with the system message prepended.

+
+
+

Examples

+
>>> messages = [Message(role="user", content="Hello!")]
+>>> prepend_sys(messages, "System initialized.")
+[Message(role='system', content='System initialized.'), Message(role='user', content='Hello!')]
+
+
+
+ +
+
+ldp.llms.prompts.prepend_sys_and_append_sys(messages: Iterable[Message], initial_sys_content: str, final_sys_content: str) list[Message][source]
+
+ +
+
+

Module contents

+
+
+class ldp.llms.EmbeddingModel(*, name: str, dimensions: int | None = None)[source]
+

Bases: ABC, BaseModel

+
+
+dimensions: int | None
+
+ +
+
+async embed_text(text: str) ndarray[source]
+
+ +
+
+abstract async embed_texts(texts: list[str]) list[ndarray][source]
+
+ +
+
+static from_name(embedding: str, **kwargs) EmbeddingModel[source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'dimensions': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'name': FieldInfo(annotation=str, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+
+set_mode(mode: EmbeddingModes) None[source]
+

Several embedding models have a ‘mode’ or prompt which affects output.

+
+ +
+ +
+
+class ldp.llms.EmbeddingModes(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: StrEnum

+

Enum representing the different modes of an embedding model.

+
+
+DOCUMENT = 'document'
+
+ +
+
+QUERY = 'query'
+
+ +
+ +
+
+class ldp.llms.HybridEmbeddingModel(*, name: str = 'hybrid-embed', dimensions: int | None = None, models: list[EmbeddingModel])[source]
+

Bases: EmbeddingModel

+
+
+dimensions: int | None
+
+ +
+
+async embed_texts(texts)[source]
+
+ +
+
+classmethod infer_dimensions(data: dict[str, Any]) dict[str, Any][source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'dimensions': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'models': FieldInfo(annotation=list[EmbeddingModel], required=True), 'name': FieldInfo(annotation=str, required=False, default='hybrid-embed')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+models: list[EmbeddingModel]
+
+ +
+
+name: str
+
+ +
+ +
+
+exception ldp.llms.JSONSchemaValidationError[source]
+

Bases: ValueError

+

Raised when the completion does not match the specified schema.

+
+ +
+
+class ldp.llms.LLMModel(*, name: str = 'unknown', config: dict = {'model': 'gpt-3.5-turbo', 'temperature': 0.1}, encoding: Any | None = None)[source]
+

Bases: MultipleCompletionLLMModel

+
+
+async call(*args, **kwargs) LLMResult[source]
+
+ +
+
+config: dict
+
+ +
+
+encoding: Any | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'config': FieldInfo(annotation=dict, required=False, default={'model': 'gpt-3.5-turbo', 'temperature': 0.1}), 'encoding': FieldInfo(annotation=Union[Any, NoneType], required=False, default=None), 'name': FieldInfo(annotation=str, required=False, default='unknown')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+ +
+
+class ldp.llms.LLMResult(*, id: UUID = None, config: dict | None = None, prompt: list[Message] | None = None, messages: list[Message] | None = None, prompt_count: int = 0, completion_count: int = 0, model: str, date: str = None, seconds_to_first_token: float | None = None, seconds_to_last_token: float = 0, logprob: float | None = None, system_fingerprint: str | None = None)[source]
+

Bases: BaseModel

+

A class to hold the result of a LLM completion.

+
+
+completion_count: int
+
+ +
+
+config: dict | None
+
+ +
+
+date: str
+
+ +
+
+get_supported_openai_params() list[str] | None[source]
+

Get the supported OpenAI parameters for the model.

+
+ +
+
+id: UUID
+
+ +
+
+logprob: float | None
+
+ +
+
+messages: list[Message] | None
+
+ +
+
+model: str
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'completion_count': FieldInfo(annotation=int, required=False, default=0, description='Count of completion tokens.'), 'config': FieldInfo(annotation=Union[dict, NoneType], required=False, default=None), 'date': FieldInfo(annotation=str, required=False, default_factory=builtin_function_or_method), 'id': FieldInfo(annotation=UUID, required=False, default_factory=uuid4), 'logprob': FieldInfo(annotation=Union[float, NoneType], required=False, default=None, description='Sum of logprobs in the completion.'), 'messages': FieldInfo(annotation=Union[list[Message], NoneType], required=False, default=None, description='Messages received from the LLM.'), 'model': FieldInfo(annotation=str, required=True), 'prompt': FieldInfo(annotation=Union[list[Message], NoneType], required=False, default=None, description='Messages sent to the LLM.'), 'prompt_count': FieldInfo(annotation=int, required=False, default=0, description='Count of prompt tokens.'), 'seconds_to_first_token': FieldInfo(annotation=Union[float, NoneType], required=False, default=None), 'seconds_to_last_token': FieldInfo(annotation=float, required=False, default=0), 'system_fingerprint': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='System fingerprint received from the LLM.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+prompt: list[Message] | None
+
+ +
+
+property prompt_and_completion_costs: tuple[float, float]
+

Get a two-tuple of prompt tokens cost and completion tokens cost, in USD.

+
+ +
+
+prompt_count: int
+
+ +
+
+property provider: str
+

Get the model provider’s name (e.g. “openai”, “mistral”).

+
+ +
+
+seconds_to_first_token: float | None
+
+ +
+
+seconds_to_last_token: float
+
+ +
+
+system_fingerprint: str | None
+
+ +
+ +
+
+class ldp.llms.LiteEmbeddingModel(*, name: str = 'text-embedding-3-small', dimensions: int | None = None, batch_size: int = 16, embed_kwargs: dict[str, Any] = None)[source]
+

Bases: EmbeddingModel

+
+
+batch_size: int
+
+ +
+
+dimensions: int | None
+
+ +
+
+embed_kwargs: dict[str, Any]
+
+ +
+
+async embed_texts(texts: list[str]) list[ndarray][source]
+
+ +
+
+classmethod infer_dimensions(data: dict[str, Any]) dict[str, Any][source]
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'batch_size': FieldInfo(annotation=int, required=False, default=16), 'dimensions': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, description="The length an embedding will have. If left unspecified, we attempt to infer an un-truncated length via LiteLLM's internal model map. If this inference fails, the embedding will be un-truncated."), 'embed_kwargs': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict, description='Extra kwargs to pass to litellm.aembedding.'), 'name': FieldInfo(annotation=str, required=False, default='text-embedding-3-small')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+ +
+
+class ldp.llms.MultipleCompletionLLMModel(*, name: str = 'unknown', config: dict = {'model': 'gpt-3.5-turbo', 'temperature': 0.1}, encoding: Any | None = None)[source]
+

Bases: BaseModel

+

Run n completions at once, all starting from the same messages.

+
+
+TOOL_CHOICE_REQUIRED: ClassVar[str] = 'required'
+
+ +
+
+async achat(messages: Iterable[Message], **kwargs) ModelResponse[source]
+
+ +
+
+async achat_iter(messages: Iterable[Message], **kwargs) AsyncGenerator[source]
+
+ +
+
+async call(messages: list[Message], callbacks: list[Callable] | None = None, output_type: type[BaseModel] | None = None, tools: list[Tool] | None = None, tool_choice: Tool | str | None = 'required', **chat_kwargs) list[LLMResult][source]
+
+ +
+
+config: dict
+
+ +
+
+encoding: Any | None
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'config': FieldInfo(annotation=dict, required=False, default={'model': 'gpt-3.5-turbo', 'temperature': 0.1}), 'encoding': FieldInfo(annotation=Union[Any, NoneType], required=False, default=None), 'name': FieldInfo(annotation=str, required=False, default='unknown')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+
+set_model_name() Self[source]
+
+ +
+ +
+
+class ldp.llms.SparseEmbeddingModel(*, name: str = 'sparse', dimensions: int = 256, enc: Encoding = None)[source]
+

Bases: EmbeddingModel

+

This is a very simple keyword search model - probably best to be mixed with others.

+
+
+dimensions: int
+
+ +
+
+async embed_texts(texts) list[ndarray][source]
+
+ +
+
+enc: Encoding
+
+ +
+
+model_computed_fields: ClassVar[dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[dict[str, FieldInfo]] = {'dimensions': FieldInfo(annotation=int, required=False, default=256), 'enc': FieldInfo(annotation=Encoding, required=False, default_factory=<lambda>), 'name': FieldInfo(annotation=str, required=False, default='sparse')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo].

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+name: str
+
+ +
+ +
+
+ldp.llms.append_to_messages(messages: list[Message], new_message: Message) list[Message][source]
+

Appends a message to a list of messages, returning that in-place modified list.

+

Examples

+
>>> messages = [Message(content="Hello")]
+>>> modified_messages = append_to_messages(messages, Message(content="New"))
+>>> modified_messages
+[Message(role='user', content='Hello'), Message(role='user', content='New')]
+>>> id(messages) == id(modified_messages)
+True
+
+
+
+ +
+
+ldp.llms.append_to_sys(user_content: str, sys_content: str | None = None) list[Message][source]
+

Appends a user message to a list of messages, optionally including a system message.

+
+
Parameters:
+
    +
  • user_content – The content of the user message.

  • +
  • sys_content – Optional content for the system message. Defaults to None.

  • +
+
+
Returns:
+

A list of messages including the optional system message and the user message.

+
+
+

Examples

+
>>> append_to_sys("Hello, world!")
+[Message(role='user', content='Hello, world!')]
+
+
+
>>> append_to_sys("Hello, world!", "System initialized.")
+[Message(role='system', content='System initialized.'), Message(role='user', content='Hello, world!')]
+
+
+
+ +
+
+ldp.llms.prepend_sys(messages: Collection, sys_content: str) list[Message][source]
+

Prepends a system message to a list of messages.

+
+
Parameters:
+
    +
  • messages – The list of existing messages.

  • +
  • sys_content – The content of the system message to be prepended.

  • +
+
+
Returns:
+

A new list of messages with the system message prepended.

+
+
+

Examples

+
>>> messages = [Message(role="user", content="Hello!")]
+>>> prepend_sys(messages, "System initialized.")
+[Message(role='system', content='System initialized.'), Message(role='user', content='Hello!')]
+
+
+
+ +
+
+ldp.llms.prepend_sys_and_append_sys(messages: Iterable[Message], initial_sys_content: str, final_sys_content: str) list[Message][source]
+
+ +
+
+ldp.llms.sum_logprobs(choice: Choices) float | None[source]
+

Calculate the sum of the log probabilities of an LLM completion (a Choices object).

+
+
Parameters:
+

choice – A sequence of choices from the completion.

+
+
Returns:
+

The sum of the log probabilities of the choice.

+
+
+
+ +
+
+ldp.llms.validate_json_completion(completion: ModelResponse, output_type: type[BaseModel]) None[source]
+

Validate a completion against a JSON schema.

+
+
Parameters:
+
    +
  • completion – The completion to validate.

  • +
  • output_type – The Pydantic model to validate the completion against.

  • +
+
+
+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/modules.html b/docs/_build/html/modules.html new file mode 100644 index 00000000..6949d44f --- /dev/null +++ b/docs/_build/html/modules.html @@ -0,0 +1,262 @@ + + + + + + + + ldp — ldp documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

ldp

+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/objects.inv b/docs/_build/html/objects.inv new file mode 100644 index 00000000..fc0db2db Binary files /dev/null and b/docs/_build/html/objects.inv differ diff --git a/docs/_build/html/py-modindex.html b/docs/_build/html/py-modindex.html new file mode 100644 index 00000000..1e1cb5f5 --- /dev/null +++ b/docs/_build/html/py-modindex.html @@ -0,0 +1,333 @@ + + + + + + + Python Module Index — ldp documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Python Module Index

+ +
+ l +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ l
+ ldp +
    + ldp.agent +
    + ldp.agent.agent +
    + ldp.agent.agent_client +
    + ldp.agent.interactive_agent +
    + ldp.agent.memory_agent +
    + ldp.agent.react_agent +
    + ldp.agent.simple_agent +
    + ldp.agent.tree_of_thoughts_agent +
    + ldp.alg +
    + ldp.alg.algorithms +
    + ldp.alg.beam_search +
    + ldp.alg.callbacks +
    + ldp.alg.datasets +
    + ldp.alg.optimizer +
    + ldp.alg.optimizer.ape +
    + ldp.alg.optimizer.memory +
    + ldp.alg.optimizer.opt +
    + ldp.alg.optimizer.replay_buffers +
    + ldp.alg.rollout +
    + ldp.alg.runners +
    + ldp.alg.tree_search +
    + ldp.data_structures +
    + ldp.graph +
    + ldp.graph.async_torch +
    + ldp.graph.common_ops +
    + ldp.graph.gradient_estimators +
    + ldp.graph.loss_ops +
    + ldp.graph.memory +
    + ldp.graph.modules +
    + ldp.graph.modules.llm_call +
    + ldp.graph.modules.react +
    + ldp.graph.modules.reflect +
    + ldp.graph.modules.thought +
    + ldp.graph.op_utils +
    + ldp.graph.ops +
    + ldp.graph.torch_ops +
    + ldp.llms +
    + ldp.llms.chat +
    + ldp.llms.embeddings +
    + ldp.llms.prompts +
    + ldp.main +
    + ldp.shims +
    + ldp.utils +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html new file mode 100644 index 00000000..9e3345ad --- /dev/null +++ b/docs/_build/html/search.html @@ -0,0 +1,120 @@ + + + + + + + Search — ldp documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js new file mode 100644 index 00000000..42bafe26 --- /dev/null +++ b/docs/_build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"Contents:": [[0, null]], "Indices and tables": [[0, "indices-and-tables"]], "Module contents": [[1, "module-ldp"], [2, "module-ldp.agent"], [3, "module-ldp.alg"], [4, "module-ldp.alg.optimizer"], [5, "module-ldp.graph"], [6, "module-ldp.graph.modules"], [7, "module-ldp.llms"]], "Submodules": [[1, "submodules"], [2, "submodules"], [3, "submodules"], [4, "submodules"], [5, "submodules"], [6, "submodules"], [7, "submodules"]], "Subpackages": [[1, "subpackages"], [3, "subpackages"], [5, "subpackages"]], "Welcome to ldp\u2019s documentation!": [[0, "welcome-to-ldp-s-documentation"]], "ldp": [[8, "ldp"]], "ldp package": [[1, "ldp-package"]], "ldp.agent package": [[2, "ldp-agent-package"]], "ldp.agent.agent module": [[2, "module-ldp.agent.agent"]], "ldp.agent.agent_client module": [[2, "module-ldp.agent.agent_client"]], "ldp.agent.interactive_agent module": [[2, "module-ldp.agent.interactive_agent"]], "ldp.agent.memory_agent module": [[2, "module-ldp.agent.memory_agent"]], "ldp.agent.react_agent module": [[2, "module-ldp.agent.react_agent"]], "ldp.agent.simple_agent module": [[2, "module-ldp.agent.simple_agent"]], "ldp.agent.tree_of_thoughts_agent module": [[2, "module-ldp.agent.tree_of_thoughts_agent"]], "ldp.alg package": [[3, "ldp-alg-package"]], "ldp.alg.algorithms module": [[3, "module-ldp.alg.algorithms"]], "ldp.alg.beam_search module": [[3, "module-ldp.alg.beam_search"]], "ldp.alg.callbacks module": [[3, "module-ldp.alg.callbacks"]], "ldp.alg.datasets module": [[3, "module-ldp.alg.datasets"]], "ldp.alg.optimizer package": [[4, "ldp-alg-optimizer-package"]], "ldp.alg.optimizer.ape module": [[4, "module-ldp.alg.optimizer.ape"]], "ldp.alg.optimizer.memory module": [[4, "module-ldp.alg.optimizer.memory"]], "ldp.alg.optimizer.opt module": [[4, "module-ldp.alg.optimizer.opt"]], "ldp.alg.optimizer.replay_buffers module": [[4, "module-ldp.alg.optimizer.replay_buffers"]], "ldp.alg.rollout module": [[3, "module-ldp.alg.rollout"]], "ldp.alg.runners module": [[3, "module-ldp.alg.runners"]], "ldp.alg.tree_search module": [[3, "module-ldp.alg.tree_search"]], "ldp.data_structures module": [[1, "module-ldp.data_structures"]], "ldp.graph package": [[5, "ldp-graph-package"]], "ldp.graph.async_torch module": [[5, "module-ldp.graph.async_torch"]], "ldp.graph.common_ops module": [[5, "module-ldp.graph.common_ops"]], "ldp.graph.gradient_estimators module": [[5, "module-ldp.graph.gradient_estimators"]], "ldp.graph.loss_ops module": [[5, "module-ldp.graph.loss_ops"]], "ldp.graph.memory module": [[5, "module-ldp.graph.memory"]], "ldp.graph.modules package": [[6, "ldp-graph-modules-package"]], "ldp.graph.modules.llm_call module": [[6, "module-ldp.graph.modules.llm_call"]], "ldp.graph.modules.react module": [[6, "module-ldp.graph.modules.react"]], "ldp.graph.modules.reflect module": [[6, "module-ldp.graph.modules.reflect"]], "ldp.graph.modules.thought module": [[6, "module-ldp.graph.modules.thought"]], "ldp.graph.op_utils module": [[5, "module-ldp.graph.op_utils"]], "ldp.graph.ops module": [[5, "module-ldp.graph.ops"]], "ldp.graph.torch_ops module": [[5, "module-ldp.graph.torch_ops"]], "ldp.llms package": [[7, "ldp-llms-package"]], "ldp.llms.chat module": [[7, "module-ldp.llms.chat"]], "ldp.llms.embeddings module": [[7, "module-ldp.llms.embeddings"]], "ldp.llms.prompts module": [[7, "module-ldp.llms.prompts"]], "ldp.main module": [[1, "module-ldp.main"]], "ldp.shims module": [[1, "module-ldp.shims"]], "ldp.utils module": [[1, "module-ldp.utils"]]}, "docnames": ["index", "ldp", "ldp.agent", "ldp.alg", "ldp.alg.optimizer", "ldp.graph", "ldp.graph.modules", "ldp.llms", "modules"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1}, "filenames": ["index.rst", "ldp.rst", "ldp.agent.rst", "ldp.alg.rst", "ldp.alg.optimizer.rst", "ldp.graph.rst", "ldp.graph.modules.rst", "ldp.llms.rst", "modules.rst"], "indexentries": {"achat() (ldp.llms.chat.multiplecompletionllmmodel method)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.achat", false]], "achat() (ldp.llms.multiplecompletionllmmodel method)": [[7, "ldp.llms.MultipleCompletionLLMModel.achat", false]], "achat_iter() (ldp.llms.chat.multiplecompletionllmmodel method)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.achat_iter", false]], "achat_iter() (ldp.llms.multiplecompletionllmmodel method)": [[7, "ldp.llms.MultipleCompletionLLMModel.achat_iter", false]], "action (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.action", false]], "add_memory() (ldp.graph.memory.memorymodel method)": [[5, "id16", false], [5, "ldp.graph.memory.MemoryModel.add_memory", false]], "add_memory() (ldp.graph.memorymodel method)": [[5, "ldp.graph.MemoryModel.add_memory", false]], "add_transition() (ldp.data_structures.transitiontree method)": [[1, "ldp.data_structures.TransitionTree.add_transition", false]], "after_agent_get_asv() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_agent_get_asv", false]], "after_agent_get_asv() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_agent_get_asv", false]], "after_agent_get_asv() (ldp.alg.callbacks.rolloutdebugdumpcallback method)": [[3, "ldp.alg.callbacks.RolloutDebugDumpCallback.after_agent_get_asv", false]], "after_agent_get_asv() (ldp.alg.callbacks.terminalprintingcallback method)": [[3, "ldp.alg.callbacks.TerminalPrintingCallback.after_agent_get_asv", false]], "after_agent_get_asv() (ldp.alg.rolloutdebugdumpcallback method)": [[3, "ldp.alg.RolloutDebugDumpCallback.after_agent_get_asv", false]], "after_agent_init_state() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_agent_init_state", false]], "after_agent_init_state() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_agent_init_state", false]], "after_env_reset() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_env_reset", false]], "after_env_reset() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_env_reset", false]], "after_env_reset() (ldp.alg.callbacks.trajectorymetricscallback method)": [[3, "ldp.alg.callbacks.TrajectoryMetricsCallback.after_env_reset", false]], "after_env_reset() (ldp.alg.trajectorymetricscallback method)": [[3, "ldp.alg.TrajectoryMetricsCallback.after_env_reset", false]], "after_env_step() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_env_step", false]], "after_env_step() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_env_step", false]], "after_env_step() (ldp.alg.callbacks.rolloutdebugdumpcallback method)": [[3, "ldp.alg.callbacks.RolloutDebugDumpCallback.after_env_step", false]], "after_env_step() (ldp.alg.callbacks.terminalprintingcallback method)": [[3, "ldp.alg.callbacks.TerminalPrintingCallback.after_env_step", false]], "after_env_step() (ldp.alg.rolloutdebugdumpcallback method)": [[3, "ldp.alg.RolloutDebugDumpCallback.after_env_step", false]], "after_eval_loop() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.callbacks.loggingcallback method)": [[3, "ldp.alg.callbacks.LoggingCallback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.callbacks.meanmetricscallback method)": [[3, "ldp.alg.callbacks.MeanMetricsCallback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.callbacks.trajectorymetricscallback method)": [[3, "ldp.alg.callbacks.TrajectoryMetricsCallback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.callbacks.wandbloggingcallback method)": [[3, "ldp.alg.callbacks.WandBLoggingCallback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.loggingcallback method)": [[3, "ldp.alg.LoggingCallback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.meanmetricscallback method)": [[3, "ldp.alg.MeanMetricsCallback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.trajectorymetricscallback method)": [[3, "ldp.alg.TrajectoryMetricsCallback.after_eval_loop", false]], "after_eval_loop() (ldp.alg.wandbloggingcallback method)": [[3, "ldp.alg.WandBLoggingCallback.after_eval_loop", false]], "after_eval_step() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_eval_step", false]], "after_eval_step() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_eval_step", false]], "after_eval_step() (ldp.alg.callbacks.clearcontextcallback method)": [[3, "ldp.alg.callbacks.ClearContextCallback.after_eval_step", false]], "after_eval_step() (ldp.alg.callbacks.trajectorymetricscallback method)": [[3, "ldp.alg.callbacks.TrajectoryMetricsCallback.after_eval_step", false]], "after_eval_step() (ldp.alg.clearcontextcallback method)": [[3, "ldp.alg.ClearContextCallback.after_eval_step", false]], "after_eval_step() (ldp.alg.trajectorymetricscallback method)": [[3, "ldp.alg.TrajectoryMetricsCallback.after_eval_step", false]], "after_retry_failure_log() (ldp.agent.react_agent.reactagent static method)": [[2, "ldp.agent.react_agent.ReActAgent.after_retry_failure_log", false]], "after_retry_failure_log() (ldp.agent.reactagent static method)": [[2, "ldp.agent.ReActAgent.after_retry_failure_log", false]], "after_train_step() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_train_step", false]], "after_train_step() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_train_step", false]], "after_train_step() (ldp.alg.callbacks.loggingcallback method)": [[3, "ldp.alg.callbacks.LoggingCallback.after_train_step", false]], "after_train_step() (ldp.alg.callbacks.meanmetricscallback method)": [[3, "ldp.alg.callbacks.MeanMetricsCallback.after_train_step", false]], "after_train_step() (ldp.alg.callbacks.trajectorymetricscallback method)": [[3, "ldp.alg.callbacks.TrajectoryMetricsCallback.after_train_step", false]], "after_train_step() (ldp.alg.callbacks.wandbloggingcallback method)": [[3, "ldp.alg.callbacks.WandBLoggingCallback.after_train_step", false]], "after_train_step() (ldp.alg.loggingcallback method)": [[3, "ldp.alg.LoggingCallback.after_train_step", false]], "after_train_step() (ldp.alg.meanmetricscallback method)": [[3, "ldp.alg.MeanMetricsCallback.after_train_step", false]], "after_train_step() (ldp.alg.trajectorymetricscallback method)": [[3, "ldp.alg.TrajectoryMetricsCallback.after_train_step", false]], "after_train_step() (ldp.alg.wandbloggingcallback method)": [[3, "ldp.alg.WandBLoggingCallback.after_train_step", false]], "after_transition() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_transition", false]], "after_transition() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_transition", false]], "after_transition() (ldp.alg.callbacks.trajectoryfilecallback method)": [[3, "ldp.alg.callbacks.TrajectoryFileCallback.after_transition", false]], "after_transition() (ldp.alg.trajectoryfilecallback method)": [[3, "ldp.alg.TrajectoryFileCallback.after_transition", false]], "after_update() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.after_update", false]], "after_update() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.after_update", false]], "after_update() (ldp.alg.callbacks.clearcontextcallback method)": [[3, "ldp.alg.callbacks.ClearContextCallback.after_update", false]], "after_update() (ldp.alg.clearcontextcallback method)": [[3, "ldp.alg.ClearContextCallback.after_update", false]], "agent (class in ldp.agent)": [[2, "ldp.agent.Agent", false]], "agent (class in ldp.agent.agent)": [[2, "ldp.agent.agent.Agent", false]], "agent_kwargs (ldp.agent.agent.agentconfig attribute)": [[2, "ldp.agent.agent.AgentConfig.agent_kwargs", false]], "agent_kwargs (ldp.agent.agentconfig attribute)": [[2, "ldp.agent.AgentConfig.agent_kwargs", false]], "agent_state (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.agent_state", false]], "agent_type (ldp.agent.agent.agentconfig attribute)": [[2, "ldp.agent.agent.AgentConfig.agent_type", false]], "agent_type (ldp.agent.agentconfig attribute)": [[2, "ldp.agent.AgentConfig.agent_type", false]], "agentconfig (class in ldp.agent)": [[2, "ldp.agent.AgentConfig", false]], "agentconfig (class in ldp.agent.agent)": [[2, "ldp.agent.agent.AgentConfig", false]], "agenterror": [[3, "ldp.alg.rollout.AgentError", false]], "aggregate() (ldp.alg.optimizer.chainedoptimizer method)": [[4, "ldp.alg.optimizer.ChainedOptimizer.aggregate", false]], "aggregate() (ldp.alg.optimizer.opt.chainedoptimizer method)": [[4, "ldp.alg.optimizer.opt.ChainedOptimizer.aggregate", false]], "aggregate() (ldp.alg.optimizer.opt.optimizer method)": [[4, "ldp.alg.optimizer.opt.Optimizer.aggregate", false]], "aggregate() (ldp.alg.optimizer.optimizer method)": [[4, "ldp.alg.optimizer.Optimizer.aggregate", false]], "aggregate_trajectory() (ldp.alg.optimizer.ape.apeopt method)": [[4, "ldp.alg.optimizer.ape.APEOpt.aggregate_trajectory", false]], "aggregate_trajectory() (ldp.alg.optimizer.apeopt method)": [[4, "ldp.alg.optimizer.APEOpt.aggregate_trajectory", false]], "aggregate_trajectory() (ldp.alg.optimizer.memory.memoryopt method)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.aggregate_trajectory", false]], "aggregate_trajectory() (ldp.alg.optimizer.memoryopt method)": [[4, "ldp.alg.optimizer.MemoryOpt.aggregate_trajectory", false]], "aggregate_trajectory() (ldp.alg.optimizer.opt.optimizer method)": [[4, "ldp.alg.optimizer.opt.Optimizer.aggregate_trajectory", false]], "aggregate_trajectory() (ldp.alg.optimizer.optimizer method)": [[4, "ldp.alg.optimizer.Optimizer.aggregate_trajectory", false]], "apeopt (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.APEOpt", false]], "apeopt (class in ldp.alg.optimizer.ape)": [[4, "ldp.alg.optimizer.ape.APEOpt", false]], "apescorefn (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.APEScoreFn", false]], "apescorefn (class in ldp.alg.optimizer.ape)": [[4, "ldp.alg.optimizer.ape.APEScoreFn", false]], "append_to_messages() (in module ldp.llms)": [[7, "ldp.llms.append_to_messages", false]], "append_to_messages() (in module ldp.llms.prompts)": [[7, "ldp.llms.prompts.append_to_messages", false]], "append_to_sys() (in module ldp.llms)": [[7, "ldp.llms.append_to_sys", false]], "append_to_sys() (in module ldp.llms.prompts)": [[7, "ldp.llms.prompts.append_to_sys", false]], "assign_constant_grads() (in module ldp.graph.gradient_estimators)": [[5, "ldp.graph.gradient_estimators.assign_constant_grads", false]], "assign_default_grads() (in module ldp.graph.gradient_estimators)": [[5, "ldp.graph.gradient_estimators.assign_default_grads", false]], "assign_mc_value_estimates() (ldp.data_structures.transitiontree method)": [[1, "ldp.data_structures.TransitionTree.assign_mc_value_estimates", false]], "async_cache() (in module ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.async_cache", false]], "async_protect_torch_call() (in module ldp.graph.async_torch)": [[5, "ldp.graph.async_torch.async_protect_torch_call", false]], "asynctorchmodule (class in ldp.graph.async_torch)": [[5, "ldp.graph.async_torch.AsyncTorchModule", false]], "backward() (ldp.graph.common_ops.configop class method)": [[5, "ldp.graph.common_ops.ConfigOp.backward", false]], "backward() (ldp.graph.common_ops.embeddingop class method)": [[5, "ldp.graph.common_ops.EmbeddingOp.backward", false]], "backward() (ldp.graph.common_ops.fxnop class method)": [[5, "ldp.graph.common_ops.FxnOp.backward", false]], "backward() (ldp.graph.common_ops.identityop class method)": [[5, "ldp.graph.common_ops.IdentityOp.backward", false]], "backward() (ldp.graph.common_ops.llmcallop class method)": [[5, "ldp.graph.common_ops.LLMCallOp.backward", false]], "backward() (ldp.graph.common_ops.memoryop class method)": [[5, "ldp.graph.common_ops.MemoryOp.backward", false]], "backward() (ldp.graph.common_ops.stopgradop class method)": [[5, "ldp.graph.common_ops.StopGradOp.backward", false]], "backward() (ldp.graph.configop class method)": [[5, "ldp.graph.ConfigOp.backward", false]], "backward() (ldp.graph.embeddingop class method)": [[5, "ldp.graph.EmbeddingOp.backward", false]], "backward() (ldp.graph.fxnop class method)": [[5, "ldp.graph.FxnOp.backward", false]], "backward() (ldp.graph.gradient_estimators.torchparambackwardestimator method)": [[5, "ldp.graph.gradient_estimators.TorchParamBackwardEstimator.backward", false]], "backward() (ldp.graph.identityop class method)": [[5, "ldp.graph.IdentityOp.backward", false]], "backward() (ldp.graph.llmcallop class method)": [[5, "ldp.graph.LLMCallOp.backward", false]], "backward() (ldp.graph.loss_ops.mselossop class method)": [[5, "ldp.graph.loss_ops.MSELossOp.backward", false]], "backward() (ldp.graph.memoryop class method)": [[5, "ldp.graph.MemoryOp.backward", false]], "backward() (ldp.graph.mselossop class method)": [[5, "ldp.graph.MSELossOp.backward", false]], "backward() (ldp.graph.op class method)": [[5, "ldp.graph.Op.backward", false]], "backward() (ldp.graph.ops.op class method)": [[5, "ldp.graph.ops.Op.backward", false]], "backward() (ldp.graph.torch_ops.torchop class method)": [[5, "ldp.graph.torch_ops.TorchOp.backward", false]], "batch_size (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.batch_size", false]], "batch_size (ldp.alg.offlinetrainerconfig attribute)": [[3, "ldp.alg.OfflineTrainerConfig.batch_size", false]], "batch_size (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.batch_size", false]], "batch_size (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.batch_size", false]], "batch_size (ldp.alg.runners.offlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OfflineTrainerConfig.batch_size", false]], "batch_size (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.batch_size", false]], "batch_size (ldp.llms.embeddings.liteembeddingmodel attribute)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.batch_size", false]], "batch_size (ldp.llms.liteembeddingmodel attribute)": [[7, "ldp.llms.LiteEmbeddingModel.batch_size", false]], "batched_iter() (ldp.alg.optimizer.replay_buffers.circularreplaybuffer method)": [[4, "ldp.alg.optimizer.replay_buffers.CircularReplayBuffer.batched_iter", false]], "beam (class in ldp.alg)": [[3, "ldp.alg.Beam", false]], "beam (class in ldp.alg.beam_search)": [[3, "ldp.alg.beam_search.Beam", false]], "beamsearchrollout (class in ldp.alg)": [[3, "ldp.alg.BeamSearchRollout", false]], "beamsearchrollout (class in ldp.alg.beam_search)": [[3, "ldp.alg.beam_search.BeamSearchRollout", false]], "before_eval_loop() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.before_eval_loop", false]], "before_eval_loop() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.before_eval_loop", false]], "before_transition() (ldp.alg.callback method)": [[3, "ldp.alg.Callback.before_transition", false]], "before_transition() (ldp.alg.callbacks.callback method)": [[3, "ldp.alg.callbacks.Callback.before_transition", false]], "before_transition() (ldp.alg.callbacks.rolloutdebugdumpcallback method)": [[3, "ldp.alg.callbacks.RolloutDebugDumpCallback.before_transition", false]], "before_transition() (ldp.alg.callbacks.terminalprintingcallback method)": [[3, "ldp.alg.callbacks.TerminalPrintingCallback.before_transition", false]], "before_transition() (ldp.alg.callbacks.trajectoryfilecallback method)": [[3, "ldp.alg.callbacks.TrajectoryFileCallback.before_transition", false]], "before_transition() (ldp.alg.rolloutdebugdumpcallback method)": [[3, "ldp.alg.RolloutDebugDumpCallback.before_transition", false]], "before_transition() (ldp.alg.trajectoryfilecallback method)": [[3, "ldp.alg.TrajectoryFileCallback.before_transition", false]], "cacheable (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.Cacheable", false]], "call() (ldp.llms.chat.llmmodel method)": [[7, "ldp.llms.chat.LLMModel.call", false]], "call() (ldp.llms.chat.multiplecompletionllmmodel method)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.call", false]], "call() (ldp.llms.llmmodel method)": [[7, "ldp.llms.LLMModel.call", false]], "call() (ldp.llms.multiplecompletionllmmodel method)": [[7, "ldp.llms.MultipleCompletionLLMModel.call", false]], "callback (class in ldp.alg)": [[3, "ldp.alg.Callback", false]], "callback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.Callback", false]], "callid (class in ldp.graph)": [[5, "ldp.graph.CallID", false]], "callid (class in ldp.graph.op_utils)": [[5, "ldp.graph.op_utils.CallID", false]], "catch_agent_failures (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.catch_agent_failures", false]], "catch_agent_failures (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.catch_agent_failures", false]], "catch_agent_failures (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.catch_agent_failures", false]], "catch_env_failures (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.catch_env_failures", false]], "catch_env_failures (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.catch_env_failures", false]], "catch_env_failures (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.catch_env_failures", false]], "caughterror": [[3, "ldp.alg.rollout.CaughtError", false]], "chainedoptimizer (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.ChainedOptimizer", false]], "chainedoptimizer (class in ldp.alg.optimizer.opt)": [[4, "ldp.alg.optimizer.opt.ChainedOptimizer", false]], "circularreplaybuffer (class in ldp.alg.optimizer.replay_buffers)": [[4, "ldp.alg.optimizer.replay_buffers.CircularReplayBuffer", false]], "cleanup() (ldp.alg.callbacks.trajectoryfilecallback method)": [[3, "ldp.alg.callbacks.TrajectoryFileCallback.cleanup", false]], "cleanup() (ldp.alg.trajectoryfilecallback method)": [[3, "ldp.alg.TrajectoryFileCallback.cleanup", false]], "clear() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.clear", false]], "clear_contexts() (ldp.graph.opctx class method)": [[5, "ldp.graph.OpCtx.clear_contexts", false]], "clear_contexts() (ldp.graph.ops.opctx class method)": [[5, "ldp.graph.ops.OpCtx.clear_contexts", false]], "clear_ctx() (ldp.graph.op method)": [[5, "ldp.graph.Op.clear_ctx", false]], "clear_ctx() (ldp.graph.ops.op method)": [[5, "ldp.graph.ops.Op.clear_ctx", false]], "clear_ctx_at_each_iter (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.clear_ctx_at_each_iter", false]], "clear_ctx_at_each_iter (ldp.alg.offlinetrainerconfig attribute)": [[3, "ldp.alg.OfflineTrainerConfig.clear_ctx_at_each_iter", false]], "clear_ctx_at_each_iter (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.clear_ctx_at_each_iter", false]], "clear_ctx_at_each_iter (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.clear_ctx_at_each_iter", false]], "clear_ctx_at_each_iter (ldp.alg.runners.offlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OfflineTrainerConfig.clear_ctx_at_each_iter", false]], "clear_ctx_at_each_iter (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.clear_ctx_at_each_iter", false]], "clearcontextcallback (class in ldp.alg)": [[3, "ldp.alg.ClearContextCallback", false]], "clearcontextcallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.ClearContextCallback", false]], "close() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.close", false]], "completion_count (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.completion_count", false]], "completion_count (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.completion_count", false]], "compute_discounted_returns() (ldp.data_structures.trajectory method)": [[1, "ldp.data_structures.Trajectory.compute_discounted_returns", false]], "compute_grads() (ldp.graph.opresult method)": [[5, "ldp.graph.OpResult.compute_grads", false]], "compute_grads() (ldp.graph.ops.opresult method)": [[5, "ldp.graph.ops.OpResult.compute_grads", false]], "compute_graph() (in module ldp.graph)": [[5, "ldp.graph.compute_graph", false]], "compute_graph() (in module ldp.graph.op_utils)": [[5, "ldp.graph.op_utils.compute_graph", false]], "compute_logprob() (ldp.graph.common_ops.llmcallop method)": [[5, "ldp.graph.common_ops.LLMCallOp.compute_logprob", false]], "compute_logprob() (ldp.graph.llmcallop method)": [[5, "ldp.graph.LLMCallOp.compute_logprob", false]], "compute_trajectory_metrics() (ldp.alg.callbacks.computetrajectorymetricsmixin method)": [[3, "ldp.alg.callbacks.ComputeTrajectoryMetricsMixin.compute_trajectory_metrics", false]], "compute_trajectory_metrics() (ldp.alg.computetrajectorymetricsmixin method)": [[3, "ldp.alg.ComputeTrajectoryMetricsMixin.compute_trajectory_metrics", false]], "computetrajectorymetricsmixin (class in ldp.alg)": [[3, "ldp.alg.ComputeTrajectoryMetricsMixin", false]], "computetrajectorymetricsmixin (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.ComputeTrajectoryMetricsMixin", false]], "config (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.config", false]], "config (ldp.llms.chat.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.config", false]], "config (ldp.llms.llmmodel attribute)": [[7, "ldp.llms.LLMModel.config", false]], "config (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.config", false]], "config (ldp.llms.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.MultipleCompletionLLMModel.config", false]], "configop (class in ldp.graph)": [[5, "ldp.graph.ConfigOp", false]], "configop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.ConfigOp", false]], "configure_log_levels() (in module ldp.utils)": [[1, "ldp.utils.configure_log_levels", false]], "configure_stdout_logs() (in module ldp.utils)": [[1, "ldp.utils.configure_stdout_logs", false]], "construct_action() (ldp.data_structures.transition class method)": [[1, "ldp.data_structures.Transition.construct_action", false]], "construct_agent() (ldp.agent.agent.agentconfig method)": [[2, "ldp.agent.agent.AgentConfig.construct_agent", false]], "construct_agent() (ldp.agent.agentconfig method)": [[2, "ldp.agent.AgentConfig.construct_agent", false]], "ctx (ldp.graph.op attribute)": [[5, "ldp.graph.Op.ctx", false]], "ctx (ldp.graph.opresult property)": [[5, "ldp.graph.OpResult.ctx", false]], "ctx (ldp.graph.ops.op attribute)": [[5, "ldp.graph.ops.Op.ctx", false]], "ctx (ldp.graph.ops.opresult property)": [[5, "ldp.graph.ops.OpResult.ctx", false]], "ctx_tensor_input_key (ldp.graph.torch_ops.torchop attribute)": [[5, "ldp.graph.torch_ops.TorchOp.CTX_TENSOR_INPUT_KEY", false]], "data (ldp.graph.opctx attribute)": [[5, "ldp.graph.OpCtx.data", false]], "data (ldp.graph.ops.opctx attribute)": [[5, "ldp.graph.ops.OpCtx.data", false]], "date (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.date", false]], "date (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.date", false]], "default_memory_factory() (ldp.alg.optimizer.memory.memoryopt method)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.default_memory_factory", false]], "default_memory_factory() (ldp.alg.optimizer.memoryopt method)": [[4, "ldp.alg.optimizer.MemoryOpt.default_memory_factory", false]], "default_memory_matches (ldp.graph.memory.memorymodel attribute)": [[5, "id15", false], [5, "ldp.graph.memory.MemoryModel.DEFAULT_MEMORY_MATCHES", false]], "default_memory_matches (ldp.graph.memorymodel attribute)": [[5, "ldp.graph.MemoryModel.DEFAULT_MEMORY_MATCHES", false]], "default_optimizer_factory() (in module ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.default_optimizer_factory", false]], "default_query_factory() (ldp.agent.memory_agent.memoryagent method)": [[2, "ldp.agent.memory_agent.MemoryAgent.default_query_factory", false]], "default_query_factory() (ldp.agent.memoryagent method)": [[2, "ldp.agent.MemoryAgent.default_query_factory", false]], "defaultllmmodelnames (class in ldp.agent)": [[2, "ldp.agent.DefaultLLMModelNames", false]], "dimensions (ldp.llms.embeddingmodel attribute)": [[7, "ldp.llms.EmbeddingModel.dimensions", false]], "dimensions (ldp.llms.embeddings.embeddingmodel attribute)": [[7, "ldp.llms.embeddings.EmbeddingModel.dimensions", false]], "dimensions (ldp.llms.embeddings.liteembeddingmodel attribute)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.dimensions", false]], "dimensions (ldp.llms.embeddings.sparseembeddingmodel attribute)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel.dimensions", false]], "dimensions (ldp.llms.hybridembeddingmodel attribute)": [[7, "ldp.llms.HybridEmbeddingModel.dimensions", false]], "dimensions (ldp.llms.liteembeddingmodel attribute)": [[7, "ldp.llms.LiteEmbeddingModel.dimensions", false]], "dimensions (ldp.llms.sparseembeddingmodel attribute)": [[7, "ldp.llms.SparseEmbeddingModel.dimensions", false]], "discounted_returns() (in module ldp.utils)": [[1, "ldp.utils.discounted_returns", false]], "display() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.display", false]], "document (ldp.llms.embeddingmodes attribute)": [[7, "ldp.llms.EmbeddingModes.DOCUMENT", false]], "document (ldp.llms.embeddings.embeddingmodes attribute)": [[7, "ldp.llms.embeddings.EmbeddingModes.DOCUMENT", false]], "done (ldp.data_structures.trajectory property)": [[1, "ldp.data_structures.Trajectory.done", false]], "done (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.done", false]], "dummytaskdataset (class in ldp.alg.datasets)": [[3, "ldp.alg.datasets.DummyTaskDataset", false]], "embed_kwargs (ldp.llms.embeddings.liteembeddingmodel attribute)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.embed_kwargs", false]], "embed_kwargs (ldp.llms.liteembeddingmodel attribute)": [[7, "ldp.llms.LiteEmbeddingModel.embed_kwargs", false]], "embed_text() (ldp.llms.embeddingmodel method)": [[7, "ldp.llms.EmbeddingModel.embed_text", false]], "embed_text() (ldp.llms.embeddings.embeddingmodel method)": [[7, "ldp.llms.embeddings.EmbeddingModel.embed_text", false]], "embed_texts() (ldp.llms.embeddingmodel method)": [[7, "ldp.llms.EmbeddingModel.embed_texts", false]], "embed_texts() (ldp.llms.embeddings.embeddingmodel method)": [[7, "ldp.llms.embeddings.EmbeddingModel.embed_texts", false]], "embed_texts() (ldp.llms.embeddings.hybridembeddingmodel method)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel.embed_texts", false]], "embed_texts() (ldp.llms.embeddings.liteembeddingmodel method)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.embed_texts", false]], "embed_texts() (ldp.llms.embeddings.sparseembeddingmodel method)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel.embed_texts", false]], "embed_texts() (ldp.llms.hybridembeddingmodel method)": [[7, "ldp.llms.HybridEmbeddingModel.embed_texts", false]], "embed_texts() (ldp.llms.liteembeddingmodel method)": [[7, "ldp.llms.LiteEmbeddingModel.embed_texts", false]], "embed_texts() (ldp.llms.sparseembeddingmodel method)": [[7, "ldp.llms.SparseEmbeddingModel.embed_texts", false]], "embedding_model (ldp.graph.memory.memorymodel attribute)": [[5, "id17", false], [5, "ldp.graph.memory.MemoryModel.embedding_model", false]], "embedding_model (ldp.graph.memorymodel attribute)": [[5, "ldp.graph.MemoryModel.embedding_model", false]], "embeddingmodel (class in ldp.llms)": [[7, "ldp.llms.EmbeddingModel", false]], "embeddingmodel (class in ldp.llms.embeddings)": [[7, "ldp.llms.embeddings.EmbeddingModel", false]], "embeddingmodes (class in ldp.llms)": [[7, "ldp.llms.EmbeddingModes", false]], "embeddingmodes (class in ldp.llms.embeddings)": [[7, "ldp.llms.embeddings.EmbeddingModes", false]], "embeddingop (class in ldp.graph)": [[5, "ldp.graph.EmbeddingOp", false]], "embeddingop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.EmbeddingOp", false]], "enc (ldp.llms.embeddings.sparseembeddingmodel attribute)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel.enc", false]], "enc (ldp.llms.sparseembeddingmodel attribute)": [[7, "ldp.llms.SparseEmbeddingModel.enc", false]], "encoding (ldp.llms.chat.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.encoding", false]], "encoding (ldp.llms.llmmodel attribute)": [[7, "ldp.llms.LLMModel.encoding", false]], "encoding (ldp.llms.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.MultipleCompletionLLMModel.encoding", false]], "enforce_empty() (ldp.graph.memory.memorymodel class method)": [[5, "id18", false], [5, "ldp.graph.memory.MemoryModel.enforce_empty", false]], "enforce_empty() (ldp.graph.memorymodel class method)": [[5, "ldp.graph.MemoryModel.enforce_empty", false]], "ensure_query() (ldp.graph.memory class method)": [[5, "ldp.graph.Memory.ensure_query", false]], "ensure_query() (ldp.graph.memory.memory class method)": [[5, "ldp.graph.memory.Memory.ensure_query", false]], "env (ldp.alg.beam attribute)": [[3, "ldp.alg.Beam.env", false]], "env (ldp.alg.beam_search.beam attribute)": [[3, "ldp.alg.beam_search.Beam.env", false]], "enverror": [[3, "ldp.alg.rollout.EnvError", false]], "eval_before (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.eval_before", false]], "eval_before (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.eval_before", false]], "eval_every (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.eval_every", false]], "eval_every (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.eval_every", false]], "eval_means (ldp.alg.callbacks.meanmetricscallback property)": [[3, "ldp.alg.callbacks.MeanMetricsCallback.eval_means", false]], "eval_means (ldp.alg.meanmetricscallback property)": [[3, "ldp.alg.MeanMetricsCallback.eval_means", false]], "evaluate() (ldp.alg.evaluator method)": [[3, "ldp.alg.Evaluator.evaluate", false]], "evaluate() (ldp.alg.onlinetrainer method)": [[3, "ldp.alg.OnlineTrainer.evaluate", false]], "evaluate() (ldp.alg.runners.evaluator method)": [[3, "ldp.alg.runners.Evaluator.evaluate", false]], "evaluate() (ldp.alg.runners.onlinetrainer method)": [[3, "ldp.alg.runners.OnlineTrainer.evaluate", false]], "evaluator (class in ldp.alg)": [[3, "ldp.alg.Evaluator", false]], "evaluator (class in ldp.alg.runners)": [[3, "ldp.alg.runners.Evaluator", false]], "evaluatorconfig (class in ldp.alg)": [[3, "ldp.alg.EvaluatorConfig", false]], "evaluatorconfig (class in ldp.alg.runners)": [[3, "ldp.alg.runners.EvaluatorConfig", false]], "example (class in ldp.alg.optimizer.ape)": [[4, "ldp.alg.optimizer.ape.Example", false]], "example_buffer (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.example_buffer", false]], "example_buffer (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.example_buffer", false]], "example_buffer (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.example_buffer", false]], "examples (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.examples", false]], "examples (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.examples", false]], "exc_type (ldp.alg.rollout.agenterror attribute)": [[3, "ldp.alg.rollout.AgentError.exc_type", false]], "exc_type (ldp.alg.rollout.caughterror attribute)": [[3, "ldp.alg.rollout.CaughtError.exc_type", false]], "exc_type (ldp.alg.rollout.enverror attribute)": [[3, "ldp.alg.rollout.EnvError.exc_type", false]], "external_write_mode() (ldp.shims.tqdm class method)": [[1, "ldp.shims.tqdm.external_write_mode", false]], "failed (ldp.data_structures.trajectory property)": [[1, "ldp.data_structures.Trajectory.failed", false]], "failed (ldp.data_structures.transition property)": [[1, "ldp.data_structures.Transition.failed", false]], "format_dict (ldp.shims.tqdm property)": [[1, "ldp.shims.tqdm.format_dict", false]], "format_interval() (ldp.shims.tqdm static method)": [[1, "ldp.shims.tqdm.format_interval", false]], "format_meter() (ldp.shims.tqdm static method)": [[1, "ldp.shims.tqdm.format_meter", false]], "format_num() (ldp.shims.tqdm static method)": [[1, "ldp.shims.tqdm.format_num", false]], "format_sizeof() (ldp.shims.tqdm static method)": [[1, "ldp.shims.tqdm.format_sizeof", false]], "forward() (ldp.graph.common_ops.configop method)": [[5, "ldp.graph.common_ops.ConfigOp.forward", false]], "forward() (ldp.graph.common_ops.embeddingop method)": [[5, "ldp.graph.common_ops.EmbeddingOp.forward", false]], "forward() (ldp.graph.common_ops.fxnop method)": [[5, "ldp.graph.common_ops.FxnOp.forward", false]], "forward() (ldp.graph.common_ops.identityop method)": [[5, "ldp.graph.common_ops.IdentityOp.forward", false]], "forward() (ldp.graph.common_ops.llmcallop method)": [[5, "ldp.graph.common_ops.LLMCallOp.forward", false]], "forward() (ldp.graph.common_ops.memoryop method)": [[5, "ldp.graph.common_ops.MemoryOp.forward", false]], "forward() (ldp.graph.configop method)": [[5, "ldp.graph.ConfigOp.forward", false]], "forward() (ldp.graph.embeddingop method)": [[5, "ldp.graph.EmbeddingOp.forward", false]], "forward() (ldp.graph.fxnop method)": [[5, "ldp.graph.FxnOp.forward", false]], "forward() (ldp.graph.identityop method)": [[5, "ldp.graph.IdentityOp.forward", false]], "forward() (ldp.graph.llmcallop method)": [[5, "ldp.graph.LLMCallOp.forward", false]], "forward() (ldp.graph.loss_ops.mselossop method)": [[5, "ldp.graph.loss_ops.MSELossOp.forward", false]], "forward() (ldp.graph.memoryop method)": [[5, "ldp.graph.MemoryOp.forward", false]], "forward() (ldp.graph.mselossop method)": [[5, "ldp.graph.MSELossOp.forward", false]], "forward() (ldp.graph.op method)": [[5, "ldp.graph.Op.forward", false]], "forward() (ldp.graph.ops.op method)": [[5, "ldp.graph.ops.Op.forward", false]], "forward() (ldp.graph.torch_ops.torchop method)": [[5, "ldp.graph.torch_ops.TorchOp.forward", false]], "from_agent() (ldp.alg.optimizer.ape.apeopt class method)": [[4, "ldp.alg.optimizer.ape.APEOpt.from_agent", false]], "from_agent() (ldp.alg.optimizer.apeopt class method)": [[4, "ldp.alg.optimizer.APEOpt.from_agent", false]], "from_agent() (ldp.alg.optimizer.memory.memoryopt class method)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.from_agent", false]], "from_agent() (ldp.alg.optimizer.memoryopt class method)": [[4, "ldp.alg.optimizer.MemoryOpt.from_agent", false]], "from_dict() (ldp.graph.opresult class method)": [[5, "ldp.graph.OpResult.from_dict", false]], "from_dict() (ldp.graph.ops.opresult class method)": [[5, "ldp.graph.ops.OpResult.from_dict", false]], "from_jsonl() (ldp.data_structures.trajectory class method)": [[1, "ldp.data_structures.Trajectory.from_jsonl", false]], "from_name() (ldp.agent.agent class method)": [[2, "ldp.agent.Agent.from_name", false]], "from_name() (ldp.agent.agent.agent class method)": [[2, "ldp.agent.agent.Agent.from_name", false]], "from_name() (ldp.llms.embeddingmodel static method)": [[7, "ldp.llms.EmbeddingModel.from_name", false]], "from_name() (ldp.llms.embeddings.embeddingmodel static method)": [[7, "ldp.llms.embeddings.EmbeddingModel.from_name", false]], "from_ops() (ldp.graph.memory class method)": [[5, "ldp.graph.Memory.from_ops", false]], "from_ops() (ldp.graph.memory.memory class method)": [[5, "ldp.graph.memory.Memory.from_ops", false]], "fwd_id (ldp.graph.callid attribute)": [[5, "ldp.graph.CallID.fwd_id", false]], "fwd_id (ldp.graph.op_utils.callid attribute)": [[5, "ldp.graph.op_utils.CallID.fwd_id", false]], "fxnop (class in ldp.graph)": [[5, "ldp.graph.FxnOp", false]], "fxnop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.FxnOp", false]], "get() (ldp.graph.opctx method)": [[5, "ldp.graph.OpCtx.get", false]], "get() (ldp.graph.ops.opctx method)": [[5, "ldp.graph.ops.OpCtx.get", false]], "get_asv() (ldp.agent.agent method)": [[2, "ldp.agent.Agent.get_asv", false]], "get_asv() (ldp.agent.agent.agent method)": [[2, "ldp.agent.agent.Agent.get_asv", false]], "get_asv() (ldp.agent.agent_client.httpagentclient method)": [[2, "ldp.agent.agent_client.HTTPAgentClient.get_asv", false]], "get_asv() (ldp.agent.httpagentclient method)": [[2, "ldp.agent.HTTPAgentClient.get_asv", false]], "get_asv() (ldp.agent.interactive_agent.interactiveagent method)": [[2, "ldp.agent.interactive_agent.InteractiveAgent.get_asv", false]], "get_asv() (ldp.agent.memory_agent.memoryagent method)": [[2, "ldp.agent.memory_agent.MemoryAgent.get_asv", false]], "get_asv() (ldp.agent.memoryagent method)": [[2, "ldp.agent.MemoryAgent.get_asv", false]], "get_asv() (ldp.agent.react_agent.reactagent method)": [[2, "ldp.agent.react_agent.ReActAgent.get_asv", false]], "get_asv() (ldp.agent.reactagent method)": [[2, "ldp.agent.ReActAgent.get_asv", false]], "get_asv() (ldp.agent.simple_agent.simpleagent method)": [[2, "ldp.agent.simple_agent.SimpleAgent.get_asv", false]], "get_asv() (ldp.agent.simpleagent method)": [[2, "ldp.agent.SimpleAgent.get_asv", false]], "get_asv() (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent method)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.get_asv", false]], "get_asv() (ldp.agent.treeofthoughtsagent method)": [[2, "ldp.agent.TreeofThoughtsAgent.get_asv", false]], "get_call_id() (in module ldp.graph)": [[5, "ldp.graph.get_call_id", false]], "get_call_id() (in module ldp.graph.op_utils)": [[5, "ldp.graph.op_utils.get_call_id", false]], "get_call_ids() (ldp.graph.op method)": [[5, "ldp.graph.Op.get_call_ids", false]], "get_call_ids() (ldp.graph.ops.op method)": [[5, "ldp.graph.ops.Op.get_call_ids", false]], "get_compute_graph() (ldp.graph.opresult method)": [[5, "ldp.graph.OpResult.get_compute_graph", false]], "get_compute_graph() (ldp.graph.ops.opresult method)": [[5, "ldp.graph.ops.OpResult.get_compute_graph", false]], "get_examples() (ldp.graph.common_ops.llmcallop method)": [[5, "ldp.graph.common_ops.LLMCallOp.get_examples", false]], "get_examples() (ldp.graph.llmcallop method)": [[5, "ldp.graph.LLMCallOp.get_examples", false]], "get_formatted_variables() (in module ldp.alg.optimizer.ape)": [[4, "ldp.alg.optimizer.ape.get_formatted_variables", false]], "get_input_grads() (ldp.graph.op method)": [[5, "ldp.graph.Op.get_input_grads", false]], "get_input_grads() (ldp.graph.opctx method)": [[5, "ldp.graph.OpCtx.get_input_grads", false]], "get_input_grads() (ldp.graph.ops.op method)": [[5, "ldp.graph.ops.Op.get_input_grads", false]], "get_input_grads() (ldp.graph.ops.opctx method)": [[5, "ldp.graph.ops.OpCtx.get_input_grads", false]], "get_lock() (ldp.shims.tqdm class method)": [[1, "ldp.shims.tqdm.get_lock", false]], "get_memory() (ldp.graph.memory.memorymodel method)": [[5, "id19", false], [5, "ldp.graph.memory.MemoryModel.get_memory", false]], "get_memory() (ldp.graph.memorymodel method)": [[5, "ldp.graph.MemoryModel.get_memory", false]], "get_next_state() (ldp.agent.simple_agent.simpleagentstate method)": [[2, "ldp.agent.simple_agent.SimpleAgentState.get_next_state", false]], "get_next_state() (ldp.agent.simpleagentstate method)": [[2, "ldp.agent.SimpleAgentState.get_next_state", false]], "get_or_create() (ldp.graph.opctx class method)": [[5, "ldp.graph.OpCtx.get_or_create", false]], "get_or_create() (ldp.graph.ops.opctx class method)": [[5, "ldp.graph.ops.OpCtx.get_or_create", false]], "get_or_make_agent() (in module ldp.main)": [[1, "ldp.main.get_or_make_agent", false]], "get_or_make_environment() (in module ldp.main)": [[1, "ldp.main.get_or_make_environment", false]], "get_prompt_prefix() (ldp.graph.modules.react.tooldescriptionmethods method)": [[6, "ldp.graph.modules.react.ToolDescriptionMethods.get_prompt_prefix", false]], "get_prompt_prefix() (ldp.graph.modules.tooldescriptionmethods method)": [[6, "ldp.graph.modules.ToolDescriptionMethods.get_prompt_prefix", false]], "get_result() (ldp.graph.common_ops.cacheable method)": [[5, "ldp.graph.common_ops.Cacheable.get_result", false]], "get_run_id() (in module ldp.graph)": [[5, "ldp.graph.get_run_id", false]], "get_run_id() (in module ldp.graph.op_utils)": [[5, "ldp.graph.op_utils.get_run_id", false]], "get_supported_openai_params() (ldp.llms.chat.llmresult method)": [[7, "ldp.llms.chat.LLMResult.get_supported_openai_params", false]], "get_supported_openai_params() (ldp.llms.llmresult method)": [[7, "ldp.llms.LLMResult.get_supported_openai_params", false]], "get_training_mode() (in module ldp.graph)": [[5, "ldp.graph.get_training_mode", false]], "get_training_mode() (in module ldp.graph.op_utils)": [[5, "ldp.graph.op_utils.get_training_mode", false]], "get_trajectories() (ldp.data_structures.transitiontree method)": [[1, "ldp.data_structures.TransitionTree.get_trajectories", false]], "get_transition() (ldp.data_structures.transitiontree method)": [[1, "ldp.data_structures.TransitionTree.get_transition", false]], "get_weight() (ldp.data_structures.transitiontree method)": [[1, "ldp.data_structures.TransitionTree.get_weight", false]], "good_examples (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.good_examples", false]], "good_examples (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.good_examples", false]], "good_reward_threshold (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.good_reward_threshold", false]], "good_reward_threshold (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.good_reward_threshold", false]], "grad (ldp.graph.opresult property)": [[5, "ldp.graph.OpResult.grad", false]], "grad (ldp.graph.ops.opresult property)": [[5, "ldp.graph.ops.OpResult.grad", false]], "gradient (ldp.alg.optimizer.ape.apescorefn attribute)": [[4, "ldp.alg.optimizer.ape.APEScoreFn.GRADIENT", false]], "gradient (ldp.alg.optimizer.apescorefn attribute)": [[4, "ldp.alg.optimizer.APEScoreFn.GRADIENT", false]], "httpagentclient (class in ldp.agent)": [[2, "ldp.agent.HTTPAgentClient", false]], "httpagentclient (class in ldp.agent.agent_client)": [[2, "ldp.agent.agent_client.HTTPAgentClient", false]], "hybridembeddingmodel (class in ldp.llms)": [[7, "ldp.llms.HybridEmbeddingModel", false]], "hybridembeddingmodel (class in ldp.llms.embeddings)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel", false]], "id (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.id", false]], "id (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.id", false]], "identityop (class in ldp.graph)": [[5, "ldp.graph.IdentityOp", false]], "identityop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.IdentityOp", false]], "indent_xml() (in module ldp.llms.prompts)": [[7, "ldp.llms.prompts.indent_xml", false]], "infer_dimensions() (ldp.llms.embeddings.hybridembeddingmodel class method)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel.infer_dimensions", false]], "infer_dimensions() (ldp.llms.embeddings.liteembeddingmodel class method)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.infer_dimensions", false]], "infer_dimensions() (ldp.llms.hybridembeddingmodel class method)": [[7, "ldp.llms.HybridEmbeddingModel.infer_dimensions", false]], "infer_dimensions() (ldp.llms.liteembeddingmodel class method)": [[7, "ldp.llms.LiteEmbeddingModel.infer_dimensions", false]], "init_state() (ldp.agent.agent method)": [[2, "ldp.agent.Agent.init_state", false]], "init_state() (ldp.agent.agent.agent method)": [[2, "ldp.agent.agent.Agent.init_state", false]], "init_state() (ldp.agent.agent_client.httpagentclient method)": [[2, "ldp.agent.agent_client.HTTPAgentClient.init_state", false]], "init_state() (ldp.agent.httpagentclient method)": [[2, "ldp.agent.HTTPAgentClient.init_state", false]], "init_state() (ldp.agent.interactive_agent.interactiveagent method)": [[2, "ldp.agent.interactive_agent.InteractiveAgent.init_state", false]], "init_state() (ldp.agent.react_agent.reactagent method)": [[2, "ldp.agent.react_agent.ReActAgent.init_state", false]], "init_state() (ldp.agent.reactagent method)": [[2, "ldp.agent.ReActAgent.init_state", false]], "init_state() (ldp.agent.simple_agent.simpleagent method)": [[2, "ldp.agent.simple_agent.SimpleAgent.init_state", false]], "init_state() (ldp.agent.simpleagent method)": [[2, "ldp.agent.SimpleAgent.init_state", false]], "init_state() (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent method)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.init_state", false]], "init_state() (ldp.agent.treeofthoughtsagent method)": [[2, "ldp.agent.TreeofThoughtsAgent.init_state", false]], "input (ldp.alg.optimizer.ape.example attribute)": [[4, "ldp.alg.optimizer.ape.Example.input", false]], "input (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.input", false]], "input (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.input", false]], "inputs (ldp.graph.opresult property)": [[5, "ldp.graph.OpResult.inputs", false]], "inputs (ldp.graph.ops.opresult property)": [[5, "ldp.graph.ops.OpResult.inputs", false]], "interactiveagent (class in ldp.agent.interactive_agent)": [[2, "ldp.agent.interactive_agent.InteractiveAgent", false]], "json (ldp.graph.modules.react.tooldescriptionmethods attribute)": [[6, "ldp.graph.modules.react.ToolDescriptionMethods.JSON", false]], "json (ldp.graph.modules.tooldescriptionmethods attribute)": [[6, "ldp.graph.modules.ToolDescriptionMethods.JSON", false]], "jsonschemavalidationerror": [[7, "ldp.llms.JSONSchemaValidationError", false], [7, "ldp.llms.chat.JSONSchemaValidationError", false]], "ldp": [[1, "module-ldp", false]], "ldp.agent": [[2, "module-ldp.agent", false]], "ldp.agent.agent": [[2, "module-ldp.agent.agent", false]], "ldp.agent.agent_client": [[2, "module-ldp.agent.agent_client", false]], "ldp.agent.interactive_agent": [[2, "module-ldp.agent.interactive_agent", false]], "ldp.agent.memory_agent": [[2, "module-ldp.agent.memory_agent", false]], "ldp.agent.react_agent": [[2, "module-ldp.agent.react_agent", false]], "ldp.agent.simple_agent": [[2, "module-ldp.agent.simple_agent", false]], "ldp.agent.tree_of_thoughts_agent": [[2, "module-ldp.agent.tree_of_thoughts_agent", false]], "ldp.alg": [[3, "module-ldp.alg", false]], "ldp.alg.algorithms": [[3, "module-ldp.alg.algorithms", false]], "ldp.alg.beam_search": [[3, "module-ldp.alg.beam_search", false]], "ldp.alg.callbacks": [[3, "module-ldp.alg.callbacks", false]], "ldp.alg.datasets": [[3, "module-ldp.alg.datasets", false]], "ldp.alg.optimizer": [[4, "module-ldp.alg.optimizer", false]], "ldp.alg.optimizer.ape": [[4, "module-ldp.alg.optimizer.ape", false]], "ldp.alg.optimizer.memory": [[4, "module-ldp.alg.optimizer.memory", false]], "ldp.alg.optimizer.opt": [[4, "module-ldp.alg.optimizer.opt", false]], "ldp.alg.optimizer.replay_buffers": [[4, "module-ldp.alg.optimizer.replay_buffers", false]], "ldp.alg.rollout": [[3, "module-ldp.alg.rollout", false]], "ldp.alg.runners": [[3, "module-ldp.alg.runners", false]], "ldp.alg.tree_search": [[3, "module-ldp.alg.tree_search", false]], "ldp.data_structures": [[1, "module-ldp.data_structures", false]], "ldp.graph": [[5, "module-ldp.graph", false]], "ldp.graph.async_torch": [[5, "module-ldp.graph.async_torch", false]], "ldp.graph.common_ops": [[5, "module-ldp.graph.common_ops", false]], "ldp.graph.gradient_estimators": [[5, "module-ldp.graph.gradient_estimators", false]], "ldp.graph.loss_ops": [[5, "module-ldp.graph.loss_ops", false]], "ldp.graph.memory": [[5, "module-ldp.graph.memory", false]], "ldp.graph.modules": [[6, "module-ldp.graph.modules", false]], "ldp.graph.modules.llm_call": [[6, "module-ldp.graph.modules.llm_call", false]], "ldp.graph.modules.react": [[6, "module-ldp.graph.modules.react", false]], "ldp.graph.modules.reflect": [[6, "module-ldp.graph.modules.reflect", false]], "ldp.graph.modules.thought": [[6, "module-ldp.graph.modules.thought", false]], "ldp.graph.op_utils": [[5, "module-ldp.graph.op_utils", false]], "ldp.graph.ops": [[5, "module-ldp.graph.ops", false]], "ldp.graph.torch_ops": [[5, "module-ldp.graph.torch_ops", false]], "ldp.llms": [[7, "module-ldp.llms", false]], "ldp.llms.chat": [[7, "module-ldp.llms.chat", false]], "ldp.llms.embeddings": [[7, "module-ldp.llms.embeddings", false]], "ldp.llms.prompts": [[7, "module-ldp.llms.prompts", false]], "ldp.main": [[1, "module-ldp.main", false]], "ldp.shims": [[1, "module-ldp.shims", false]], "ldp.utils": [[1, "module-ldp.utils", false]], "liteembeddingmodel (class in ldp.llms)": [[7, "ldp.llms.LiteEmbeddingModel", false]], "liteembeddingmodel (class in ldp.llms.embeddings)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel", false]], "llm (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.llm", false]], "llm (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.llm", false]], "llm_call_op (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.llm_call_op", false]], "llm_call_op (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.llm_call_op", false]], "llm_model (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.llm_model", false]], "llm_model (ldp.agent.react_agent.reactagent attribute)": [[2, "ldp.agent.react_agent.ReActAgent.llm_model", false]], "llm_model (ldp.agent.reactagent attribute)": [[2, "ldp.agent.ReActAgent.llm_model", false]], "llm_model (ldp.agent.simple_agent.simpleagent attribute)": [[2, "ldp.agent.simple_agent.SimpleAgent.llm_model", false]], "llm_model (ldp.agent.simpleagent attribute)": [[2, "ldp.agent.SimpleAgent.llm_model", false]], "llm_model (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.llm_model", false]], "llm_model (ldp.agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.TreeofThoughtsAgent.llm_model", false]], "llm_model (ldp.graph.modules.reflect.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.reflect.ReflectModuleConfig.llm_model", false]], "llm_model (ldp.graph.modules.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.ReflectModuleConfig.llm_model", false]], "llm_straight_through_estimator() (in module ldp.graph.gradient_estimators)": [[5, "ldp.graph.gradient_estimators.llm_straight_through_estimator", false]], "llmcallop (class in ldp.graph)": [[5, "ldp.graph.LLMCallOp", false]], "llmcallop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.LLMCallOp", false]], "llmmodel (class in ldp.llms)": [[7, "ldp.llms.LLMModel", false]], "llmmodel (class in ldp.llms.chat)": [[7, "ldp.llms.chat.LLMModel", false]], "llmresult (class in ldp.llms)": [[7, "ldp.llms.LLMResult", false]], "llmresult (class in ldp.llms.chat)": [[7, "ldp.llms.chat.LLMResult", false]], "loggingcallback (class in ldp.alg)": [[3, "ldp.alg.LoggingCallback", false]], "loggingcallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.LoggingCallback", false]], "logprob (ldp.graph.opresult property)": [[5, "ldp.graph.OpResult.logprob", false]], "logprob (ldp.graph.ops.opresult property)": [[5, "ldp.graph.ops.OpResult.logprob", false]], "logprob (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.logprob", false]], "logprob (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.logprob", false]], "logsumexp() (in module ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.logsumexp", false]], "main() (in module ldp.main)": [[1, "ldp.main.main", false]], "make_act_agent() (ldp.agent.react_agent.reactagent class method)": [[2, "ldp.agent.react_agent.ReActAgent.make_act_agent", false]], "make_act_agent() (ldp.agent.reactagent class method)": [[2, "ldp.agent.ReActAgent.make_act_agent", false]], "make_rollout_manager() (ldp.alg.evaluatorconfig method)": [[3, "ldp.alg.EvaluatorConfig.make_rollout_manager", false]], "make_rollout_manager() (ldp.alg.runners.evaluatorconfig method)": [[3, "ldp.alg.runners.EvaluatorConfig.make_rollout_manager", false]], "make_simple_agent_server() (in module ldp.agent)": [[2, "ldp.agent.make_simple_agent_server", false]], "make_simple_agent_server() (in module ldp.agent.agent_client)": [[2, "ldp.agent.agent_client.make_simple_agent_server", false]], "max_examples (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.max_examples", false]], "max_examples (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.max_examples", false]], "max_rollout_steps (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.max_rollout_steps", false]], "max_rollout_steps (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.max_rollout_steps", false]], "max_rollout_steps (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.max_rollout_steps", false]], "meanmetricscallback (class in ldp.alg)": [[3, "ldp.alg.MeanMetricsCallback", false]], "meanmetricscallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.MeanMetricsCallback", false]], "memories (ldp.graph.memory.memorymodel attribute)": [[5, "id20", false], [5, "ldp.graph.memory.MemoryModel.memories", false]], "memories (ldp.graph.memorymodel attribute)": [[5, "ldp.graph.MemoryModel.memories", false]], "memory (class in ldp.graph)": [[5, "ldp.graph.Memory", false]], "memory (class in ldp.graph.memory)": [[5, "ldp.graph.memory.Memory", false]], "memory_factory (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.memory_factory", false]], "memory_factory (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.memory_factory", false]], "memory_factory (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.memory_factory", false]], "memory_op (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.memory_op", false]], "memory_op (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.memory_op", false]], "memory_op (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.memory_op", false]], "memory_prompt (ldp.agent.memory_agent.memoryagent attribute)": [[2, "ldp.agent.memory_agent.MemoryAgent.memory_prompt", false]], "memory_prompt (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.memory_prompt", false]], "memory_template (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.memory_template", false]], "memory_template (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.memory_template", false]], "memory_template (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.memory_template", false]], "memoryagent (class in ldp.agent)": [[2, "ldp.agent.MemoryAgent", false]], "memoryagent (class in ldp.agent.memory_agent)": [[2, "ldp.agent.memory_agent.MemoryAgent", false]], "memoryfactory (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.MemoryFactory", false]], "memoryfactory (class in ldp.alg.optimizer.memory)": [[4, "ldp.alg.optimizer.memory.MemoryFactory", false]], "memorymodel (class in ldp.graph)": [[5, "ldp.graph.MemoryModel", false]], "memorymodel (class in ldp.graph.memory)": [[5, "id0", false], [5, "ldp.graph.memory.MemoryModel", false]], "memoryop (class in ldp.graph)": [[5, "ldp.graph.MemoryOp", false]], "memoryop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.MemoryOp", false]], "memoryopt (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.MemoryOpt", false]], "memoryopt (class in ldp.alg.optimizer.memory)": [[4, "ldp.alg.optimizer.memory.MemoryOpt", false]], "merge_identical_nodes() (ldp.data_structures.transitiontree method)": [[1, "ldp.data_structures.TransitionTree.merge_identical_nodes", false]], "messages (ldp.agent.simple_agent.simpleagentstate attribute)": [[2, "ldp.agent.simple_agent.SimpleAgentState.messages", false]], "messages (ldp.agent.simpleagentstate attribute)": [[2, "ldp.agent.SimpleAgentState.messages", false]], "messages (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.messages", false]], "messages (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.messages", false]], "metadata (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.metadata", false]], "metadata (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.metadata", false]], "metadata (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.metadata", false]], "model (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.model", false]], "model (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.model", false]], "model_computed_fields (ldp.agent.agent.agentconfig attribute)": [[2, "ldp.agent.agent.AgentConfig.model_computed_fields", false]], "model_computed_fields (ldp.agent.agentconfig attribute)": [[2, "ldp.agent.AgentConfig.model_computed_fields", false]], "model_computed_fields (ldp.agent.memory_agent.memoryagent attribute)": [[2, "ldp.agent.memory_agent.MemoryAgent.model_computed_fields", false]], "model_computed_fields (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.model_computed_fields", false]], "model_computed_fields (ldp.agent.react_agent.reactagent attribute)": [[2, "ldp.agent.react_agent.ReActAgent.model_computed_fields", false]], "model_computed_fields (ldp.agent.reactagent attribute)": [[2, "ldp.agent.ReActAgent.model_computed_fields", false]], "model_computed_fields (ldp.agent.simple_agent.simpleagent attribute)": [[2, "ldp.agent.simple_agent.SimpleAgent.model_computed_fields", false]], "model_computed_fields (ldp.agent.simple_agent.simpleagentstate attribute)": [[2, "ldp.agent.simple_agent.SimpleAgentState.model_computed_fields", false]], "model_computed_fields (ldp.agent.simpleagent attribute)": [[2, "ldp.agent.SimpleAgent.model_computed_fields", false]], "model_computed_fields (ldp.agent.simpleagentstate attribute)": [[2, "ldp.agent.SimpleAgentState.model_computed_fields", false]], "model_computed_fields (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.model_computed_fields", false]], "model_computed_fields (ldp.agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.TreeofThoughtsAgent.model_computed_fields", false]], "model_computed_fields (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.model_computed_fields", false]], "model_computed_fields (ldp.alg.offlinetrainerconfig attribute)": [[3, "ldp.alg.OfflineTrainerConfig.model_computed_fields", false]], "model_computed_fields (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.ape.example attribute)": [[4, "ldp.alg.optimizer.ape.Example.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.ape.outputprompt attribute)": [[4, "ldp.alg.optimizer.ape.OutputPrompt.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.memory.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.memory.PositiveMemoryOpt.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.optimizerconfig attribute)": [[4, "ldp.alg.optimizer.OptimizerConfig.model_computed_fields", false]], "model_computed_fields (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.model_computed_fields", false]], "model_computed_fields (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.model_computed_fields", false]], "model_computed_fields (ldp.alg.runners.offlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OfflineTrainerConfig.model_computed_fields", false]], "model_computed_fields (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.model_computed_fields", false]], "model_computed_fields (ldp.data_structures.trajectory attribute)": [[1, "ldp.data_structures.Trajectory.model_computed_fields", false]], "model_computed_fields (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.model_computed_fields", false]], "model_computed_fields (ldp.graph.callid attribute)": [[5, "ldp.graph.CallID.model_computed_fields", false]], "model_computed_fields (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.model_computed_fields", false]], "model_computed_fields (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.model_computed_fields", false]], "model_computed_fields (ldp.graph.memory.memorymodel attribute)": [[5, "id21", false], [5, "ldp.graph.memory.MemoryModel.model_computed_fields", false]], "model_computed_fields (ldp.graph.memory.uindexmemorymodel attribute)": [[5, "ldp.graph.memory.UIndexMemoryModel.model_computed_fields", false]], "model_computed_fields (ldp.graph.memorymodel attribute)": [[5, "ldp.graph.MemoryModel.model_computed_fields", false]], "model_computed_fields (ldp.graph.modules.reflect.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.reflect.ReflectModuleConfig.model_computed_fields", false]], "model_computed_fields (ldp.graph.modules.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.ReflectModuleConfig.model_computed_fields", false]], "model_computed_fields (ldp.graph.op_utils.callid attribute)": [[5, "ldp.graph.op_utils.CallID.model_computed_fields", false]], "model_computed_fields (ldp.graph.opctx attribute)": [[5, "ldp.graph.OpCtx.model_computed_fields", false]], "model_computed_fields (ldp.graph.ops.opctx attribute)": [[5, "ldp.graph.ops.OpCtx.model_computed_fields", false]], "model_computed_fields (ldp.llms.chat.llmmodel attribute)": [[7, "ldp.llms.chat.LLMModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.model_computed_fields", false]], "model_computed_fields (ldp.llms.chat.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.embeddingmodel attribute)": [[7, "ldp.llms.EmbeddingModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.embeddings.embeddingmodel attribute)": [[7, "ldp.llms.embeddings.EmbeddingModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.embeddings.hybridembeddingmodel attribute)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.embeddings.liteembeddingmodel attribute)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.embeddings.sparseembeddingmodel attribute)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.hybridembeddingmodel attribute)": [[7, "ldp.llms.HybridEmbeddingModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.liteembeddingmodel attribute)": [[7, "ldp.llms.LiteEmbeddingModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.llmmodel attribute)": [[7, "ldp.llms.LLMModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.model_computed_fields", false]], "model_computed_fields (ldp.llms.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.MultipleCompletionLLMModel.model_computed_fields", false]], "model_computed_fields (ldp.llms.sparseembeddingmodel attribute)": [[7, "ldp.llms.SparseEmbeddingModel.model_computed_fields", false]], "model_config (ldp.agent.agent.agentconfig attribute)": [[2, "ldp.agent.agent.AgentConfig.model_config", false]], "model_config (ldp.agent.agentconfig attribute)": [[2, "ldp.agent.AgentConfig.model_config", false]], "model_config (ldp.agent.memory_agent.memoryagent attribute)": [[2, "ldp.agent.memory_agent.MemoryAgent.model_config", false]], "model_config (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.model_config", false]], "model_config (ldp.agent.react_agent.reactagent attribute)": [[2, "ldp.agent.react_agent.ReActAgent.model_config", false]], "model_config (ldp.agent.reactagent attribute)": [[2, "ldp.agent.ReActAgent.model_config", false]], "model_config (ldp.agent.simple_agent.simpleagent attribute)": [[2, "ldp.agent.simple_agent.SimpleAgent.model_config", false]], "model_config (ldp.agent.simple_agent.simpleagentstate attribute)": [[2, "ldp.agent.simple_agent.SimpleAgentState.model_config", false]], "model_config (ldp.agent.simpleagent attribute)": [[2, "ldp.agent.SimpleAgent.model_config", false]], "model_config (ldp.agent.simpleagentstate attribute)": [[2, "ldp.agent.SimpleAgentState.model_config", false]], "model_config (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.model_config", false]], "model_config (ldp.agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.TreeofThoughtsAgent.model_config", false]], "model_config (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.model_config", false]], "model_config (ldp.alg.offlinetrainerconfig attribute)": [[3, "ldp.alg.OfflineTrainerConfig.model_config", false]], "model_config (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.model_config", false]], "model_config (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.model_config", false]], "model_config (ldp.alg.optimizer.ape.example attribute)": [[4, "ldp.alg.optimizer.ape.Example.model_config", false]], "model_config (ldp.alg.optimizer.ape.outputprompt attribute)": [[4, "ldp.alg.optimizer.ape.OutputPrompt.model_config", false]], "model_config (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.model_config", false]], "model_config (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.model_config", false]], "model_config (ldp.alg.optimizer.memory.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.memory.PositiveMemoryOpt.model_config", false]], "model_config (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.model_config", false]], "model_config (ldp.alg.optimizer.optimizerconfig attribute)": [[4, "ldp.alg.optimizer.OptimizerConfig.model_config", false]], "model_config (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.model_config", false]], "model_config (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.model_config", false]], "model_config (ldp.alg.runners.offlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OfflineTrainerConfig.model_config", false]], "model_config (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.model_config", false]], "model_config (ldp.data_structures.trajectory attribute)": [[1, "ldp.data_structures.Trajectory.model_config", false]], "model_config (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.model_config", false]], "model_config (ldp.graph.callid attribute)": [[5, "ldp.graph.CallID.model_config", false]], "model_config (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.model_config", false]], "model_config (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.model_config", false]], "model_config (ldp.graph.memory.memorymodel attribute)": [[5, "id22", false], [5, "ldp.graph.memory.MemoryModel.model_config", false]], "model_config (ldp.graph.memory.uindexmemorymodel attribute)": [[5, "ldp.graph.memory.UIndexMemoryModel.model_config", false]], "model_config (ldp.graph.memorymodel attribute)": [[5, "ldp.graph.MemoryModel.model_config", false]], "model_config (ldp.graph.modules.reflect.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.reflect.ReflectModuleConfig.model_config", false]], "model_config (ldp.graph.modules.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.ReflectModuleConfig.model_config", false]], "model_config (ldp.graph.op_utils.callid attribute)": [[5, "ldp.graph.op_utils.CallID.model_config", false]], "model_config (ldp.graph.opctx attribute)": [[5, "ldp.graph.OpCtx.model_config", false]], "model_config (ldp.graph.ops.opctx attribute)": [[5, "ldp.graph.ops.OpCtx.model_config", false]], "model_config (ldp.llms.chat.llmmodel attribute)": [[7, "ldp.llms.chat.LLMModel.model_config", false]], "model_config (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.model_config", false]], "model_config (ldp.llms.chat.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.model_config", false]], "model_config (ldp.llms.embeddingmodel attribute)": [[7, "ldp.llms.EmbeddingModel.model_config", false]], "model_config (ldp.llms.embeddings.embeddingmodel attribute)": [[7, "ldp.llms.embeddings.EmbeddingModel.model_config", false]], "model_config (ldp.llms.embeddings.hybridembeddingmodel attribute)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel.model_config", false]], "model_config (ldp.llms.embeddings.liteembeddingmodel attribute)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.model_config", false]], "model_config (ldp.llms.embeddings.sparseembeddingmodel attribute)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel.model_config", false]], "model_config (ldp.llms.hybridembeddingmodel attribute)": [[7, "ldp.llms.HybridEmbeddingModel.model_config", false]], "model_config (ldp.llms.liteembeddingmodel attribute)": [[7, "ldp.llms.LiteEmbeddingModel.model_config", false]], "model_config (ldp.llms.llmmodel attribute)": [[7, "ldp.llms.LLMModel.model_config", false]], "model_config (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.model_config", false]], "model_config (ldp.llms.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.MultipleCompletionLLMModel.model_config", false]], "model_config (ldp.llms.sparseembeddingmodel attribute)": [[7, "ldp.llms.SparseEmbeddingModel.model_config", false]], "model_dump_json() (ldp.data_structures.transition method)": [[1, "ldp.data_structures.Transition.model_dump_json", false]], "model_fields (ldp.agent.agent.agentconfig attribute)": [[2, "ldp.agent.agent.AgentConfig.model_fields", false]], "model_fields (ldp.agent.agentconfig attribute)": [[2, "ldp.agent.AgentConfig.model_fields", false]], "model_fields (ldp.agent.memory_agent.memoryagent attribute)": [[2, "ldp.agent.memory_agent.MemoryAgent.model_fields", false]], "model_fields (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.model_fields", false]], "model_fields (ldp.agent.react_agent.reactagent attribute)": [[2, "ldp.agent.react_agent.ReActAgent.model_fields", false]], "model_fields (ldp.agent.reactagent attribute)": [[2, "ldp.agent.ReActAgent.model_fields", false]], "model_fields (ldp.agent.simple_agent.simpleagent attribute)": [[2, "ldp.agent.simple_agent.SimpleAgent.model_fields", false]], "model_fields (ldp.agent.simple_agent.simpleagentstate attribute)": [[2, "ldp.agent.simple_agent.SimpleAgentState.model_fields", false]], "model_fields (ldp.agent.simpleagent attribute)": [[2, "ldp.agent.SimpleAgent.model_fields", false]], "model_fields (ldp.agent.simpleagentstate attribute)": [[2, "ldp.agent.SimpleAgentState.model_fields", false]], "model_fields (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.model_fields", false]], "model_fields (ldp.agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.TreeofThoughtsAgent.model_fields", false]], "model_fields (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.model_fields", false]], "model_fields (ldp.alg.offlinetrainerconfig attribute)": [[3, "ldp.alg.OfflineTrainerConfig.model_fields", false]], "model_fields (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.model_fields", false]], "model_fields (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.model_fields", false]], "model_fields (ldp.alg.optimizer.ape.example attribute)": [[4, "ldp.alg.optimizer.ape.Example.model_fields", false]], "model_fields (ldp.alg.optimizer.ape.outputprompt attribute)": [[4, "ldp.alg.optimizer.ape.OutputPrompt.model_fields", false]], "model_fields (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.model_fields", false]], "model_fields (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.model_fields", false]], "model_fields (ldp.alg.optimizer.memory.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.memory.PositiveMemoryOpt.model_fields", false]], "model_fields (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.model_fields", false]], "model_fields (ldp.alg.optimizer.optimizerconfig attribute)": [[4, "ldp.alg.optimizer.OptimizerConfig.model_fields", false]], "model_fields (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.model_fields", false]], "model_fields (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.model_fields", false]], "model_fields (ldp.alg.runners.offlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OfflineTrainerConfig.model_fields", false]], "model_fields (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.model_fields", false]], "model_fields (ldp.data_structures.trajectory attribute)": [[1, "ldp.data_structures.Trajectory.model_fields", false]], "model_fields (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.model_fields", false]], "model_fields (ldp.graph.callid attribute)": [[5, "ldp.graph.CallID.model_fields", false]], "model_fields (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.model_fields", false]], "model_fields (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.model_fields", false]], "model_fields (ldp.graph.memory.memorymodel attribute)": [[5, "id23", false], [5, "ldp.graph.memory.MemoryModel.model_fields", false]], "model_fields (ldp.graph.memory.uindexmemorymodel attribute)": [[5, "ldp.graph.memory.UIndexMemoryModel.model_fields", false]], "model_fields (ldp.graph.memorymodel attribute)": [[5, "ldp.graph.MemoryModel.model_fields", false]], "model_fields (ldp.graph.modules.reflect.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.reflect.ReflectModuleConfig.model_fields", false]], "model_fields (ldp.graph.modules.reflectmoduleconfig attribute)": [[6, "ldp.graph.modules.ReflectModuleConfig.model_fields", false]], "model_fields (ldp.graph.op_utils.callid attribute)": [[5, "ldp.graph.op_utils.CallID.model_fields", false]], "model_fields (ldp.graph.opctx attribute)": [[5, "ldp.graph.OpCtx.model_fields", false]], "model_fields (ldp.graph.ops.opctx attribute)": [[5, "ldp.graph.ops.OpCtx.model_fields", false]], "model_fields (ldp.llms.chat.llmmodel attribute)": [[7, "ldp.llms.chat.LLMModel.model_fields", false]], "model_fields (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.model_fields", false]], "model_fields (ldp.llms.chat.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.model_fields", false]], "model_fields (ldp.llms.embeddingmodel attribute)": [[7, "ldp.llms.EmbeddingModel.model_fields", false]], "model_fields (ldp.llms.embeddings.embeddingmodel attribute)": [[7, "ldp.llms.embeddings.EmbeddingModel.model_fields", false]], "model_fields (ldp.llms.embeddings.hybridembeddingmodel attribute)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel.model_fields", false]], "model_fields (ldp.llms.embeddings.liteembeddingmodel attribute)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.model_fields", false]], "model_fields (ldp.llms.embeddings.sparseembeddingmodel attribute)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel.model_fields", false]], "model_fields (ldp.llms.hybridembeddingmodel attribute)": [[7, "ldp.llms.HybridEmbeddingModel.model_fields", false]], "model_fields (ldp.llms.liteembeddingmodel attribute)": [[7, "ldp.llms.LiteEmbeddingModel.model_fields", false]], "model_fields (ldp.llms.llmmodel attribute)": [[7, "ldp.llms.LLMModel.model_fields", false]], "model_fields (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.model_fields", false]], "model_fields (ldp.llms.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.MultipleCompletionLLMModel.model_fields", false]], "model_fields (ldp.llms.sparseembeddingmodel attribute)": [[7, "ldp.llms.SparseEmbeddingModel.model_fields", false]], "model_post_init() (ldp.alg.optimizer.ape.apeopt method)": [[4, "ldp.alg.optimizer.ape.APEOpt.model_post_init", false]], "model_post_init() (ldp.alg.optimizer.apeopt method)": [[4, "ldp.alg.optimizer.APEOpt.model_post_init", false]], "model_post_init() (ldp.graph.memory.memorymodel method)": [[5, "id24", false], [5, "ldp.graph.memory.MemoryModel.model_post_init", false]], "model_post_init() (ldp.graph.memory.uindexmemorymodel method)": [[5, "ldp.graph.memory.UIndexMemoryModel.model_post_init", false]], "model_post_init() (ldp.graph.memorymodel method)": [[5, "ldp.graph.MemoryModel.model_post_init", false]], "model_post_init() (ldp.graph.opctx method)": [[5, "ldp.graph.OpCtx.model_post_init", false]], "model_post_init() (ldp.graph.ops.opctx method)": [[5, "ldp.graph.ops.OpCtx.model_post_init", false]], "models (ldp.llms.embeddings.hybridembeddingmodel attribute)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel.models", false]], "models (ldp.llms.hybridembeddingmodel attribute)": [[7, "ldp.llms.HybridEmbeddingModel.models", false]], "module": [[1, "module-ldp", false], [1, "module-ldp.data_structures", false], [1, "module-ldp.main", false], [1, "module-ldp.shims", false], [1, "module-ldp.utils", false], [2, "module-ldp.agent", false], [2, "module-ldp.agent.agent", false], [2, "module-ldp.agent.agent_client", false], [2, "module-ldp.agent.interactive_agent", false], [2, "module-ldp.agent.memory_agent", false], [2, "module-ldp.agent.react_agent", false], [2, "module-ldp.agent.simple_agent", false], [2, "module-ldp.agent.tree_of_thoughts_agent", false], [3, "module-ldp.alg", false], [3, "module-ldp.alg.algorithms", false], [3, "module-ldp.alg.beam_search", false], [3, "module-ldp.alg.callbacks", false], [3, "module-ldp.alg.datasets", false], [3, "module-ldp.alg.rollout", false], [3, "module-ldp.alg.runners", false], [3, "module-ldp.alg.tree_search", false], [4, "module-ldp.alg.optimizer", false], [4, "module-ldp.alg.optimizer.ape", false], [4, "module-ldp.alg.optimizer.memory", false], [4, "module-ldp.alg.optimizer.opt", false], [4, "module-ldp.alg.optimizer.replay_buffers", false], [5, "module-ldp.graph", false], [5, "module-ldp.graph.async_torch", false], [5, "module-ldp.graph.common_ops", false], [5, "module-ldp.graph.gradient_estimators", false], [5, "module-ldp.graph.loss_ops", false], [5, "module-ldp.graph.memory", false], [5, "module-ldp.graph.op_utils", false], [5, "module-ldp.graph.ops", false], [5, "module-ldp.graph.torch_ops", false], [6, "module-ldp.graph.modules", false], [6, "module-ldp.graph.modules.llm_call", false], [6, "module-ldp.graph.modules.react", false], [6, "module-ldp.graph.modules.reflect", false], [6, "module-ldp.graph.modules.thought", false], [7, "module-ldp.llms", false], [7, "module-ldp.llms.chat", false], [7, "module-ldp.llms.embeddings", false], [7, "module-ldp.llms.prompts", false]], "monitor (ldp.shims.tqdm attribute)": [[1, "ldp.shims.tqdm.monitor", false]], "monitor_interval (ldp.shims.tqdm attribute)": [[1, "ldp.shims.tqdm.monitor_interval", false]], "moveto() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.moveto", false]], "mselossop (class in ldp.graph)": [[5, "ldp.graph.MSELossOp", false]], "mselossop (class in ldp.graph.loss_ops)": [[5, "ldp.graph.loss_ops.MSELossOp", false]], "multiplecompletionllmmodel (class in ldp.llms)": [[7, "ldp.llms.MultipleCompletionLLMModel", false]], "multiplecompletionllmmodel (class in ldp.llms.chat)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel", false]], "name (ldp.graph.op attribute)": [[5, "ldp.graph.Op.name", false]], "name (ldp.graph.ops.op attribute)": [[5, "ldp.graph.ops.Op.name", false]], "name (ldp.llms.chat.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.name", false]], "name (ldp.llms.embeddingmodel attribute)": [[7, "ldp.llms.EmbeddingModel.name", false]], "name (ldp.llms.embeddings.embeddingmodel attribute)": [[7, "ldp.llms.embeddings.EmbeddingModel.name", false]], "name (ldp.llms.embeddings.hybridembeddingmodel attribute)": [[7, "ldp.llms.embeddings.HybridEmbeddingModel.name", false]], "name (ldp.llms.embeddings.liteembeddingmodel attribute)": [[7, "ldp.llms.embeddings.LiteEmbeddingModel.name", false]], "name (ldp.llms.embeddings.sparseembeddingmodel attribute)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel.name", false]], "name (ldp.llms.hybridembeddingmodel attribute)": [[7, "ldp.llms.HybridEmbeddingModel.name", false]], "name (ldp.llms.liteembeddingmodel attribute)": [[7, "ldp.llms.LiteEmbeddingModel.name", false]], "name (ldp.llms.llmmodel attribute)": [[7, "ldp.llms.LLMModel.name", false]], "name (ldp.llms.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.MultipleCompletionLLMModel.name", false]], "name (ldp.llms.sparseembeddingmodel attribute)": [[7, "ldp.llms.SparseEmbeddingModel.name", false]], "named_ops() (ldp.agent.agent method)": [[2, "ldp.agent.Agent.named_ops", false]], "named_ops() (ldp.agent.agent.agent method)": [[2, "ldp.agent.agent.Agent.named_ops", false]], "next_agent_state (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.next_agent_state", false]], "next_observation (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.next_observation", false]], "no_observation (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.NO_OBSERVATION", false]], "num_eval_iterations (ldp.alg.evaluatorconfig attribute)": [[3, "ldp.alg.EvaluatorConfig.num_eval_iterations", false]], "num_eval_iterations (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.num_eval_iterations", false]], "num_eval_iterations (ldp.alg.runners.evaluatorconfig attribute)": [[3, "ldp.alg.runners.EvaluatorConfig.num_eval_iterations", false]], "num_memories (ldp.agent.memory_agent.memoryagent attribute)": [[2, "ldp.agent.memory_agent.MemoryAgent.num_memories", false]], "num_memories (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.num_memories", false]], "num_rollouts_per_env (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.num_rollouts_per_env", false]], "num_rollouts_per_env (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.num_rollouts_per_env", false]], "num_train_iterations (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.num_train_iterations", false]], "num_train_iterations (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.num_train_iterations", false]], "observation (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.observation", false]], "offlinetrainer (class in ldp.alg)": [[3, "ldp.alg.OfflineTrainer", false]], "offlinetrainer (class in ldp.alg.runners)": [[3, "ldp.alg.runners.OfflineTrainer", false]], "offlinetrainerconfig (class in ldp.alg)": [[3, "ldp.alg.OfflineTrainerConfig", false]], "offlinetrainerconfig (class in ldp.alg.runners)": [[3, "ldp.alg.runners.OfflineTrainerConfig", false]], "onlinetrainer (class in ldp.alg)": [[3, "ldp.alg.OnlineTrainer", false]], "onlinetrainer (class in ldp.alg.runners)": [[3, "ldp.alg.runners.OnlineTrainer", false]], "onlinetrainerconfig (class in ldp.alg)": [[3, "ldp.alg.OnlineTrainerConfig", false]], "onlinetrainerconfig (class in ldp.alg.runners)": [[3, "ldp.alg.runners.OnlineTrainerConfig", false]], "op (class in ldp.graph)": [[5, "ldp.graph.Op", false]], "op (class in ldp.graph.ops)": [[5, "ldp.graph.ops.Op", false]], "op_call() (in module ldp.graph)": [[5, "ldp.graph.op_call", false]], "op_call() (in module ldp.graph.op_utils)": [[5, "ldp.graph.op_utils.op_call", false]], "op_class (ldp.graph.opresult property)": [[5, "ldp.graph.OpResult.op_class", false]], "op_class (ldp.graph.ops.opresult property)": [[5, "ldp.graph.ops.OpResult.op_class", false]], "op_name (ldp.graph.opctx attribute)": [[5, "ldp.graph.OpCtx.op_name", false]], "op_name (ldp.graph.ops.opctx attribute)": [[5, "ldp.graph.ops.OpCtx.op_name", false]], "opctx (class in ldp.graph)": [[5, "ldp.graph.OpCtx", false]], "opctx (class in ldp.graph.ops)": [[5, "ldp.graph.ops.OpCtx", false]], "openai (ldp.agent.defaultllmmodelnames attribute)": [[2, "ldp.agent.DefaultLLMModelNames.OPENAI", false]], "opresult (class in ldp.graph)": [[5, "ldp.graph.OpResult", false]], "opresult (class in ldp.graph.ops)": [[5, "ldp.graph.ops.OpResult", false]], "optimizer (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.Optimizer", false]], "optimizer (class in ldp.alg.optimizer.opt)": [[4, "ldp.alg.optimizer.opt.Optimizer", false]], "optimizer_kwargs (ldp.alg.optimizer.optimizerconfig attribute)": [[4, "ldp.alg.optimizer.OptimizerConfig.optimizer_kwargs", false]], "optimizer_type (ldp.alg.optimizer.optimizerconfig attribute)": [[4, "ldp.alg.optimizer.OptimizerConfig.optimizer_type", false]], "optimizerconfig (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.OptimizerConfig", false]], "output (ldp.alg.optimizer.ape.example attribute)": [[4, "ldp.alg.optimizer.ape.Example.output", false]], "output (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.output", false]], "output (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.output", false]], "output_op (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.output_op", false]], "output_op (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.output_op", false]], "output_op (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.output_op", false]], "outputprompt (class in ldp.alg.optimizer.ape)": [[4, "ldp.alg.optimizer.ape.OutputPrompt", false]], "pandas() (ldp.shims.tqdm class method)": [[1, "ldp.shims.tqdm.pandas", false]], "parse_message() (in module ldp.graph.modules)": [[6, "ldp.graph.modules.parse_message", false]], "parse_message() (in module ldp.graph.modules.react)": [[6, "ldp.graph.modules.react.parse_message", false]], "parse_message() (ldp.graph.modules.react.reactmodule static method)": [[6, "ldp.graph.modules.react.ReActModule.parse_message", false]], "parse_message() (ldp.graph.modules.reactmodule static method)": [[6, "ldp.graph.modules.ReActModule.parse_message", false]], "parsedllmcallmodule (class in ldp.graph.modules)": [[6, "ldp.graph.modules.ParsedLLMCallModule", false]], "parsedllmcallmodule (class in ldp.graph.modules.llm_call)": [[6, "ldp.graph.modules.llm_call.ParsedLLMCallModule", false]], "positivememoryopt (class in ldp.alg.optimizer)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt", false]], "positivememoryopt (class in ldp.alg.optimizer.memory)": [[4, "ldp.alg.optimizer.memory.PositiveMemoryOpt", false]], "prepend_sys() (in module ldp.llms)": [[7, "ldp.llms.prepend_sys", false]], "prepend_sys() (in module ldp.llms.prompts)": [[7, "ldp.llms.prompts.prepend_sys", false]], "prepend_sys_and_append_sys() (in module ldp.llms)": [[7, "ldp.llms.prepend_sys_and_append_sys", false]], "prepend_sys_and_append_sys() (in module ldp.llms.prompts)": [[7, "ldp.llms.prompts.prepend_sys_and_append_sys", false]], "prompt (ldp.agent.memory_agent.memoryagent attribute)": [[2, "ldp.agent.memory_agent.MemoryAgent.prompt", false]], "prompt (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.prompt", false]], "prompt (ldp.alg.optimizer.ape.outputprompt attribute)": [[4, "ldp.alg.optimizer.ape.OutputPrompt.prompt", false]], "prompt (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.prompt", false]], "prompt (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.prompt", false]], "prompt_and_completion_costs (ldp.llms.chat.llmresult property)": [[7, "ldp.llms.chat.LLMResult.prompt_and_completion_costs", false]], "prompt_and_completion_costs (ldp.llms.llmresult property)": [[7, "ldp.llms.LLMResult.prompt_and_completion_costs", false]], "prompt_count (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.prompt_count", false]], "prompt_count (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.prompt_count", false]], "prompt_op (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.prompt_op", false]], "prompt_op (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.prompt_op", false]], "promptop (class in ldp.graph)": [[5, "ldp.graph.PromptOp", false]], "promptop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.PromptOp", false]], "proposal_prompt_func (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.proposal_prompt_func", false]], "proposal_prompt_func (ldp.agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.TreeofThoughtsAgent.proposal_prompt_func", false]], "provider (ldp.llms.chat.llmresult property)": [[7, "ldp.llms.chat.LLMResult.provider", false]], "provider (ldp.llms.llmresult property)": [[7, "ldp.llms.LLMResult.provider", false]], "query (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.query", false]], "query (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.query", false]], "query (ldp.llms.embeddingmodes attribute)": [[7, "ldp.llms.EmbeddingModes.QUERY", false]], "query (ldp.llms.embeddings.embeddingmodes attribute)": [[7, "ldp.llms.embeddings.EmbeddingModes.QUERY", false]], "query_factory (ldp.agent.memory_agent.memoryagent attribute)": [[2, "ldp.agent.memory_agent.MemoryAgent.query_factory", false]], "query_factory (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.query_factory", false]], "query_prompt (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.query_prompt", false]], "query_prompt (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.query_prompt", false]], "reactagent (class in ldp.agent)": [[2, "ldp.agent.ReActAgent", false]], "reactagent (class in ldp.agent.react_agent)": [[2, "ldp.agent.react_agent.ReActAgent", false]], "reactmodule (class in ldp.graph.modules)": [[6, "ldp.graph.modules.ReActModule", false]], "reactmodule (class in ldp.graph.modules.react)": [[6, "ldp.graph.modules.react.ReActModule", false]], "reflectmodule (class in ldp.graph.modules)": [[6, "ldp.graph.modules.ReflectModule", false]], "reflectmodule (class in ldp.graph.modules.reflect)": [[6, "ldp.graph.modules.reflect.ReflectModule", false]], "reflectmoduleconfig (class in ldp.graph.modules)": [[6, "ldp.graph.modules.ReflectModuleConfig", false]], "reflectmoduleconfig (class in ldp.graph.modules.reflect)": [[6, "ldp.graph.modules.reflect.ReflectModuleConfig", false]], "refresh() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.refresh", false]], "reraise_exc_as() (in module ldp.alg.rollout)": [[3, "ldp.alg.rollout.reraise_exc_as", false]], "reset() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.reset", false]], "resize() (ldp.alg.optimizer.replay_buffers.circularreplaybuffer method)": [[4, "ldp.alg.optimizer.replay_buffers.CircularReplayBuffer.resize", false]], "resolve_fully_qualified_name() (in module ldp.graph.ops)": [[5, "ldp.graph.ops.resolve_fully_qualified_name", false]], "reward (ldp.alg.optimizer.ape.apescorefn attribute)": [[4, "ldp.alg.optimizer.ape.APEScoreFn.REWARD", false]], "reward (ldp.alg.optimizer.apescorefn attribute)": [[4, "ldp.alg.optimizer.APEScoreFn.REWARD", false]], "reward (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.reward", false]], "reward_discount (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.reward_discount", false]], "reward_discount (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.reward_discount", false]], "reward_discount (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.reward_discount", false]], "reward_discount (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.reward_discount", false]], "reward_discount (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.reward_discount", false]], "rolloutdebugdumpcallback (class in ldp.alg)": [[3, "ldp.alg.RolloutDebugDumpCallback", false]], "rolloutdebugdumpcallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.RolloutDebugDumpCallback", false]], "rolloutmanager (class in ldp.alg)": [[3, "ldp.alg.RolloutManager", false]], "rolloutmanager (class in ldp.alg.rollout)": [[3, "ldp.alg.rollout.RolloutManager", false]], "run() (ldp.alg.evaluator method)": [[3, "ldp.alg.Evaluator.run", false]], "run() (ldp.alg.runners.evaluator method)": [[3, "ldp.alg.runners.Evaluator.run", false]], "run_id (ldp.graph.callid attribute)": [[5, "ldp.graph.CallID.run_id", false]], "run_id (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.run_id", false]], "run_id (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.run_id", false]], "run_id (ldp.graph.op_utils.callid attribute)": [[5, "ldp.graph.op_utils.CallID.run_id", false]], "run_id (ldp.graph.opresult property)": [[5, "ldp.graph.OpResult.run_id", false]], "run_id (ldp.graph.ops.opresult property)": [[5, "ldp.graph.ops.OpResult.run_id", false]], "safe_access_index() (ldp.graph.memory.memorymodel method)": [[5, "id25", false], [5, "ldp.graph.memory.MemoryModel.safe_access_index", false]], "safe_access_index() (ldp.graph.memorymodel method)": [[5, "ldp.graph.MemoryModel.safe_access_index", false]], "sample_trajectories() (ldp.alg.beam_search.beamsearchrollout method)": [[3, "ldp.alg.beam_search.BeamSearchRollout.sample_trajectories", false]], "sample_trajectories() (ldp.alg.beamsearchrollout method)": [[3, "ldp.alg.BeamSearchRollout.sample_trajectories", false]], "sample_trajectories() (ldp.alg.rollout.rolloutmanager method)": [[3, "ldp.alg.rollout.RolloutManager.sample_trajectories", false]], "sample_trajectories() (ldp.alg.rolloutmanager method)": [[3, "ldp.alg.RolloutManager.sample_trajectories", false]], "sample_tree() (ldp.alg.tree_search.treesearchrollout method)": [[3, "ldp.alg.tree_search.TreeSearchRollout.sample_tree", false]], "sample_tree() (ldp.alg.treesearchrollout method)": [[3, "ldp.alg.TreeSearchRollout.sample_tree", false]], "sample_trees() (ldp.alg.tree_search.treesearchrollout method)": [[3, "ldp.alg.tree_search.TreeSearchRollout.sample_trees", false]], "sample_trees() (ldp.alg.treesearchrollout method)": [[3, "ldp.alg.TreeSearchRollout.sample_trees", false]], "score (ldp.alg.optimizer.ape.example attribute)": [[4, "ldp.alg.optimizer.ape.Example.score", false]], "score_fn (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.score_fn", false]], "score_fn (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.score_fn", false]], "seconds_to_first_token (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.seconds_to_first_token", false]], "seconds_to_first_token (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.seconds_to_first_token", false]], "seconds_to_last_token (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.seconds_to_last_token", false]], "seconds_to_last_token (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.seconds_to_last_token", false]], "serialize_uuid() (ldp.graph.callid method)": [[5, "ldp.graph.CallID.serialize_uuid", false]], "serialize_uuid() (ldp.graph.op_utils.callid method)": [[5, "ldp.graph.op_utils.CallID.serialize_uuid", false]], "set_description() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.set_description", false]], "set_description_str() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.set_description_str", false]], "set_lock() (ldp.shims.tqdm class method)": [[1, "ldp.shims.tqdm.set_lock", false]], "set_mode() (ldp.llms.embeddingmodel method)": [[7, "ldp.llms.EmbeddingModel.set_mode", false]], "set_mode() (ldp.llms.embeddings.embeddingmodel method)": [[7, "ldp.llms.embeddings.EmbeddingModel.set_mode", false]], "set_model_name() (ldp.llms.chat.multiplecompletionllmmodel method)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.set_model_name", false]], "set_model_name() (ldp.llms.multiplecompletionllmmodel method)": [[7, "ldp.llms.MultipleCompletionLLMModel.set_model_name", false]], "set_name() (ldp.graph.op method)": [[5, "ldp.graph.Op.set_name", false]], "set_name() (ldp.graph.ops.op method)": [[5, "ldp.graph.ops.Op.set_name", false]], "set_postfix() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.set_postfix", false]], "set_postfix_str() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.set_postfix_str", false]], "set_training_mode() (in module ldp.graph)": [[5, "ldp.graph.set_training_mode", false]], "set_training_mode() (in module ldp.graph.op_utils)": [[5, "ldp.graph.op_utils.set_training_mode", false]], "simpleagent (class in ldp.agent)": [[2, "ldp.agent.SimpleAgent", false]], "simpleagent (class in ldp.agent.simple_agent)": [[2, "ldp.agent.simple_agent.SimpleAgent", false]], "simpleagentstate (class in ldp.agent)": [[2, "ldp.agent.SimpleAgentState", false]], "simpleagentstate (class in ldp.agent.simple_agent)": [[2, "ldp.agent.simple_agent.SimpleAgentState", false]], "sparseembeddingmodel (class in ldp.llms)": [[7, "ldp.llms.SparseEmbeddingModel", false]], "sparseembeddingmodel (class in ldp.llms.embeddings)": [[7, "ldp.llms.embeddings.SparseEmbeddingModel", false]], "status_printer() (ldp.shims.tqdm static method)": [[1, "ldp.shims.tqdm.status_printer", false]], "steps (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.steps", false]], "steps (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.steps", false]], "steps (ldp.alg.optimizer.memory.memoryopt attribute)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.steps", false]], "steps (ldp.alg.optimizer.memoryopt attribute)": [[4, "ldp.alg.optimizer.MemoryOpt.steps", false]], "steps (ldp.alg.optimizer.positivememoryopt attribute)": [[4, "ldp.alg.optimizer.PositiveMemoryOpt.steps", false]], "steps (ldp.data_structures.trajectory attribute)": [[1, "ldp.data_structures.Trajectory.steps", false]], "stop_grad() (in module ldp.graph.gradient_estimators)": [[5, "ldp.graph.gradient_estimators.stop_grad", false]], "stopgradop (class in ldp.graph.common_ops)": [[5, "ldp.graph.common_ops.StopGradOp", false]], "store_tensor_inputs() (in module ldp.graph.torch_ops)": [[5, "ldp.graph.torch_ops.store_tensor_inputs", false]], "str (ldp.graph.modules.react.tooldescriptionmethods attribute)": [[6, "ldp.graph.modules.react.ToolDescriptionMethods.STR", false]], "str (ldp.graph.modules.tooldescriptionmethods attribute)": [[6, "ldp.graph.modules.ToolDescriptionMethods.STR", false]], "straight_through_estimator() (in module ldp.graph.gradient_estimators)": [[5, "ldp.graph.gradient_estimators.straight_through_estimator", false]], "sum_logprobs() (in module ldp.llms)": [[7, "ldp.llms.sum_logprobs", false]], "sum_logprobs() (in module ldp.llms.chat)": [[7, "ldp.llms.chat.sum_logprobs", false]], "sys_prompt (ldp.agent.memoryagent attribute)": [[2, "ldp.agent.MemoryAgent.sys_prompt", false]], "sys_prompt (ldp.agent.react_agent.reactagent attribute)": [[2, "ldp.agent.react_agent.ReActAgent.sys_prompt", false]], "sys_prompt (ldp.agent.reactagent attribute)": [[2, "ldp.agent.ReActAgent.sys_prompt", false]], "sys_prompt (ldp.agent.simple_agent.simpleagent attribute)": [[2, "ldp.agent.simple_agent.SimpleAgent.sys_prompt", false]], "sys_prompt (ldp.agent.simpleagent attribute)": [[2, "ldp.agent.SimpleAgent.sys_prompt", false]], "system_fingerprint (ldp.llms.chat.llmresult attribute)": [[7, "ldp.llms.chat.LLMResult.system_fingerprint", false]], "system_fingerprint (ldp.llms.llmresult attribute)": [[7, "ldp.llms.LLMResult.system_fingerprint", false]], "system_prompt (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.system_prompt", false]], "system_prompt (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.system_prompt", false]], "template (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.template", false]], "template (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.template", false]], "terminalprintingcallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.TerminalPrintingCallback", false]], "thoughtmodule (class in ldp.graph.modules)": [[6, "ldp.graph.modules.ThoughtModule", false]], "thoughtmodule (class in ldp.graph.modules.thought)": [[6, "ldp.graph.modules.thought.ThoughtModule", false]], "timestep (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.timestep", false]], "to_dict() (ldp.graph.opresult method)": [[5, "ldp.graph.OpResult.to_dict", false]], "to_dict() (ldp.graph.ops.opresult method)": [[5, "ldp.graph.ops.OpResult.to_dict", false]], "to_jsonl() (ldp.data_structures.trajectory method)": [[1, "ldp.data_structures.Trajectory.to_jsonl", false]], "to_network() (in module ldp.alg)": [[3, "ldp.alg.to_network", false]], "to_network() (in module ldp.alg.algorithms)": [[3, "ldp.alg.algorithms.to_network", false]], "tool_choice_required (ldp.llms.chat.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.chat.MultipleCompletionLLMModel.TOOL_CHOICE_REQUIRED", false]], "tool_choice_required (ldp.llms.multiplecompletionllmmodel attribute)": [[7, "ldp.llms.MultipleCompletionLLMModel.TOOL_CHOICE_REQUIRED", false]], "tool_description_method (ldp.agent.react_agent.reactagent attribute)": [[2, "ldp.agent.react_agent.ReActAgent.tool_description_method", false]], "tool_description_method (ldp.agent.reactagent attribute)": [[2, "ldp.agent.ReActAgent.tool_description_method", false]], "tooldescriptionmethods (class in ldp.graph.modules)": [[6, "ldp.graph.modules.ToolDescriptionMethods", false]], "tooldescriptionmethods (class in ldp.graph.modules.react)": [[6, "ldp.graph.modules.react.ToolDescriptionMethods", false]], "tools (ldp.agent.simple_agent.simpleagentstate attribute)": [[2, "ldp.agent.simple_agent.SimpleAgentState.tools", false]], "tools (ldp.agent.simpleagentstate attribute)": [[2, "ldp.agent.SimpleAgentState.tools", false]], "tools_to_track (ldp.alg.callbacks.computetrajectorymetricsmixin attribute)": [[3, "ldp.alg.callbacks.ComputeTrajectoryMetricsMixin.tools_to_track", false]], "tools_to_track (ldp.alg.computetrajectorymetricsmixin attribute)": [[3, "ldp.alg.ComputeTrajectoryMetricsMixin.tools_to_track", false]], "torchop (class in ldp.graph.torch_ops)": [[5, "ldp.graph.torch_ops.TorchOp", false]], "torchparambackwardestimator (class in ldp.graph.gradient_estimators)": [[5, "ldp.graph.gradient_estimators.TorchParamBackwardEstimator", false]], "tqdm (class in ldp.shims)": [[1, "ldp.shims.tqdm", false]], "trace (ldp.alg.optimizer.ape.apeopt attribute)": [[4, "ldp.alg.optimizer.ape.APEOpt.trace", false]], "trace (ldp.alg.optimizer.apeopt attribute)": [[4, "ldp.alg.optimizer.APEOpt.trace", false]], "train() (ldp.alg.offlinetrainer method)": [[3, "ldp.alg.OfflineTrainer.train", false]], "train() (ldp.alg.onlinetrainer method)": [[3, "ldp.alg.OnlineTrainer.train", false]], "train() (ldp.alg.runners.offlinetrainer method)": [[3, "ldp.alg.runners.OfflineTrainer.train", false]], "train() (ldp.alg.runners.onlinetrainer method)": [[3, "ldp.alg.runners.OnlineTrainer.train", false]], "train_means (ldp.alg.callbacks.meanmetricscallback property)": [[3, "ldp.alg.callbacks.MeanMetricsCallback.train_means", false]], "train_means (ldp.alg.meanmetricscallback property)": [[3, "ldp.alg.MeanMetricsCallback.train_means", false]], "traj (ldp.alg.beam attribute)": [[3, "ldp.alg.Beam.traj", false]], "traj (ldp.alg.beam_search.beam attribute)": [[3, "ldp.alg.beam_search.Beam.traj", false]], "traj_id (ldp.data_structures.trajectory attribute)": [[1, "ldp.data_structures.Trajectory.traj_id", false]], "trajectory (class in ldp.data_structures)": [[1, "ldp.data_structures.Trajectory", false]], "trajectoryfilecallback (class in ldp.alg)": [[3, "ldp.alg.TrajectoryFileCallback", false]], "trajectoryfilecallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.TrajectoryFileCallback", false]], "trajectorymetricscallback (class in ldp.alg)": [[3, "ldp.alg.TrajectoryMetricsCallback", false]], "trajectorymetricscallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.TrajectoryMetricsCallback", false]], "trange() (in module ldp.shims)": [[1, "ldp.shims.trange", false]], "transition (class in ldp.data_structures)": [[1, "ldp.data_structures.Transition", false]], "transitiontree (class in ldp.data_structures)": [[1, "ldp.data_structures.TransitionTree", false]], "traverse() (ldp.graph.opresult method)": [[5, "ldp.graph.OpResult.traverse", false]], "traverse() (ldp.graph.ops.opresult method)": [[5, "ldp.graph.ops.OpResult.traverse", false]], "treeofthoughtsagent (class in ldp.agent)": [[2, "ldp.agent.TreeofThoughtsAgent", false]], "treeofthoughtsagent (class in ldp.agent.tree_of_thoughts_agent)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent", false]], "treesearchrollout (class in ldp.alg)": [[3, "ldp.alg.TreeSearchRollout", false]], "treesearchrollout (class in ldp.alg.tree_search)": [[3, "ldp.alg.tree_search.TreeSearchRollout", false]], "truncated (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.truncated", false]], "uindexmemorymodel (class in ldp.graph.memory)": [[5, "ldp.graph.memory.UIndexMemoryModel", false]], "unpause() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.unpause", false]], "unwrap_value() (ldp.graph.opresult static method)": [[5, "ldp.graph.OpResult.unwrap_value", false]], "unwrap_value() (ldp.graph.ops.opresult static method)": [[5, "ldp.graph.ops.OpResult.unwrap_value", false]], "update() (ldp.alg.optimizer.ape.apeopt method)": [[4, "ldp.alg.optimizer.ape.APEOpt.update", false]], "update() (ldp.alg.optimizer.apeopt method)": [[4, "ldp.alg.optimizer.APEOpt.update", false]], "update() (ldp.alg.optimizer.chainedoptimizer method)": [[4, "ldp.alg.optimizer.ChainedOptimizer.update", false]], "update() (ldp.alg.optimizer.memory.memoryopt method)": [[4, "ldp.alg.optimizer.memory.MemoryOpt.update", false]], "update() (ldp.alg.optimizer.memoryopt method)": [[4, "ldp.alg.optimizer.MemoryOpt.update", false]], "update() (ldp.alg.optimizer.opt.chainedoptimizer method)": [[4, "ldp.alg.optimizer.opt.ChainedOptimizer.update", false]], "update() (ldp.alg.optimizer.opt.optimizer method)": [[4, "ldp.alg.optimizer.opt.Optimizer.update", false]], "update() (ldp.alg.optimizer.optimizer method)": [[4, "ldp.alg.optimizer.Optimizer.update", false]], "update() (ldp.graph.opctx method)": [[5, "ldp.graph.OpCtx.update", false]], "update() (ldp.graph.ops.opctx method)": [[5, "ldp.graph.ops.OpCtx.update", false]], "update() (ldp.shims.tqdm method)": [[1, "ldp.shims.tqdm.update", false]], "update_every (ldp.alg.offlinetrainerconfig attribute)": [[3, "ldp.alg.OfflineTrainerConfig.update_every", false]], "update_every (ldp.alg.onlinetrainerconfig attribute)": [[3, "ldp.alg.OnlineTrainerConfig.update_every", false]], "update_every (ldp.alg.runners.offlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OfflineTrainerConfig.update_every", false]], "update_every (ldp.alg.runners.onlinetrainerconfig attribute)": [[3, "ldp.alg.runners.OnlineTrainerConfig.update_every", false]], "validate_json_completion() (in module ldp.llms)": [[7, "ldp.llms.validate_json_completion", false]], "validate_json_completion() (in module ldp.llms.chat)": [[7, "ldp.llms.chat.validate_json_completion", false]], "validate_score_fn() (ldp.alg.optimizer.ape.apeopt method)": [[4, "ldp.alg.optimizer.ape.APEOpt.validate_score_fn", false]], "validate_score_fn() (ldp.alg.optimizer.apeopt method)": [[4, "ldp.alg.optimizer.APEOpt.validate_score_fn", false]], "validate_uuid() (ldp.graph.callid class method)": [[5, "ldp.graph.CallID.validate_uuid", false]], "validate_uuid() (ldp.graph.op_utils.callid class method)": [[5, "ldp.graph.op_utils.CallID.validate_uuid", false]], "value (ldp.data_structures.transition attribute)": [[1, "ldp.data_structures.Transition.value", false]], "value (ldp.graph.memory attribute)": [[5, "ldp.graph.Memory.value", false]], "value (ldp.graph.memory.memory attribute)": [[5, "ldp.graph.memory.Memory.value", false]], "value_prompt_func (ldp.agent.tree_of_thoughts_agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent.value_prompt_func", false]], "value_prompt_func (ldp.agent.treeofthoughtsagent attribute)": [[2, "ldp.agent.TreeofThoughtsAgent.value_prompt_func", false]], "wandbloggingcallback (class in ldp.alg)": [[3, "ldp.alg.WandBLoggingCallback", false]], "wandbloggingcallback (class in ldp.alg.callbacks)": [[3, "ldp.alg.callbacks.WandBLoggingCallback", false]], "wrapattr() (ldp.shims.tqdm class method)": [[1, "ldp.shims.tqdm.wrapattr", false]], "write() (ldp.shims.tqdm class method)": [[1, "ldp.shims.tqdm.write", false]], "xml (ldp.graph.modules.react.tooldescriptionmethods attribute)": [[6, "ldp.graph.modules.react.ToolDescriptionMethods.XML", false]], "xml (ldp.graph.modules.tooldescriptionmethods attribute)": [[6, "ldp.graph.modules.ToolDescriptionMethods.XML", false]], "zero_estimator() (in module ldp.graph.gradient_estimators)": [[5, "ldp.graph.gradient_estimators.zero_estimator", false]]}, "objects": {"": [[1, 0, 0, "-", "ldp"]], "ldp": [[2, 0, 0, "-", "agent"], [3, 0, 0, "-", "alg"], [1, 0, 0, "-", "data_structures"], [5, 0, 0, "-", "graph"], [7, 0, 0, "-", "llms"], [1, 0, 0, "-", "main"], [1, 0, 0, "-", "shims"], [1, 0, 0, "-", "utils"]], "ldp.agent": [[2, 1, 1, "", "Agent"], [2, 1, 1, "", "AgentConfig"], [2, 1, 1, "", "DefaultLLMModelNames"], [2, 1, 1, "", "HTTPAgentClient"], [2, 1, 1, "", "MemoryAgent"], [2, 1, 1, "", "ReActAgent"], [2, 1, 1, "", "SimpleAgent"], [2, 1, 1, "", "SimpleAgentState"], [2, 1, 1, "", "TreeofThoughtsAgent"], [2, 0, 0, "-", "agent"], [2, 0, 0, "-", "agent_client"], [2, 0, 0, "-", "interactive_agent"], [2, 4, 1, "", "make_simple_agent_server"], [2, 0, 0, "-", "memory_agent"], [2, 0, 0, "-", "react_agent"], [2, 0, 0, "-", "simple_agent"], [2, 0, 0, "-", "tree_of_thoughts_agent"]], "ldp.agent.Agent": [[2, 2, 1, "", "from_name"], [2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 2, 1, "", "named_ops"]], "ldp.agent.AgentConfig": [[2, 3, 1, "", "agent_kwargs"], [2, 3, 1, "", "agent_type"], [2, 2, 1, "", "construct_agent"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"]], "ldp.agent.DefaultLLMModelNames": [[2, 3, 1, "", "OPENAI"]], "ldp.agent.HTTPAgentClient": [[2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"]], "ldp.agent.MemoryAgent": [[2, 2, 1, "", "default_query_factory"], [2, 2, 1, "", "get_asv"], [2, 3, 1, "", "llm_model"], [2, 3, 1, "", "memory_prompt"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "num_memories"], [2, 3, 1, "", "prompt"], [2, 3, 1, "", "query_factory"], [2, 3, 1, "", "sys_prompt"]], "ldp.agent.ReActAgent": [[2, 2, 1, "", "after_retry_failure_log"], [2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 3, 1, "", "llm_model"], [2, 2, 1, "", "make_act_agent"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "sys_prompt"], [2, 3, 1, "", "tool_description_method"]], "ldp.agent.SimpleAgent": [[2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 3, 1, "", "llm_model"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "sys_prompt"]], "ldp.agent.SimpleAgentState": [[2, 2, 1, "", "get_next_state"], [2, 3, 1, "", "messages"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "tools"]], "ldp.agent.TreeofThoughtsAgent": [[2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 3, 1, "", "llm_model"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "proposal_prompt_func"], [2, 3, 1, "", "value_prompt_func"]], "ldp.agent.agent": [[2, 1, 1, "", "Agent"], [2, 1, 1, "", "AgentConfig"]], "ldp.agent.agent.Agent": [[2, 2, 1, "", "from_name"], [2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 2, 1, "", "named_ops"]], "ldp.agent.agent.AgentConfig": [[2, 3, 1, "", "agent_kwargs"], [2, 3, 1, "", "agent_type"], [2, 2, 1, "", "construct_agent"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"]], "ldp.agent.agent_client": [[2, 1, 1, "", "HTTPAgentClient"], [2, 4, 1, "", "make_simple_agent_server"]], "ldp.agent.agent_client.HTTPAgentClient": [[2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"]], "ldp.agent.interactive_agent": [[2, 1, 1, "", "InteractiveAgent"]], "ldp.agent.interactive_agent.InteractiveAgent": [[2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"]], "ldp.agent.memory_agent": [[2, 1, 1, "", "MemoryAgent"]], "ldp.agent.memory_agent.MemoryAgent": [[2, 2, 1, "", "default_query_factory"], [2, 2, 1, "", "get_asv"], [2, 3, 1, "", "memory_prompt"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "num_memories"], [2, 3, 1, "", "prompt"], [2, 3, 1, "", "query_factory"]], "ldp.agent.react_agent": [[2, 1, 1, "", "ReActAgent"]], "ldp.agent.react_agent.ReActAgent": [[2, 2, 1, "", "after_retry_failure_log"], [2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 3, 1, "", "llm_model"], [2, 2, 1, "", "make_act_agent"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "sys_prompt"], [2, 3, 1, "", "tool_description_method"]], "ldp.agent.simple_agent": [[2, 1, 1, "", "SimpleAgent"], [2, 1, 1, "", "SimpleAgentState"]], "ldp.agent.simple_agent.SimpleAgent": [[2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 3, 1, "", "llm_model"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "sys_prompt"]], "ldp.agent.simple_agent.SimpleAgentState": [[2, 2, 1, "", "get_next_state"], [2, 3, 1, "", "messages"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "tools"]], "ldp.agent.tree_of_thoughts_agent": [[2, 1, 1, "", "TreeofThoughtsAgent"]], "ldp.agent.tree_of_thoughts_agent.TreeofThoughtsAgent": [[2, 2, 1, "", "get_asv"], [2, 2, 1, "", "init_state"], [2, 3, 1, "", "llm_model"], [2, 3, 1, "", "model_computed_fields"], [2, 3, 1, "", "model_config"], [2, 3, 1, "", "model_fields"], [2, 3, 1, "", "proposal_prompt_func"], [2, 3, 1, "", "value_prompt_func"]], "ldp.alg": [[3, 1, 1, "", "Beam"], [3, 1, 1, "", "BeamSearchRollout"], [3, 1, 1, "", "Callback"], [3, 1, 1, "", "ClearContextCallback"], [3, 1, 1, "", "ComputeTrajectoryMetricsMixin"], [3, 1, 1, "", "Evaluator"], [3, 1, 1, "", "EvaluatorConfig"], [3, 1, 1, "", "LoggingCallback"], [3, 1, 1, "", "MeanMetricsCallback"], [3, 1, 1, "", "OfflineTrainer"], [3, 1, 1, "", "OfflineTrainerConfig"], [3, 1, 1, "", "OnlineTrainer"], [3, 1, 1, "", "OnlineTrainerConfig"], [3, 1, 1, "", "RolloutDebugDumpCallback"], [3, 1, 1, "", "RolloutManager"], [3, 1, 1, "", "TrajectoryFileCallback"], [3, 1, 1, "", "TrajectoryMetricsCallback"], [3, 1, 1, "", "TreeSearchRollout"], [3, 1, 1, "", "WandBLoggingCallback"], [3, 0, 0, "-", "algorithms"], [3, 0, 0, "-", "beam_search"], [3, 0, 0, "-", "callbacks"], [3, 0, 0, "-", "datasets"], [4, 0, 0, "-", "optimizer"], [3, 0, 0, "-", "rollout"], [3, 0, 0, "-", "runners"], [3, 4, 1, "", "to_network"], [3, 0, 0, "-", "tree_search"]], "ldp.alg.Beam": [[3, 3, 1, "", "env"], [3, 3, 1, "", "traj"]], "ldp.alg.BeamSearchRollout": [[3, 2, 1, "", "sample_trajectories"]], "ldp.alg.Callback": [[3, 2, 1, "", "after_agent_get_asv"], [3, 2, 1, "", "after_agent_init_state"], [3, 2, 1, "", "after_env_reset"], [3, 2, 1, "", "after_env_step"], [3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_eval_step"], [3, 2, 1, "", "after_train_step"], [3, 2, 1, "", "after_transition"], [3, 2, 1, "", "after_update"], [3, 2, 1, "", "before_eval_loop"], [3, 2, 1, "", "before_transition"]], "ldp.alg.ClearContextCallback": [[3, 2, 1, "", "after_eval_step"], [3, 2, 1, "", "after_update"]], "ldp.alg.ComputeTrajectoryMetricsMixin": [[3, 2, 1, "", "compute_trajectory_metrics"], [3, 3, 1, "", "tools_to_track"]], "ldp.alg.Evaluator": [[3, 2, 1, "", "evaluate"], [3, 2, 1, "", "run"]], "ldp.alg.EvaluatorConfig": [[3, 3, 1, "", "batch_size"], [3, 3, 1, "", "catch_agent_failures"], [3, 3, 1, "", "catch_env_failures"], [3, 3, 1, "", "clear_ctx_at_each_iter"], [3, 2, 1, "", "make_rollout_manager"], [3, 3, 1, "", "max_rollout_steps"], [3, 3, 1, "", "model_computed_fields"], [3, 3, 1, "", "model_config"], [3, 3, 1, "", "model_fields"], [3, 3, 1, "", "num_eval_iterations"]], "ldp.alg.LoggingCallback": [[3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_train_step"]], "ldp.alg.MeanMetricsCallback": [[3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_train_step"], [3, 5, 1, "", "eval_means"], [3, 5, 1, "", "train_means"]], "ldp.alg.OfflineTrainer": [[3, 2, 1, "", "train"]], "ldp.alg.OfflineTrainerConfig": [[3, 3, 1, "", "batch_size"], [3, 3, 1, "", "clear_ctx_at_each_iter"], [3, 3, 1, "", "model_computed_fields"], [3, 3, 1, "", "model_config"], [3, 3, 1, "", "model_fields"], [3, 3, 1, "", "update_every"]], "ldp.alg.OnlineTrainer": [[3, 2, 1, "", "evaluate"], [3, 2, 1, "", "train"]], "ldp.alg.OnlineTrainerConfig": [[3, 3, 1, "", "batch_size"], [3, 3, 1, "", "catch_agent_failures"], [3, 3, 1, "", "catch_env_failures"], [3, 3, 1, "", "clear_ctx_at_each_iter"], [3, 3, 1, "", "eval_before"], [3, 3, 1, "", "eval_every"], [3, 3, 1, "", "max_rollout_steps"], [3, 3, 1, "", "model_computed_fields"], [3, 3, 1, "", "model_config"], [3, 3, 1, "", "model_fields"], [3, 3, 1, "", "num_eval_iterations"], [3, 3, 1, "", "num_rollouts_per_env"], [3, 3, 1, "", "num_train_iterations"], [3, 3, 1, "", "update_every"]], "ldp.alg.RolloutDebugDumpCallback": [[3, 2, 1, "", "after_agent_get_asv"], [3, 2, 1, "", "after_env_step"], [3, 2, 1, "", "before_transition"]], "ldp.alg.RolloutManager": [[3, 2, 1, "", "sample_trajectories"]], "ldp.alg.TrajectoryFileCallback": [[3, 2, 1, "", "after_transition"], [3, 2, 1, "", "before_transition"], [3, 2, 1, "", "cleanup"]], "ldp.alg.TrajectoryMetricsCallback": [[3, 2, 1, "", "after_env_reset"], [3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_eval_step"], [3, 2, 1, "", "after_train_step"]], "ldp.alg.TreeSearchRollout": [[3, 2, 1, "", "sample_tree"], [3, 2, 1, "", "sample_trees"]], "ldp.alg.WandBLoggingCallback": [[3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_train_step"]], "ldp.alg.algorithms": [[3, 4, 1, "", "to_network"]], "ldp.alg.beam_search": [[3, 1, 1, "", "Beam"], [3, 1, 1, "", "BeamSearchRollout"]], "ldp.alg.beam_search.Beam": [[3, 3, 1, "", "env"], [3, 3, 1, "", "traj"]], "ldp.alg.beam_search.BeamSearchRollout": [[3, 2, 1, "", "sample_trajectories"]], "ldp.alg.callbacks": [[3, 1, 1, "", "Callback"], [3, 1, 1, "", "ClearContextCallback"], [3, 1, 1, "", "ComputeTrajectoryMetricsMixin"], [3, 1, 1, "", "LoggingCallback"], [3, 1, 1, "", "MeanMetricsCallback"], [3, 1, 1, "", "RolloutDebugDumpCallback"], [3, 1, 1, "", "TerminalPrintingCallback"], [3, 1, 1, "", "TrajectoryFileCallback"], [3, 1, 1, "", "TrajectoryMetricsCallback"], [3, 1, 1, "", "WandBLoggingCallback"]], "ldp.alg.callbacks.Callback": [[3, 2, 1, "", "after_agent_get_asv"], [3, 2, 1, "", "after_agent_init_state"], [3, 2, 1, "", "after_env_reset"], [3, 2, 1, "", "after_env_step"], [3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_eval_step"], [3, 2, 1, "", "after_train_step"], [3, 2, 1, "", "after_transition"], [3, 2, 1, "", "after_update"], [3, 2, 1, "", "before_eval_loop"], [3, 2, 1, "", "before_transition"]], "ldp.alg.callbacks.ClearContextCallback": [[3, 2, 1, "", "after_eval_step"], [3, 2, 1, "", "after_update"]], "ldp.alg.callbacks.ComputeTrajectoryMetricsMixin": [[3, 2, 1, "", "compute_trajectory_metrics"], [3, 3, 1, "", "tools_to_track"]], "ldp.alg.callbacks.LoggingCallback": [[3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_train_step"]], "ldp.alg.callbacks.MeanMetricsCallback": [[3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_train_step"], [3, 5, 1, "", "eval_means"], [3, 5, 1, "", "train_means"]], "ldp.alg.callbacks.RolloutDebugDumpCallback": [[3, 2, 1, "", "after_agent_get_asv"], [3, 2, 1, "", "after_env_step"], [3, 2, 1, "", "before_transition"]], "ldp.alg.callbacks.TerminalPrintingCallback": [[3, 2, 1, "", "after_agent_get_asv"], [3, 2, 1, "", "after_env_step"], [3, 2, 1, "", "before_transition"]], "ldp.alg.callbacks.TrajectoryFileCallback": [[3, 2, 1, "", "after_transition"], [3, 2, 1, "", "before_transition"], [3, 2, 1, "", "cleanup"]], "ldp.alg.callbacks.TrajectoryMetricsCallback": [[3, 2, 1, "", "after_env_reset"], [3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_eval_step"], [3, 2, 1, "", "after_train_step"]], "ldp.alg.callbacks.WandBLoggingCallback": [[3, 2, 1, "", "after_eval_loop"], [3, 2, 1, "", "after_train_step"]], "ldp.alg.datasets": [[3, 1, 1, "", "DummyTaskDataset"]], "ldp.alg.optimizer": [[4, 1, 1, "", "APEOpt"], [4, 1, 1, "", "APEScoreFn"], [4, 1, 1, "", "ChainedOptimizer"], [4, 1, 1, "", "MemoryFactory"], [4, 1, 1, "", "MemoryOpt"], [4, 1, 1, "", "Optimizer"], [4, 1, 1, "", "OptimizerConfig"], [4, 1, 1, "", "PositiveMemoryOpt"], [4, 0, 0, "-", "ape"], [4, 4, 1, "", "default_optimizer_factory"], [4, 0, 0, "-", "memory"], [4, 0, 0, "-", "opt"], [4, 0, 0, "-", "replay_buffers"]], "ldp.alg.optimizer.APEOpt": [[4, 2, 1, "", "aggregate_trajectory"], [4, 3, 1, "", "examples"], [4, 2, 1, "", "from_agent"], [4, 3, 1, "", "good_examples"], [4, 3, 1, "", "good_reward_threshold"], [4, 3, 1, "", "llm"], [4, 3, 1, "", "llm_call_op"], [4, 3, 1, "", "max_examples"], [4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 2, 1, "", "model_post_init"], [4, 3, 1, "", "prompt_op"], [4, 3, 1, "", "query_prompt"], [4, 3, 1, "", "reward_discount"], [4, 3, 1, "", "score_fn"], [4, 3, 1, "", "steps"], [4, 3, 1, "", "system_prompt"], [4, 3, 1, "", "trace"], [4, 2, 1, "", "update"], [4, 2, 1, "", "validate_score_fn"]], "ldp.alg.optimizer.APEScoreFn": [[4, 3, 1, "", "GRADIENT"], [4, 3, 1, "", "REWARD"]], "ldp.alg.optimizer.ChainedOptimizer": [[4, 2, 1, "", "aggregate"], [4, 2, 1, "", "update"]], "ldp.alg.optimizer.MemoryOpt": [[4, 2, 1, "", "aggregate_trajectory"], [4, 2, 1, "", "default_memory_factory"], [4, 3, 1, "", "example_buffer"], [4, 2, 1, "", "from_agent"], [4, 3, 1, "", "memory_factory"], [4, 3, 1, "", "memory_op"], [4, 3, 1, "", "memory_template"], [4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 3, 1, "", "output_op"], [4, 3, 1, "", "reward_discount"], [4, 3, 1, "", "steps"], [4, 2, 1, "", "update"]], "ldp.alg.optimizer.Optimizer": [[4, 2, 1, "", "aggregate"], [4, 2, 1, "", "aggregate_trajectory"], [4, 2, 1, "", "update"]], "ldp.alg.optimizer.OptimizerConfig": [[4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 3, 1, "", "optimizer_kwargs"], [4, 3, 1, "", "optimizer_type"]], "ldp.alg.optimizer.PositiveMemoryOpt": [[4, 3, 1, "", "example_buffer"], [4, 3, 1, "", "memory_factory"], [4, 3, 1, "", "memory_op"], [4, 3, 1, "", "memory_template"], [4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 3, 1, "", "output_op"], [4, 3, 1, "", "reward_discount"], [4, 3, 1, "", "steps"]], "ldp.alg.optimizer.ape": [[4, 1, 1, "", "APEOpt"], [4, 1, 1, "", "APEScoreFn"], [4, 1, 1, "", "Example"], [4, 1, 1, "", "OutputPrompt"], [4, 4, 1, "", "get_formatted_variables"]], "ldp.alg.optimizer.ape.APEOpt": [[4, 2, 1, "", "aggregate_trajectory"], [4, 3, 1, "", "examples"], [4, 2, 1, "", "from_agent"], [4, 3, 1, "", "good_examples"], [4, 3, 1, "", "good_reward_threshold"], [4, 3, 1, "", "llm"], [4, 3, 1, "", "llm_call_op"], [4, 3, 1, "", "max_examples"], [4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 2, 1, "", "model_post_init"], [4, 3, 1, "", "prompt_op"], [4, 3, 1, "", "query_prompt"], [4, 3, 1, "", "reward_discount"], [4, 3, 1, "", "score_fn"], [4, 3, 1, "", "steps"], [4, 3, 1, "", "system_prompt"], [4, 3, 1, "", "trace"], [4, 2, 1, "", "update"], [4, 2, 1, "", "validate_score_fn"]], "ldp.alg.optimizer.ape.APEScoreFn": [[4, 3, 1, "", "GRADIENT"], [4, 3, 1, "", "REWARD"]], "ldp.alg.optimizer.ape.Example": [[4, 3, 1, "", "input"], [4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 3, 1, "", "output"], [4, 3, 1, "", "score"]], "ldp.alg.optimizer.ape.OutputPrompt": [[4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 3, 1, "", "prompt"]], "ldp.alg.optimizer.memory": [[4, 1, 1, "", "MemoryFactory"], [4, 1, 1, "", "MemoryOpt"], [4, 1, 1, "", "PositiveMemoryOpt"]], "ldp.alg.optimizer.memory.MemoryOpt": [[4, 2, 1, "", "aggregate_trajectory"], [4, 2, 1, "", "default_memory_factory"], [4, 3, 1, "", "example_buffer"], [4, 2, 1, "", "from_agent"], [4, 3, 1, "", "memory_factory"], [4, 3, 1, "", "memory_op"], [4, 3, 1, "", "memory_template"], [4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"], [4, 3, 1, "", "output_op"], [4, 3, 1, "", "reward_discount"], [4, 3, 1, "", "steps"], [4, 2, 1, "", "update"]], "ldp.alg.optimizer.memory.PositiveMemoryOpt": [[4, 3, 1, "", "model_computed_fields"], [4, 3, 1, "", "model_config"], [4, 3, 1, "", "model_fields"]], "ldp.alg.optimizer.opt": [[4, 1, 1, "", "ChainedOptimizer"], [4, 1, 1, "", "Optimizer"]], "ldp.alg.optimizer.opt.ChainedOptimizer": [[4, 2, 1, "", "aggregate"], [4, 2, 1, "", "update"]], "ldp.alg.optimizer.opt.Optimizer": [[4, 2, 1, "", "aggregate"], [4, 2, 1, "", "aggregate_trajectory"], [4, 2, 1, "", "update"]], "ldp.alg.optimizer.replay_buffers": [[4, 1, 1, "", "CircularReplayBuffer"]], "ldp.alg.optimizer.replay_buffers.CircularReplayBuffer": [[4, 2, 1, "", "batched_iter"], [4, 2, 1, "", "resize"]], "ldp.alg.rollout": [[3, 6, 1, "", "AgentError"], [3, 6, 1, "", "CaughtError"], [3, 6, 1, "", "EnvError"], [3, 1, 1, "", "RolloutManager"], [3, 4, 1, "", "reraise_exc_as"]], "ldp.alg.rollout.AgentError": [[3, 3, 1, "", "exc_type"]], "ldp.alg.rollout.CaughtError": [[3, 3, 1, "", "exc_type"]], "ldp.alg.rollout.EnvError": [[3, 3, 1, "", "exc_type"]], "ldp.alg.rollout.RolloutManager": [[3, 2, 1, "", "sample_trajectories"]], "ldp.alg.runners": [[3, 1, 1, "", "Evaluator"], [3, 1, 1, "", "EvaluatorConfig"], [3, 1, 1, "", "OfflineTrainer"], [3, 1, 1, "", "OfflineTrainerConfig"], [3, 1, 1, "", "OnlineTrainer"], [3, 1, 1, "", "OnlineTrainerConfig"]], "ldp.alg.runners.Evaluator": [[3, 2, 1, "", "evaluate"], [3, 2, 1, "", "run"]], "ldp.alg.runners.EvaluatorConfig": [[3, 3, 1, "", "batch_size"], [3, 3, 1, "", "catch_agent_failures"], [3, 3, 1, "", "catch_env_failures"], [3, 3, 1, "", "clear_ctx_at_each_iter"], [3, 2, 1, "", "make_rollout_manager"], [3, 3, 1, "", "max_rollout_steps"], [3, 3, 1, "", "model_computed_fields"], [3, 3, 1, "", "model_config"], [3, 3, 1, "", "model_fields"], [3, 3, 1, "", "num_eval_iterations"]], "ldp.alg.runners.OfflineTrainer": [[3, 2, 1, "", "train"]], "ldp.alg.runners.OfflineTrainerConfig": [[3, 3, 1, "", "batch_size"], [3, 3, 1, "", "clear_ctx_at_each_iter"], [3, 3, 1, "", "model_computed_fields"], [3, 3, 1, "", "model_config"], [3, 3, 1, "", "model_fields"], [3, 3, 1, "", "update_every"]], "ldp.alg.runners.OnlineTrainer": [[3, 2, 1, "", "evaluate"], [3, 2, 1, "", "train"]], "ldp.alg.runners.OnlineTrainerConfig": [[3, 3, 1, "", "batch_size"], [3, 3, 1, "", "clear_ctx_at_each_iter"], [3, 3, 1, "", "eval_before"], [3, 3, 1, "", "eval_every"], [3, 3, 1, "", "model_computed_fields"], [3, 3, 1, "", "model_config"], [3, 3, 1, "", "model_fields"], [3, 3, 1, "", "num_rollouts_per_env"], [3, 3, 1, "", "num_train_iterations"], [3, 3, 1, "", "update_every"]], "ldp.alg.tree_search": [[3, 1, 1, "", "TreeSearchRollout"]], "ldp.alg.tree_search.TreeSearchRollout": [[3, 2, 1, "", "sample_tree"], [3, 2, 1, "", "sample_trees"]], "ldp.data_structures": [[1, 1, 1, "", "Trajectory"], [1, 1, 1, "", "Transition"], [1, 1, 1, "", "TransitionTree"]], "ldp.data_structures.Trajectory": [[1, 2, 1, "", "compute_discounted_returns"], [1, 5, 1, "", "done"], [1, 5, 1, "", "failed"], [1, 2, 1, "", "from_jsonl"], [1, 3, 1, "", "model_computed_fields"], [1, 3, 1, "", "model_config"], [1, 3, 1, "", "model_fields"], [1, 3, 1, "", "steps"], [1, 2, 1, "", "to_jsonl"], [1, 3, 1, "", "traj_id"]], "ldp.data_structures.Transition": [[1, 3, 1, "", "NO_OBSERVATION"], [1, 3, 1, "", "action"], [1, 3, 1, "", "agent_state"], [1, 2, 1, "", "construct_action"], [1, 3, 1, "", "done"], [1, 5, 1, "", "failed"], [1, 3, 1, "", "metadata"], [1, 3, 1, "", "model_computed_fields"], [1, 3, 1, "", "model_config"], [1, 2, 1, "", "model_dump_json"], [1, 3, 1, "", "model_fields"], [1, 3, 1, "", "next_agent_state"], [1, 3, 1, "", "next_observation"], [1, 3, 1, "", "observation"], [1, 3, 1, "", "reward"], [1, 3, 1, "", "timestep"], [1, 3, 1, "", "truncated"], [1, 3, 1, "", "value"]], "ldp.data_structures.TransitionTree": [[1, 2, 1, "", "add_transition"], [1, 2, 1, "", "assign_mc_value_estimates"], [1, 2, 1, "", "get_trajectories"], [1, 2, 1, "", "get_transition"], [1, 2, 1, "", "get_weight"], [1, 2, 1, "", "merge_identical_nodes"]], "ldp.graph": [[5, 1, 1, "", "CallID"], [5, 1, 1, "", "ConfigOp"], [5, 1, 1, "", "EmbeddingOp"], [5, 1, 1, "", "FxnOp"], [5, 1, 1, "", "IdentityOp"], [5, 1, 1, "", "LLMCallOp"], [5, 1, 1, "", "MSELossOp"], [5, 1, 1, "", "Memory"], [5, 1, 1, "", "MemoryModel"], [5, 1, 1, "", "MemoryOp"], [5, 1, 1, "", "Op"], [5, 1, 1, "", "OpCtx"], [5, 1, 1, "", "OpResult"], [5, 1, 1, "", "PromptOp"], [5, 0, 0, "-", "async_torch"], [5, 0, 0, "-", "common_ops"], [5, 4, 1, "", "compute_graph"], [5, 4, 1, "", "get_call_id"], [5, 4, 1, "", "get_run_id"], [5, 4, 1, "", "get_training_mode"], [5, 0, 0, "-", "gradient_estimators"], [5, 0, 0, "-", "loss_ops"], [5, 0, 0, "-", "memory"], [6, 0, 0, "-", "modules"], [5, 4, 1, "", "op_call"], [5, 0, 0, "-", "op_utils"], [5, 0, 0, "-", "ops"], [5, 4, 1, "", "set_training_mode"], [5, 0, 0, "-", "torch_ops"]], "ldp.graph.CallID": [[5, 3, 1, "", "fwd_id"], [5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 3, 1, "", "run_id"], [5, 2, 1, "", "serialize_uuid"], [5, 2, 1, "", "validate_uuid"]], "ldp.graph.ConfigOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.EmbeddingOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.FxnOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.IdentityOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.LLMCallOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "compute_logprob"], [5, 2, 1, "", "forward"], [5, 2, 1, "", "get_examples"]], "ldp.graph.MSELossOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.Memory": [[5, 2, 1, "", "ensure_query"], [5, 2, 1, "", "from_ops"], [5, 3, 1, "", "input"], [5, 3, 1, "", "metadata"], [5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 3, 1, "", "output"], [5, 3, 1, "", "query"], [5, 3, 1, "", "run_id"], [5, 3, 1, "", "template"], [5, 3, 1, "", "value"]], "ldp.graph.MemoryModel": [[5, 3, 1, "", "DEFAULT_MEMORY_MATCHES"], [5, 2, 1, "", "add_memory"], [5, 3, 1, "", "embedding_model"], [5, 2, 1, "", "enforce_empty"], [5, 2, 1, "", "get_memory"], [5, 3, 1, "", "memories"], [5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 2, 1, "", "model_post_init"], [5, 2, 1, "", "safe_access_index"]], "ldp.graph.MemoryOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.Op": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "clear_ctx"], [5, 3, 1, "", "ctx"], [5, 2, 1, "", "forward"], [5, 2, 1, "", "get_call_ids"], [5, 2, 1, "", "get_input_grads"], [5, 3, 1, "", "name"], [5, 2, 1, "", "set_name"]], "ldp.graph.OpCtx": [[5, 2, 1, "", "clear_contexts"], [5, 3, 1, "", "data"], [5, 2, 1, "", "get"], [5, 2, 1, "", "get_input_grads"], [5, 2, 1, "", "get_or_create"], [5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 2, 1, "", "model_post_init"], [5, 3, 1, "", "op_name"], [5, 2, 1, "", "update"]], "ldp.graph.OpResult": [[5, 2, 1, "", "compute_grads"], [5, 5, 1, "", "ctx"], [5, 2, 1, "", "from_dict"], [5, 2, 1, "", "get_compute_graph"], [5, 5, 1, "", "grad"], [5, 5, 1, "", "inputs"], [5, 5, 1, "", "logprob"], [5, 5, 1, "", "op_class"], [5, 5, 1, "", "run_id"], [5, 2, 1, "", "to_dict"], [5, 2, 1, "", "traverse"], [5, 2, 1, "", "unwrap_value"]], "ldp.graph.async_torch": [[5, 1, 1, "", "AsyncTorchModule"], [5, 4, 1, "", "async_protect_torch_call"]], "ldp.graph.common_ops": [[5, 1, 1, "", "Cacheable"], [5, 1, 1, "", "ConfigOp"], [5, 1, 1, "", "EmbeddingOp"], [5, 1, 1, "", "FxnOp"], [5, 1, 1, "", "IdentityOp"], [5, 1, 1, "", "LLMCallOp"], [5, 1, 1, "", "MemoryOp"], [5, 1, 1, "", "PromptOp"], [5, 1, 1, "", "StopGradOp"], [5, 4, 1, "", "async_cache"], [5, 4, 1, "", "logsumexp"]], "ldp.graph.common_ops.Cacheable": [[5, 2, 1, "", "get_result"]], "ldp.graph.common_ops.ConfigOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.common_ops.EmbeddingOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.common_ops.FxnOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.common_ops.IdentityOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.common_ops.LLMCallOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "compute_logprob"], [5, 2, 1, "", "forward"], [5, 2, 1, "", "get_examples"]], "ldp.graph.common_ops.MemoryOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.common_ops.StopGradOp": [[5, 2, 1, "", "backward"]], "ldp.graph.gradient_estimators": [[5, 1, 1, "", "TorchParamBackwardEstimator"], [5, 4, 1, "", "assign_constant_grads"], [5, 4, 1, "", "assign_default_grads"], [5, 4, 1, "", "llm_straight_through_estimator"], [5, 4, 1, "", "stop_grad"], [5, 4, 1, "", "straight_through_estimator"], [5, 4, 1, "", "zero_estimator"]], "ldp.graph.gradient_estimators.TorchParamBackwardEstimator": [[5, 2, 1, "", "backward"]], "ldp.graph.loss_ops": [[5, 1, 1, "", "MSELossOp"]], "ldp.graph.loss_ops.MSELossOp": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.graph.memory": [[5, 1, 1, "", "Memory"], [5, 1, 1, "id0", "MemoryModel"], [5, 1, 1, "", "UIndexMemoryModel"]], "ldp.graph.memory.Memory": [[5, 2, 1, "", "ensure_query"], [5, 2, 1, "", "from_ops"], [5, 3, 1, "", "input"], [5, 3, 1, "", "metadata"], [5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 3, 1, "", "output"], [5, 3, 1, "", "query"], [5, 3, 1, "", "run_id"], [5, 3, 1, "", "template"], [5, 3, 1, "", "value"]], "ldp.graph.memory.MemoryModel": [[5, 3, 1, "id15", "DEFAULT_MEMORY_MATCHES"], [5, 2, 1, "id16", "add_memory"], [5, 3, 1, "id17", "embedding_model"], [5, 2, 1, "id18", "enforce_empty"], [5, 2, 1, "id19", "get_memory"], [5, 3, 1, "id20", "memories"], [5, 3, 1, "id21", "model_computed_fields"], [5, 3, 1, "id22", "model_config"], [5, 3, 1, "id23", "model_fields"], [5, 2, 1, "id24", "model_post_init"], [5, 2, 1, "id25", "safe_access_index"]], "ldp.graph.memory.UIndexMemoryModel": [[5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 2, 1, "", "model_post_init"]], "ldp.graph.modules": [[6, 1, 1, "", "ParsedLLMCallModule"], [6, 1, 1, "", "ReActModule"], [6, 1, 1, "", "ReflectModule"], [6, 1, 1, "", "ReflectModuleConfig"], [6, 1, 1, "", "ThoughtModule"], [6, 1, 1, "", "ToolDescriptionMethods"], [6, 0, 0, "-", "llm_call"], [6, 4, 1, "", "parse_message"], [6, 0, 0, "-", "react"], [6, 0, 0, "-", "reflect"], [6, 0, 0, "-", "thought"]], "ldp.graph.modules.ReActModule": [[6, 2, 1, "", "parse_message"]], "ldp.graph.modules.ReflectModuleConfig": [[6, 3, 1, "", "llm_model"], [6, 3, 1, "", "model_computed_fields"], [6, 3, 1, "", "model_config"], [6, 3, 1, "", "model_fields"]], "ldp.graph.modules.ToolDescriptionMethods": [[6, 3, 1, "", "JSON"], [6, 3, 1, "", "STR"], [6, 3, 1, "", "XML"], [6, 2, 1, "", "get_prompt_prefix"]], "ldp.graph.modules.llm_call": [[6, 1, 1, "", "ParsedLLMCallModule"]], "ldp.graph.modules.react": [[6, 1, 1, "", "ReActModule"], [6, 1, 1, "", "ToolDescriptionMethods"], [6, 4, 1, "", "parse_message"]], "ldp.graph.modules.react.ReActModule": [[6, 2, 1, "", "parse_message"]], "ldp.graph.modules.react.ToolDescriptionMethods": [[6, 3, 1, "", "JSON"], [6, 3, 1, "", "STR"], [6, 3, 1, "", "XML"], [6, 2, 1, "", "get_prompt_prefix"]], "ldp.graph.modules.reflect": [[6, 1, 1, "", "ReflectModule"], [6, 1, 1, "", "ReflectModuleConfig"]], "ldp.graph.modules.reflect.ReflectModuleConfig": [[6, 3, 1, "", "llm_model"], [6, 3, 1, "", "model_computed_fields"], [6, 3, 1, "", "model_config"], [6, 3, 1, "", "model_fields"]], "ldp.graph.modules.thought": [[6, 1, 1, "", "ThoughtModule"]], "ldp.graph.op_utils": [[5, 1, 1, "", "CallID"], [5, 4, 1, "", "compute_graph"], [5, 4, 1, "", "get_call_id"], [5, 4, 1, "", "get_run_id"], [5, 4, 1, "", "get_training_mode"], [5, 4, 1, "", "op_call"], [5, 4, 1, "", "set_training_mode"]], "ldp.graph.op_utils.CallID": [[5, 3, 1, "", "fwd_id"], [5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 3, 1, "", "run_id"], [5, 2, 1, "", "serialize_uuid"], [5, 2, 1, "", "validate_uuid"]], "ldp.graph.ops": [[5, 1, 1, "", "Op"], [5, 1, 1, "", "OpCtx"], [5, 1, 1, "", "OpResult"], [5, 4, 1, "", "resolve_fully_qualified_name"]], "ldp.graph.ops.Op": [[5, 2, 1, "", "backward"], [5, 2, 1, "", "clear_ctx"], [5, 3, 1, "", "ctx"], [5, 2, 1, "", "forward"], [5, 2, 1, "", "get_call_ids"], [5, 2, 1, "", "get_input_grads"], [5, 3, 1, "", "name"], [5, 2, 1, "", "set_name"]], "ldp.graph.ops.OpCtx": [[5, 2, 1, "", "clear_contexts"], [5, 3, 1, "", "data"], [5, 2, 1, "", "get"], [5, 2, 1, "", "get_input_grads"], [5, 2, 1, "", "get_or_create"], [5, 3, 1, "", "model_computed_fields"], [5, 3, 1, "", "model_config"], [5, 3, 1, "", "model_fields"], [5, 2, 1, "", "model_post_init"], [5, 3, 1, "", "op_name"], [5, 2, 1, "", "update"]], "ldp.graph.ops.OpResult": [[5, 2, 1, "", "compute_grads"], [5, 5, 1, "", "ctx"], [5, 2, 1, "", "from_dict"], [5, 2, 1, "", "get_compute_graph"], [5, 5, 1, "", "grad"], [5, 5, 1, "", "inputs"], [5, 5, 1, "", "logprob"], [5, 5, 1, "", "op_class"], [5, 5, 1, "", "run_id"], [5, 2, 1, "", "to_dict"], [5, 2, 1, "", "traverse"], [5, 2, 1, "", "unwrap_value"]], "ldp.graph.torch_ops": [[5, 1, 1, "", "TorchOp"], [5, 4, 1, "", "store_tensor_inputs"]], "ldp.graph.torch_ops.TorchOp": [[5, 3, 1, "", "CTX_TENSOR_INPUT_KEY"], [5, 2, 1, "", "backward"], [5, 2, 1, "", "forward"]], "ldp.llms": [[7, 1, 1, "", "EmbeddingModel"], [7, 1, 1, "", "EmbeddingModes"], [7, 1, 1, "", "HybridEmbeddingModel"], [7, 6, 1, "", "JSONSchemaValidationError"], [7, 1, 1, "", "LLMModel"], [7, 1, 1, "", "LLMResult"], [7, 1, 1, "", "LiteEmbeddingModel"], [7, 1, 1, "", "MultipleCompletionLLMModel"], [7, 1, 1, "", "SparseEmbeddingModel"], [7, 4, 1, "", "append_to_messages"], [7, 4, 1, "", "append_to_sys"], [7, 0, 0, "-", "chat"], [7, 0, 0, "-", "embeddings"], [7, 4, 1, "", "prepend_sys"], [7, 4, 1, "", "prepend_sys_and_append_sys"], [7, 0, 0, "-", "prompts"], [7, 4, 1, "", "sum_logprobs"], [7, 4, 1, "", "validate_json_completion"]], "ldp.llms.EmbeddingModel": [[7, 3, 1, "", "dimensions"], [7, 2, 1, "", "embed_text"], [7, 2, 1, "", "embed_texts"], [7, 2, 1, "", "from_name"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"], [7, 2, 1, "", "set_mode"]], "ldp.llms.EmbeddingModes": [[7, 3, 1, "", "DOCUMENT"], [7, 3, 1, "", "QUERY"]], "ldp.llms.HybridEmbeddingModel": [[7, 3, 1, "", "dimensions"], [7, 2, 1, "", "embed_texts"], [7, 2, 1, "", "infer_dimensions"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "models"], [7, 3, 1, "", "name"]], "ldp.llms.LLMModel": [[7, 2, 1, "", "call"], [7, 3, 1, "", "config"], [7, 3, 1, "", "encoding"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"]], "ldp.llms.LLMResult": [[7, 3, 1, "", "completion_count"], [7, 3, 1, "", "config"], [7, 3, 1, "", "date"], [7, 2, 1, "", "get_supported_openai_params"], [7, 3, 1, "", "id"], [7, 3, 1, "", "logprob"], [7, 3, 1, "", "messages"], [7, 3, 1, "", "model"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "prompt"], [7, 5, 1, "", "prompt_and_completion_costs"], [7, 3, 1, "", "prompt_count"], [7, 5, 1, "", "provider"], [7, 3, 1, "", "seconds_to_first_token"], [7, 3, 1, "", "seconds_to_last_token"], [7, 3, 1, "", "system_fingerprint"]], "ldp.llms.LiteEmbeddingModel": [[7, 3, 1, "", "batch_size"], [7, 3, 1, "", "dimensions"], [7, 3, 1, "", "embed_kwargs"], [7, 2, 1, "", "embed_texts"], [7, 2, 1, "", "infer_dimensions"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"]], "ldp.llms.MultipleCompletionLLMModel": [[7, 3, 1, "", "TOOL_CHOICE_REQUIRED"], [7, 2, 1, "", "achat"], [7, 2, 1, "", "achat_iter"], [7, 2, 1, "", "call"], [7, 3, 1, "", "config"], [7, 3, 1, "", "encoding"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"], [7, 2, 1, "", "set_model_name"]], "ldp.llms.SparseEmbeddingModel": [[7, 3, 1, "", "dimensions"], [7, 2, 1, "", "embed_texts"], [7, 3, 1, "", "enc"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"]], "ldp.llms.chat": [[7, 6, 1, "", "JSONSchemaValidationError"], [7, 1, 1, "", "LLMModel"], [7, 1, 1, "", "LLMResult"], [7, 1, 1, "", "MultipleCompletionLLMModel"], [7, 4, 1, "", "sum_logprobs"], [7, 4, 1, "", "validate_json_completion"]], "ldp.llms.chat.LLMModel": [[7, 2, 1, "", "call"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"]], "ldp.llms.chat.LLMResult": [[7, 3, 1, "", "completion_count"], [7, 3, 1, "", "config"], [7, 3, 1, "", "date"], [7, 2, 1, "", "get_supported_openai_params"], [7, 3, 1, "", "id"], [7, 3, 1, "", "logprob"], [7, 3, 1, "", "messages"], [7, 3, 1, "", "model"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "prompt"], [7, 5, 1, "", "prompt_and_completion_costs"], [7, 3, 1, "", "prompt_count"], [7, 5, 1, "", "provider"], [7, 3, 1, "", "seconds_to_first_token"], [7, 3, 1, "", "seconds_to_last_token"], [7, 3, 1, "", "system_fingerprint"]], "ldp.llms.chat.MultipleCompletionLLMModel": [[7, 3, 1, "", "TOOL_CHOICE_REQUIRED"], [7, 2, 1, "", "achat"], [7, 2, 1, "", "achat_iter"], [7, 2, 1, "", "call"], [7, 3, 1, "", "config"], [7, 3, 1, "", "encoding"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"], [7, 2, 1, "", "set_model_name"]], "ldp.llms.embeddings": [[7, 1, 1, "", "EmbeddingModel"], [7, 1, 1, "", "EmbeddingModes"], [7, 1, 1, "", "HybridEmbeddingModel"], [7, 1, 1, "", "LiteEmbeddingModel"], [7, 1, 1, "", "SparseEmbeddingModel"]], "ldp.llms.embeddings.EmbeddingModel": [[7, 3, 1, "", "dimensions"], [7, 2, 1, "", "embed_text"], [7, 2, 1, "", "embed_texts"], [7, 2, 1, "", "from_name"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"], [7, 2, 1, "", "set_mode"]], "ldp.llms.embeddings.EmbeddingModes": [[7, 3, 1, "", "DOCUMENT"], [7, 3, 1, "", "QUERY"]], "ldp.llms.embeddings.HybridEmbeddingModel": [[7, 2, 1, "", "embed_texts"], [7, 2, 1, "", "infer_dimensions"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "models"], [7, 3, 1, "", "name"]], "ldp.llms.embeddings.LiteEmbeddingModel": [[7, 3, 1, "", "batch_size"], [7, 3, 1, "", "dimensions"], [7, 3, 1, "", "embed_kwargs"], [7, 2, 1, "", "embed_texts"], [7, 2, 1, "", "infer_dimensions"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"]], "ldp.llms.embeddings.SparseEmbeddingModel": [[7, 3, 1, "", "dimensions"], [7, 2, 1, "", "embed_texts"], [7, 3, 1, "", "enc"], [7, 3, 1, "", "model_computed_fields"], [7, 3, 1, "", "model_config"], [7, 3, 1, "", "model_fields"], [7, 3, 1, "", "name"]], "ldp.llms.prompts": [[7, 4, 1, "", "append_to_messages"], [7, 4, 1, "", "append_to_sys"], [7, 4, 1, "", "indent_xml"], [7, 4, 1, "", "prepend_sys"], [7, 4, 1, "", "prepend_sys_and_append_sys"]], "ldp.main": [[1, 4, 1, "", "get_or_make_agent"], [1, 4, 1, "", "get_or_make_environment"], [1, 4, 1, "", "main"]], "ldp.shims": [[1, 1, 1, "", "tqdm"], [1, 4, 1, "", "trange"]], "ldp.shims.tqdm": [[1, 2, 1, "", "clear"], [1, 2, 1, "", "close"], [1, 2, 1, "", "display"], [1, 2, 1, "", "external_write_mode"], [1, 5, 1, "", "format_dict"], [1, 2, 1, "", "format_interval"], [1, 2, 1, "", "format_meter"], [1, 2, 1, "", "format_num"], [1, 2, 1, "", "format_sizeof"], [1, 2, 1, "", "get_lock"], [1, 3, 1, "", "monitor"], [1, 3, 1, "", "monitor_interval"], [1, 2, 1, "", "moveto"], [1, 2, 1, "", "pandas"], [1, 2, 1, "", "refresh"], [1, 2, 1, "", "reset"], [1, 2, 1, "", "set_description"], [1, 2, 1, "", "set_description_str"], [1, 2, 1, "", "set_lock"], [1, 2, 1, "", "set_postfix"], [1, 2, 1, "", "set_postfix_str"], [1, 2, 1, "", "status_printer"], [1, 2, 1, "", "unpause"], [1, 2, 1, "", "update"], [1, 2, 1, "", "wrapattr"], [1, 2, 1, "", "write"]], "ldp.utils": [[1, 4, 1, "", "configure_log_levels"], [1, 4, 1, "", "configure_stdout_logs"], [1, 4, 1, "", "discounted_returns"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "function", "Python function"], "5": ["py", "property", "Python property"], "6": ["py", "exception", "Python exception"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:attribute", "4": "py:function", "5": "py:property", "6": "py:exception"}, "terms": {"": [1, 2, 3, 4, 5, 7], "0": [1, 2, 3, 4, 5, 7], "00ff00": 1, "03629": [2, 6], "06": 2, "08": 2, "0f": 1, "1": [1, 2, 3, 4, 5, 6, 7], "10": 1, "100": 1, "1000": 1, "100000": 1, "123456789": 1, "16": 7, "18603270": 1, "2": [1, 5, 7], "20": 1, "2024": 2, "2210": [2, 6], "23": 1, "24": 2, "256": 7, "3": [1, 2, 5, 6, 7], "382": 1, "3f": 1, "3g": 1, "4": [1, 5], "4o": 2, "5": [1, 5, 6, 7], "50": [1, 4], "5xc1ecxo1h": 2, "6": 1, "7": [1, 2, 6], "8": 1, "9": 1, "92gvk82de": 4, "9e9": 1, "A": [1, 2, 3, 4, 5, 6, 7], "As": 2, "By": 4, "For": [1, 5], "If": [1, 2, 3, 4, 5, 7], "In": 5, "It": [2, 3, 4, 5], "One": 2, "Or": 5, "That": [2, 5], "The": [1, 2, 4, 5, 6, 7], "There": 2, "These": 5, "Will": 5, "_": 1, "__": 1, "__call__": 5, "__fields__": [1, 2, 3, 4, 5, 6, 7], "__init__": 4, "_apeopt__context": 4, "_default_memory_factori": 4, "_default_query_factori": 2, "_eval_loop": 3, "a_t": 1, "ab": [1, 2, 6], "abc": [1, 2, 4, 5, 7], "about": [1, 2, 3, 4, 5, 6, 7], "abov": 2, "abstract": [2, 4, 5, 7], "accept": 5, "access": [1, 2, 6], "account": 1, "achat": [1, 7], "achat_it": [1, 7], "acquir": 1, "act": [1, 2, 4, 6], "action": [1, 2, 3, 5, 6, 8], "actual": 2, "ad": 1, "add": [1, 3, 4], "add_memori": [1, 5], "add_transit": [1, 8], "addit": [1, 2, 4], "adjust": 1, "aembed": 7, "affect": [2, 7], "after": [1, 3, 4], "after_agent_get_asv": [1, 3], "after_agent_init_st": [1, 3], "after_env_reset": [1, 3], "after_env_step": [1, 3], "after_eval_loop": [1, 3], "after_eval_step": [1, 3], "after_retry_failure_log": [1, 2], "after_train_step": [1, 3], "after_transit": [1, 3], "after_upd": [1, 3], "against": 7, "agent": [0, 1, 3, 4, 8], "agent_cli": [1, 8], "agent_clone_fn": 3, "agent_kwarg": [1, 2], "agent_st": [1, 2, 3, 8], "agent_state_hash_fn": 1, "agent_typ": [1, 2], "agentconfig": [1, 2], "agenterror": [1, 3], "aggreg": [3, 4, 5], "aggregate_trajectori": [3, 4], "alg": [0, 1, 8], "algorithm": [1, 8], "alia": 3, "alias": 1, "all": [1, 3, 4, 5, 7], "allow": [1, 3], "along": 2, "alreadi": 5, "also": [2, 5], "alter": 1, "alwai": [2, 6], "an": [1, 2, 4, 5, 6, 7], "analog": [2, 6], "ani": [1, 2, 3, 4, 5, 6, 7], "anim": 1, "annot": [1, 2, 3, 4, 5, 6, 7], "answer": [2, 6], "ap": [1, 3], "apeopt": [3, 4], "apescorefn": [3, 4], "api": 1, "app": 2, "append": [1, 7], "append_to_messag": [1, 7], "append_to_si": [1, 7], "appli": [1, 5], "appropri": 1, "approxim": 5, "ar": [1, 2, 3, 4, 5], "arbitrari": 1, "arbitrary_types_allow": [1, 4, 5, 7], "aren": 2, "arg": [1, 2, 3, 4, 5, 7], "argument": [1, 2, 4, 5], "arxiv": [2, 6], "ascii": 1, "asctim": 1, "assign": [1, 5], "assign_constant_grad": [1, 5], "assign_default_grad": [1, 5], "assign_mc_value_estim": [1, 8], "assist": [2, 6], "associ": 5, "async": [1, 2, 3, 4, 5, 7], "async_cach": [1, 5], "async_protect_torch_cal": [1, 5], "async_torch": [1, 8], "asyncbufferedwork": 5, "asyncgener": 7, "asynciter": 5, "asynctorchmodul": [1, 5], "attempt": [1, 2, 7], "attribut": 5, "augment": 4, "autocast_device_typ": 5, "autocast_dtyp": 5, "autograd": 5, "automat": [1, 4], "avail": 2, "averag": 1, "aviari": [1, 2, 5], "avoid": [1, 2], "await": [2, 3, 5], "b": 5, "back": 5, "backend": 5, "backprop": 5, "backpropag": 5, "backward": [1, 5], "backward_fn": 5, "backwardstyp": 5, "bar": 1, "bar_format": 1, "base": [1, 2, 3, 4, 5, 6, 7], "baselin": 2, "basemodel": [1, 2, 3, 4, 5, 6, 7], "basic": [1, 4, 5], "batch": 3, "batch_siz": [1, 3, 4, 5, 7], "batched_it": [3, 4], "beam": [1, 3], "beam_search": [1, 8], "beam_width": 3, "beamsearchrollout": [1, 3], "becaus": [2, 3, 5], "been": [1, 5], "befor": [2, 3], "before_eval_loop": [1, 3], "before_transit": [1, 3], "behav": 5, "behavior": 1, "being": 4, "below": 4, "best": [2, 6, 7], "better": 4, "between": [1, 3], "blank": 1, "block": 1, "bool": [1, 2, 3, 4, 5], "boolean": 1, "both": [1, 5], "bother": 5, "bound": 1, "boundari": [2, 4, 6, 7], "brain": 2, "branching_factor": 3, "break": 1, "bucket": 2, "buffer": 4, "built": [2, 6], "builtin_function_or_method": 7, "by_alia": 1, "byte": 1, "c": 5, "cacheabl": [1, 5], "calcul": [1, 3, 5, 7], "call": [1, 2, 3, 5, 7], "call_id": 5, "callabl": [1, 2, 3, 5, 6, 7], "callback": [1, 7, 8], "caller": 1, "callid": [1, 4, 5], "can": [1, 2, 3, 4, 5, 6], "capabl": 2, "carlo": [1, 4, 5], "case": 5, "catch": 3, "catch_agent_failur": [1, 3], "catch_env_failur": [1, 3], "caughterror": [1, 3], "chainedoptim": [3, 4], "chang": 2, "char": 3, "charact": 1, "chat": [1, 2, 6, 8], "chat_kwarg": 7, "check": 5, "choic": [5, 7], "choos": 2, "chosen": 2, "chunk": 1, "chunk_siz": 1, "circular": 1, "circularreplaybuff": [3, 4], "cl": 5, "class": [1, 2, 3, 4, 5, 6, 7], "classmethod": [1, 2, 4, 5, 7], "classvar": [1, 2, 3, 4, 5, 6, 7], "cleanup": [1, 3], "clear": [1, 5, 8], "clear_context": [1, 5], "clear_ctx": [1, 5], "clear_ctx_at_each_it": [1, 3], "clearcontextcallback": [1, 3], "clock": 1, "close": [1, 8], "co": 5, "code": 2, "collate_fn": 5, "collect": [1, 2, 3, 5, 7], "colour": 1, "com": 1, "combin": [1, 2], "come": [1, 2], "comma": [2, 6], "common_op": [1, 4, 8], "commonli": [4, 5], "compact": 1, "compar": 1, "compat": 5, "complet": [1, 2, 4, 7], "completion_count": [1, 7], "compos": 5, "comput": [1, 2, 3, 4, 5, 6, 7], "compute_discounted_return": [1, 8], "compute_grad": [1, 5], "compute_graph": [1, 5], "compute_logprob": [1, 5], "compute_trajectory_metr": [1, 3], "computedfieldinfo": [1, 2, 3, 4, 5, 6, 7], "computetrajectorymetricsmixin": [1, 3], "concept": 1, "concis": 4, "concurr": 3, "concurrency_limit": 3, "config": [1, 2, 3, 4, 5, 6, 7], "configdict": [1, 2, 3, 4, 5, 6, 7], "configop": [1, 5], "configur": [1, 2, 3, 4, 5, 6, 7], "configure_log_level": [0, 1, 8], "configure_stdout_log": [0, 1, 8], "confirm": 6, "conform": [1, 2, 3, 4, 5, 6, 7], "consid": [1, 5], "consol": 3, "constantli": 1, "construct": [1, 4, 5], "construct_act": [1, 8], "construct_ag": [1, 2], "constructor": 2, "consum": 5, "contain": [2, 5], "content": 8, "context": [1, 5], "conveni": 1, "copi": [2, 5], "core": [1, 5], "correct": 4, "correspond": [1, 2, 3, 4, 5, 6, 7], "cost": 7, "could": [1, 2, 5], "count": 7, "counter": 1, "cpu": 1, "creat": [1, 2, 4, 5], "ctx": [1, 5], "ctx_tensor_input_kei": [1, 5], "cumul": [1, 2], "current": [1, 2, 4, 5], "current_buff": 1, "custom": [1, 3], "d": 5, "dai": [2, 6], "data": [1, 5, 7], "data_structur": [0, 8], "datafram": 1, "dataframegroupbi": 1, "dataset": [1, 8], "datatyp": 1, "date": [1, 7], "db": 5, "debug": [1, 5], "decid": [1, 5], "decis": 2, "decollate_fn": 5, "decor": [1, 5], "default": [1, 2, 3, 4, 5, 6, 7], "default_col": 5, "default_factori": [1, 2, 4, 5, 7], "default_grad_v": 5, "default_memory_factori": [3, 4], "default_memory_match": [1, 5], "default_optimizer_factori": [3, 4], "default_query_factori": [1, 2], "defaultllmmodelnam": [1, 2], "defin": [1, 2, 3, 4, 5, 6, 7], "delai": 1, "demonstr": 3, "depend": 5, "depth": 5, "deriv": 5, "desc": 1, "descend": 5, "describ": [2, 6], "describe_json": 6, "describe_str": [2, 6], "describe_xml": 6, "descript": [1, 2, 3, 4, 5, 6, 7], "design": 2, "desir": [2, 4, 5], "detach": 5, "detail": [4, 5], "dev": 1, "df": 1, "dict": [1, 2, 3, 4, 5, 6, 7], "dictat": 2, "dictionari": [1, 2, 3, 4, 5, 6, 7], "differ": [2, 5, 7], "differenti": 5, "digraph": 5, "dimens": [1, 7], "direct": [3, 5], "directori": 3, "disabl": 1, "discount": [1, 2], "discount_factor": 1, "discounted_return": [0, 1, 8], "displai": [1, 8], "divisor": 1, "do": [1, 2, 4, 5, 6], "doc": 1, "document": [1, 7], "doe": [1, 2, 3, 7], "doesn": 2, "domain": 2, "don": [1, 2, 5], "done": [1, 3, 5, 8], "dot": 3, "draw": 3, "dreampuf": 3, "dtype": 5, "duck": 1, "dummytaskdataset": [1, 3], "dump": [1, 3, 5], "dure": [1, 3, 5], "dynam": [1, 5], "dynamic_minit": 1, "dynamic_ncol": 1, "e": [1, 2, 3, 5, 7], "each": [1, 2, 3, 5], "edg": 3, "effici": 1, "eg": 1, "elaps": 1, "elapsed_": 1, "element": [1, 5], "emb": 7, "embed": [1, 5, 8], "embed_kwarg": [1, 7], "embed_text": [1, 7], "embedding_model": [1, 5], "embeddingmod": [1, 7], "embeddingmodel": [1, 5, 7], "embeddingop": [1, 5], "emit": 1, "emploi": 2, "empti": 1, "emul": 5, "enabl": [1, 3], "enc": [1, 7], "encod": [1, 7], "encount": 1, "end": 1, "enforce_empti": [1, 5], "engin": 4, "enough": 5, "ensure_queri": [1, 5], "entail": 2, "entir": [1, 4], "entiti": [2, 6], "entri": [2, 6], "enum": 7, "env": [1, 3], "env_clone_fn": 3, "enverror": [1, 3], "environ": [1, 2, 3], "environment_factori": 3, "episod": [1, 2], "equal": 1, "equival": 5, "errat": 1, "error": 1, "escap": 2, "estim": [1, 2, 5], "eta": 1, "etc": [1, 5], "eval": 3, "eval_befor": [1, 3], "eval_dataset": 3, "eval_everi": [1, 3], "eval_funct": 2, "eval_mean": [1, 3], "evalu": [1, 2, 3], "evaluatorconfig": [1, 3], "everi": [1, 3, 5], "exact": 2, "exactli": 1, "exampl": [1, 2, 3, 4, 5, 7], "example_buff": [3, 4], "exc_typ": [1, 3], "except": [1, 3, 7], "exclud": [1, 2, 4, 5], "exclude_default": 1, "exclude_non": 1, "exclude_unset": 1, "execut": [3, 5], "exhaust": 3, "exist": [1, 5, 7], "exit": 1, "expans": 1, "expect": 1, "explicit": 2, "explicitli": 1, "explor": 2, "exponenti": 1, "export": 3, "expos": 6, "extend": [2, 3, 4], "external_write_mod": [1, 8], "extra": [1, 2, 3, 4, 7], "extra_kwarg": 1, "face": 5, "factor": 1, "factori": 4, "fail": [1, 5, 7, 8], "failur": 2, "fallback": 1, "fals": [1, 2, 3, 4, 5, 6, 7], "far": 2, "fast": 1, "fastapi": 2, "field": [1, 2, 3, 4, 5, 6, 7], "fieldinfo": [1, 2, 3, 4, 5, 6, 7], "file": [1, 3], "file_obj": 1, "filenam": 1, "files": 1, "fill": 1, "filter": [3, 5], "filter_fn": 5, "final_sys_cont": 7, "fingerprint": 7, "finish": [1, 3], "first": [1, 2, 5], "first_sys_prompt": 6, "flag": 1, "float": [1, 2, 3, 4, 5, 7], "flush": 1, "fmt": 1, "fobj": 1, "follow": [1, 2, 4, 6], "forbid": [1, 2, 3, 4, 7], "forc": 1, "forecast": [2, 6], "form": [1, 5], "format": [1, 2, 4, 5, 6], "format_dict": [1, 8], "format_interv": [1, 8], "format_met": [1, 8], "format_num": [1, 8], "format_sizeof": [1, 8], "forum": 2, "forward": [1, 4, 5], "frame": 1, "from": [1, 2, 3, 4, 5, 6, 7], "from_ag": [3, 4], "from_dict": [1, 5], "from_jsonl": [1, 8], "from_nam": [1, 2, 7], "from_op": [1, 5], "front": 6, "frozen": 2, "func": 5, "function": [1, 2, 3, 4, 5, 7], "further": 4, "futur": [1, 2], "fwd_arg": 5, "fwd_id": [1, 5], "fxn": 5, "fxnop": [1, 5], "g": [1, 3, 5, 7], "g_t": 1, "game": 2, "gamma": 1, "ge": 3, "gener": [1, 2, 4, 5, 6], "get": [1, 2, 5, 6, 7], "get_asv": [1, 2, 3], "get_call_id": [1, 5], "get_compute_graph": [1, 5], "get_exampl": [1, 5], "get_formatted_vari": [3, 4], "get_input_grad": [1, 5], "get_lock": [1, 8], "get_memori": [1, 5], "get_next_st": [1, 2], "get_or_cr": [1, 5], "get_or_make_ag": [0, 1, 8], "get_or_make_environ": [0, 1, 8], "get_prompt_prefix": [5, 6], "get_result": [1, 5], "get_run_id": [1, 5], "get_supported_openai_param": [1, 7], "get_training_mod": [1, 5], "get_trajectori": [1, 8], "get_transit": [1, 8], "get_weath": [2, 6], "get_weight": [1, 8], "github": 3, "give": 6, "given": [1, 2, 5], "global": 1, "go": 1, "goe": 5, "good": [1, 4], "good_exampl": [3, 4], "good_reward_threshold": [3, 4], "gpt": [2, 6, 7], "gpu": 2, "grad": [1, 5], "grad_input": 5, "grad_output": 5, "grad_param": 5, "gradient": [3, 4, 5], "gradient_estim": [1, 8], "gradintyp": 5, "graph": [0, 1, 3, 4, 8], "graphic": 1, "graphviz": 3, "graphvizonlin": 3, "greater": 1, "green": 1, "groupbi": 1, "gui": 1, "h": 1, "ha": [1, 2, 6], "handl": 1, "hashabl": 1, "have": [1, 2, 5, 6, 7], "height": [1, 3], "hello": 7, "help": 2, "helper": 5, "here": [1, 2, 4], "heurist": 2, "hide": 1, "highli": 1, "histori": [2, 4], "hold": 7, "hood": 2, "how": [1, 2, 3, 5], "howev": 1, "http": [1, 2, 3, 4, 6], "httpagentcli": [1, 2], "human": 2, "hybrid": 7, "hybridembeddingmodel": [1, 7], "hydrat": 5, "hyperparamet": 2, "i": [1, 2, 3, 4, 5, 6, 7], "id": [1, 2, 4, 5, 7], "idempot": 1, "ident": 1, "identifi": 1, "identityop": [1, 5], "ignor": 1, "impact": 1, "implement": [4, 5], "impli": 4, "import": 1, "improv": 4, "includ": [1, 2, 4, 5, 7], "incorrect": 4, "increment": 1, "indent": 1, "indent_s": 7, "indent_xml": [1, 7], "index": [0, 1, 5], "indic": 1, "individu": 2, "inf": 1, "infer": 7, "infer_dimens": [1, 7], "infinit": 4, "inform": [3, 5], "infti": 1, "inherit": 1, "init_st": [1, 2, 3], "initi": [1, 2, 4, 5, 7], "initial_sys_cont": 7, "initialis": [1, 5], "initlist": 4, "input": [1, 2, 3, 4, 5, 6], "input_arg": 5, "input_grad": 5, "input_grad_arg": 5, "input_grad_kwarg": 5, "input_kwarg": 5, "insid": [4, 5], "instanc": [1, 5], "instantan": 1, "instanti": 4, "instead": [1, 2, 5], "int": [1, 2, 3, 4, 5, 7], "integr": 2, "intellig": 1, "interact": [2, 5], "interactive_ag": [1, 8], "interactiveag": [1, 2], "interfac": 2, "intermedi": [1, 2], "intern": [1, 5, 7], "interv": 1, "invok": [2, 3], "involv": [2, 4], "io": [1, 3], "irrelev": 2, "issu": 2, "item": [1, 5], "iter": [1, 2, 3, 4, 5, 7], "its": 5, "join": 1, "json": [1, 2, 5, 6, 7], "jsonl": 3, "jsonschemavalidationerror": [1, 7], "jsonvalu": [1, 2, 4, 5], "just": 2, "k": [1, 5], "keep": 1, "kei": 5, "keyword": [2, 5, 7], "kick": 3, "kilo": 1, "kwarg": [1, 2, 3, 4, 5, 7], "l_bar": 1, "label": 3, "lag": 1, "lambda": [1, 2, 5, 7], "languag": [2, 4, 5], "larg": 1, "larger": [4, 5], "last": 1, "latter": 1, "lazili": 5, "learn": 4, "learnabl": [2, 6], "leav": [1, 5], "led": 5, "left": 7, "len": 1, "length": [5, 7], "level": 1, "levelnam": 1, "lightweight": 2, "like": [1, 2, 5, 6], "limit": [1, 4], "line": [1, 3], "linear": 5, "list": [1, 2, 3, 4, 5, 6, 7], "liteembeddingmodel": [1, 7], "litellm": [5, 7], "live": [1, 2], "llm": [0, 1, 2, 3, 4, 5, 6, 8], "llm_call": [1, 5], "llm_call_op": [3, 4], "llm_model": [1, 2, 5, 6], "llm_straight_through_estim": [1, 5], "llmcallop": [1, 4, 5], "llmmodel": [1, 4, 5, 7], "llmresult": [1, 5, 7], "ln": 5, "local": 2, "lock": [1, 5], "lock_arg": 1, "log": [1, 3, 5, 7], "logger": 1, "loggingcallback": [1, 3], "logic": 2, "logprob": [1, 2, 4, 5, 7], "logsumexp": [1, 5], "long": 1, "longer": 1, "loop": [1, 3], "loss": 5, "loss_op": [1, 8], "m": [1, 6], "magnitud": 1, "mai": [1, 5], "main": [0, 8], "maintain": 2, "make": [2, 4], "make_act_ag": [1, 2], "make_rollout_manag": [1, 3], "make_simple_agent_serv": [1, 2], "manag": [1, 5], "mani": 3, "manual": 1, "map": [1, 2, 3, 4, 5, 6, 7], "mark": 3, "match": [5, 7], "matplotlib": 1, "matter": 2, "max": [3, 4], "max_depth": 3, "max_exampl": [3, 4], "max_label_height": 3, "max_label_width": 3, "max_rollout_step": [1, 3], "max_step": 3, "max_wait_interv": 5, "maximum": 1, "maxinterv": 1, "mdp": 1, "mean": [1, 2, 3, 4], "meaningless": 1, "meanmetricscallback": [1, 3], "meant": [2, 5], "measur": 5, "mechan": 2, "mega": 1, "mem_call_id": 5, "mem_op": 5, "member": 1, "memori": [1, 2, 3, 8], "memory_ag": [1, 8], "memory_factori": [3, 4], "memory_op": [3, 4], "memory_prompt": [1, 2], "memory_templ": [3, 4], "memoryag": [1, 2, 4], "memoryfactori": [3, 4], "memorymodel": [1, 5], "memoryop": [1, 2, 4, 5], "memoryopt": [3, 4], "mention": 4, "merg": 1, "merge_identical_nod": [1, 8], "messag": [1, 2, 3, 5, 6, 7], "metadata": [1, 2, 3, 4, 5, 6, 7, 8], "meter": 1, "method": [1, 2, 3, 4, 5, 6], "metric": [1, 3], "metrics_to_log": 3, "minim": 4, "minimum": 1, "mininterv": 1, "minit": 1, "mistral": 7, "mix": 7, "mixin": 3, "mm": 1, "mode": [1, 3, 4, 5, 7], "model": [1, 2, 3, 4, 5, 6, 7], "model_computed_field": [1, 2, 3, 4, 5, 6, 7, 8], "model_config": [1, 2, 3, 4, 5, 6, 7, 8], "model_construct": 4, "model_dump": 5, "model_dump_json": [1, 8], "model_field": [1, 2, 3, 4, 5, 6, 7, 8], "model_kwarg": 5, "model_post_init": [1, 3, 4, 5], "modelmodel_dump_json": 1, "modelrespons": 7, "modifi": [1, 7], "modified_messag": 7, "modul": [0, 8], "module_call_fn": 5, "monitor": [1, 8], "monitor_interv": [1, 8], "mont": [1, 4, 5], "more": [1, 2, 4, 5], "most": [2, 5], "move": 1, "moveto": [1, 8], "mselossop": [1, 5], "msg": [1, 5], "much": 5, "multi": 3, "multidigraph": 3, "multipl": 1, "multiplecompletionllmmodel": [1, 7], "must": 5, "mutat": 2, "n": [1, 2, 4, 6, 7], "n_fmt": 1, "n_select_sampl": 2, "n_step": 2, "naction": [2, 6], "name": [1, 2, 3, 4, 5, 6, 7], "named_op": [1, 2], "named_paramet": 2, "namedtupl": 3, "ncol": 1, "nconsid": 2, "ndarrai": [5, 7], "necessari": [1, 2, 5], "necessarili": 2, "need": [1, 2, 5, 6], "neg": 2, "nest": 1, "net": [2, 4], "network": 1, "networkx": 3, "new": [1, 2, 4, 5, 6, 7], "new_messag": 7, "nexampl": [2, 6], "next": [1, 2], "next_agent_st": [1, 3, 8], "next_observ": [1, 8], "next_observation_hash_fn": 1, "nn": [2, 5, 6], "no_grad": 5, "no_observ": [1, 8], "nobserv": [2, 6], "node": [1, 2, 3, 5, 6], "nolock": 1, "non": [1, 4, 5], "none": [1, 2, 3, 4, 5, 6, 7], "nonetyp": [1, 2, 3, 4, 5, 7], "notabl": 2, "notat": 1, "note": [1, 2, 3, 5, 6], "noutput": [4, 5], "now": 1, "np": 1, "npt": 5, "nrevis": 4, "nreward": 4, "nrow": 1, "nthe": 4, "nthese": 2, "nthought": [2, 6], "num": 1, "num_eval_iter": [1, 3], "num_memori": [1, 2], "num_rollouts_per_env": [1, 3], "num_train_iter": [1, 3], "number": [1, 2, 3, 4], "numer": 1, "numpi": 1, "nuse": [2, 6], "nvalu": 5, "nwhich": 4, "nx": 3, "nx_pydot": 3, "o_t": 1, "ob": [2, 3], "object": [1, 2, 3, 4, 5, 6, 7], "observ": [1, 2, 3, 5, 6, 8], "observation_hash_fn": 1, "off": 3, "offlin": 3, "offlinetrain": [1, 3], "offlinetrainerconfig": [1, 3], "offset": 1, "onc": [1, 7], "one": [2, 3, 6], "ones": 2, "onli": [1, 5], "onlin": 3, "onlinetrain": [1, 3], "onlinetrainerconfig": [1, 3], "onward": 1, "op": [1, 2, 3, 4, 6, 8], "op_cal": [1, 5], "op_class": [1, 5], "op_class_nam": 5, "op_nam": [1, 3, 5], "op_result": 3, "op_util": [1, 4, 8], "opctx": [1, 5], "openai": [1, 2, 7], "openreview": [2, 4], "oper": [1, 2, 5], "opresult": [1, 2, 3, 5], "opt": [1, 2, 3], "optim": [1, 3, 5], "optimizer_cl": 4, "optimizer_kwarg": [3, 4], "optimizer_typ": [3, 4], "optimizerconfig": [3, 4], "option": [1, 2, 3, 5, 7], "orchestr": 2, "order": [1, 3, 4, 5], "ordered_dict": 1, "ordereddict": 1, "org": [2, 6], "origin": [1, 2], "original_exc": 3, "other": [1, 5, 7], "otherwis": 5, "out": 1, "output": [1, 2, 3, 4, 5, 7], "output_call_id": 5, "output_dir": 3, "output_op": [3, 4, 5], "output_typ": 7, "outputprompt": [3, 4], "outsid": 1, "over": [3, 5], "overlap": 1, "overload": 1, "overrid": [1, 4], "p": 5, "p_": 5, "packag": [0, 8], "page": 0, "panda": [1, 8], "paper": [2, 4, 6], "paramet": [1, 2, 3, 4, 5, 6, 7], "parent": [1, 3], "pars": 6, "parse_messag": [5, 6], "parsedllmcallmodul": [5, 6], "parser": 6, "partial": 2, "pass": [1, 2, 3, 5, 7], "patch": 5, "path": [1, 2], "pathlik": [1, 3], "pd": 1, "pdf": 4, "per": 3, "percentag": 1, "perfect": 2, "perform": [1, 2, 3, 4], "persist": 5, "pick": 2, "pin": 2, "place": [1, 2, 5, 7], "plain": 2, "png": 3, "po": 1, "point": 5, "pomdp": 2, "popul": 3, "portion": 3, "posit": [1, 2, 5], "positivememoryopt": [3, 4], "possibl": [1, 2, 4, 6], "possibli": 1, "post": [1, 2], "postfix": 1, "potenti": 2, "predict": 5, "prefix": [1, 6], "prepend": 7, "prepend_si": [1, 7], "prepend_sys_and_append_si": [1, 7], "previou": 2, "print": [1, 3], "prior": 2, "prior_stat": 2, "privat": 5, "probabl": [2, 7], "problem": 2, "process": [2, 3, 6], "produc": 4, "progress": 1, "progress_appli": 1, "progressbar": 1, "promis": 2, "prompt": [1, 2, 3, 4, 5, 6, 8], "prompt_and_completion_cost": [1, 7], "prompt_count": [1, 7], "prompt_op": [3, 4], "promptop": [1, 4, 5], "propag": 5, "properti": [1, 3, 5, 7], "propos": [2, 4], "proposal_prompt_func": [1, 2], "protect": 5, "protocol": 4, "provid": [1, 2, 3, 4, 5, 7], "pseudocod": 3, "public": 1, "pull": 2, "purpos": [1, 5], "put": 6, "puzzl": 2, "pydant": [1, 2, 3, 4, 5, 6, 7], "pydantic_cor": 1, "pydanticserializationerror": 1, "python": [1, 2, 5, 6], "pytorch": [5, 6], "q": [1, 2], "qualiti": 5, "qualnam": [2, 4, 6, 7], "queri": [1, 2, 5, 7], "query_factori": [1, 2], "query_prompt": [3, 4], "question": [1, 2, 6], "quit": 2, "r_": 1, "r_bar": 1, "r_t": 1, "rais": [1, 5, 7], "randint": 1, "randn": 5, "random": 1, "rang": 1, "rate": [1, 3], "rate_fmt": 1, "rate_inv": 1, "rate_inv_fmt": 1, "rate_noinv": 1, "rate_noinv_fmt": 1, "raw": 6, "raw_log_p": 5, "reach": 1, "react": [1, 2, 5], "react_ag": [1, 8], "reactag": [1, 2, 4], "reactmodul": [5, 6], "read": [1, 2], "readi": 1, "realiz": 2, "reason": 2, "recal": 2, "receiv": [1, 7], "recent": 2, "recommend": 1, "record": 5, "recurs": 3, "redefinit": 2, "reduc": 1, "refer": 1, "reflect": [1, 5], "reflectmodul": [5, 6], "reflectmoduleconfig": [5, 6], "refresh": [1, 8], "regist": 1, "rehydr": 5, "relev": [2, 5], "remain": 1, "remaining_": 1, "remot": 2, "remov": 1, "render": 3, "render_doc": 2, "repeat": [1, 2, 6], "repeatedli": 3, "replac": [1, 2, 3, 4, 5, 6, 7], "replay_actions_on_clon": 3, "replay_buff": [1, 3], "repr": 1, "repres": [1, 2, 7], "represent": [1, 4], "request": [1, 2], "requir": [1, 2, 3, 4, 5, 6, 7], "requires_grad": 5, "rerais": 3, "reraise_exc_a": [1, 3], "reset": [1, 3, 8], "resiz": [1, 3, 4], "resolve_fully_qualified_nam": [1, 5], "resort": 1, "respect": 5, "restart": 1, "result": [1, 2, 3, 4, 5, 6, 7], "resultorvalu": 5, "retriev": [2, 5], "retry_st": 2, "retrycallst": 2, "return": [1, 2, 3, 4, 5, 6, 7], "reward": [1, 2, 3, 4, 8], "reward_discount": [3, 4], "right": 5, "rl": [1, 2], "role": 7, "rollout": [1, 8], "rollout_manag": 3, "rolloutdebugdumpcallback": [1, 3], "rolloutmanag": [1, 3], "root": 1, "root_id": 1, "round_trip": 1, "run": [1, 2, 3, 4, 5, 7], "run_id": [1, 5], "runner": [1, 8], "s_0": 1, "s_t": 1, "safe": [2, 3], "safe_access_index": [1, 5], "same": [5, 7], "sampl": 4, "sample_trajectori": [1, 3], "sample_tre": [1, 3], "samples_per_beam": 3, "scale": 1, "schema": 7, "scientif": 1, "score": [3, 4], "score_fn": [3, 4], "scoring_fn": 3, "screen": 1, "search": [0, 2, 4, 5, 7], "second": 1, "second_sys_prompt": 6, "seconds_to_first_token": [1, 7], "seconds_to_last_token": [1, 7], "section": 5, "see": [1, 4, 5], "select": [2, 5, 6], "self": [1, 2, 4, 5, 7], "sent": 7, "separ": [2, 6], "sequenc": [3, 4, 5, 7], "sequenti": [2, 5], "seri": 1, "serial": [1, 5], "serialize_as_ani": 1, "serialize_uuid": [1, 5], "seriesgroupbi": 1, "server": 2, "set": [1, 2, 3, 4, 5], "set_descript": [1, 8], "set_description_str": [1, 8], "set_lock": [1, 8], "set_mod": [1, 7], "set_model_nam": [1, 7], "set_nam": [1, 5], "set_postfix": [1, 8], "set_postfix_str": [1, 8], "set_training_mod": [1, 5], "sever": 7, "shim": [0, 8], "shortcut": 1, "should": [1, 2, 3, 4, 5, 6, 7], "show_pbar": 4, "shuffl": 4, "si": 1, "similar": [1, 2], "simpl": [2, 7], "simple_ag": [1, 8], "simpleag": [1, 2], "simpleagentst": [1, 2], "simpli": [2, 4, 5, 6], "sinc": [1, 5], "singl": [4, 5, 6], "size": [1, 4], "skip": [1, 3], "slow": 1, "small": 7, "smooth": 1, "so": [2, 3, 4, 6], "solut": 2, "solv": 2, "some": [1, 4, 5], "some_frontend": 1, "someth": 2, "sourc": [1, 2, 3, 4, 5, 6, 7], "sp": 1, "spars": 7, "sparseembeddingmodel": [1, 7], "specifi": [1, 2, 3, 4, 7], "speed": 1, "ss": 1, "stabil": 2, "stackoverflow": 1, "stai": 1, "standard": 1, "start": [1, 2, 3, 4, 6, 7], "start_config": 6, "stat": 1, "state": [1, 2], "static": [1, 2, 5, 6, 7], "statist": 1, "status_print": [1, 8], "stderr": 1, "stdout": 1, "step": [1, 2, 3, 4, 8], "step_id": 1, "still": 5, "stop_grad": [1, 5], "stopgradop": [1, 5], "storag": 5, "store": [2, 3, 5], "store_tensor_input": [1, 5], "str": [1, 2, 3, 4, 5, 6, 7], "straight": 5, "straight_through_estim": [1, 5], "strategi": 4, "stream": 1, "strenum": [2, 4, 6, 7], "string": [1, 2, 4, 5], "string_input": 5, "stringio": 1, "structur": 5, "structurekv": 5, "style": [2, 6], "sub": 4, "subclass": 2, "subgraph": 6, "submodul": [0, 8], "subpackag": [0, 8], "subsequ": 1, "success": 2, "suffix": 1, "sum": [5, 7], "sum_": 1, "sum_logprob": [1, 7], "suppli": 2, "support": [1, 2, 7], "sy": 1, "symmetri": 2, "sys_cont": 7, "sys_prompt": [1, 2, 6], "system": [1, 2, 6, 7], "system_fingerprint": [1, 7], "system_prompt": [3, 4], "t": [1, 2, 5], "t_output": 5, "tagentst": [2, 3], "take": [1, 2, 3, 5, 6], "taken": [2, 5], "target": 5, "target_reward": 3, "task": [1, 2, 3], "taskdataset": 3, "tconfig": 5, "temperatur": [2, 5, 7], "templat": [1, 2, 4, 5], "tensor": 5, "tensor_arg": 5, "tensor_input": 5, "tensor_kwarg": 5, "tenv": 3, "term": 1, "termin": [1, 3, 5], "terminalprintingcallback": [1, 3], "test": 2, "text": [5, 7], "textiowrapp": 1, "than": [1, 2], "thei": 4, "them": [1, 2, 3, 4], "thi": [1, 2, 3, 4, 5, 6, 7], "think": [2, 5, 6], "those": 5, "thought": [1, 2, 5], "thoughtmodul": [5, 6], "thread": 1, "three": 2, "through": 5, "tight": 1, "time": [1, 2, 3, 5, 6], "timer": [1, 3], "timestep": [1, 8], "tindex": 5, "to_dict": [1, 5], "to_json": 1, "to_jsonl": [1, 8], "to_network": [1, 3], "to_pydot": 3, "token": 7, "tool": [1, 2, 3, 5, 6, 7], "tool_cal": 5, "tool_choic": [5, 7], "tool_choice_requir": [1, 5, 7], "tool_description_method": [1, 2, 6], "tool_nam": [2, 6], "tooldescriptionmethod": [2, 5, 6], "toolrequestmessag": [1, 2, 3, 5, 6], "toolresponsemessag": [1, 2], "tools_to_track": [1, 3], "top_logprob": 2, "topolog": 5, "topological_ord": 5, "torch": [2, 5, 6], "torch_modul": 5, "torch_op": [1, 8], "torchop": [1, 5], "torchparambackwardestim": [1, 5], "total": 1, "total_fmt": 1, "toutput": [4, 5], "tparsedmessag": 6, "tqdm": [0, 1, 8], "tqdm_gui": 1, "tqdm_kwarg": 1, "trace": [1, 3, 4, 5], "track": 2, "track_tool_usag": 3, "trail": 1, "train": [1, 2, 3, 4, 5], "train_dataset": 3, "train_mean": [1, 3], "train_trajectori": 3, "trainabl": 2, "trainer": 4, "training_mod": 5, "traj": [1, 3], "traj_id": [1, 3, 8], "trajectori": [0, 1, 2, 3, 4, 8], "trajectoryfilecallback": [1, 3], "trajectorymetricscallback": [1, 3], "trang": [0, 1, 8], "transform": 5, "transit": [0, 1, 3, 4, 8], "transitiontre": [0, 1, 3, 8], "travers": [1, 5], "tree": [1, 2, 5], "tree_of_thoughts_ag": [1, 8], "tree_search": [1, 8], "treeofthoughtsag": [1, 2], "treesearchrollout": [1, 3], "tresult": 5, "trigger": 1, "true": [1, 2, 3, 4, 5, 7], "trunc": 3, "truncat": [1, 5, 7, 8], "try": [4, 5], "tserializableagentst": 2, "tty": 1, "tupl": [1, 2, 3, 4, 5, 6, 7], "turbo": [6, 7], "tweak": 1, "two": 7, "type": [1, 2, 3, 4, 5, 6, 7], "typic": [2, 5], "u": 5, "uindexmemorymodel": [1, 5], "un": 7, "unbias": 5, "undefin": 3, "under": [2, 5], "undertak": 2, "unicod": 1, "union": [1, 2, 3, 4, 5, 7], "uniqu": 1, "unit": 1, "unit_divisor": 1, "unit_scal": 1, "uniti": 1, "unknown": 7, "unless": 1, "unpaus": [1, 8], "unset": 3, "unspecifi": [1, 2, 7], "until": 1, "unwrap_valu": [1, 5], "up": [1, 2, 5], "updat": [1, 3, 4, 5, 8], "update_everi": [1, 3], "updating_optim": 3, "upon": [1, 5], "upstream": 5, "us": [1, 2, 3, 4, 5, 6], "usag": 1, "usd": 7, "user": [2, 3, 5, 6, 7], "user_cont": 7, "userlist": 4, "usual": 1, "util": [0, 7, 8], "uuid": [1, 5, 7], "uuid4": 7, "v": [1, 5], "v1": [1, 2, 3, 4, 5, 6, 7], "valid": [1, 3, 4, 6, 7], "validate_json_complet": [1, 7], "validate_score_fn": [3, 4], "validate_uuid": [1, 5], "valu": [1, 2, 3, 4, 5, 6, 7, 8], "value_prompt_func": [1, 2], "valueerror": 7, "var": 1, "variabl": [4, 5], "variou": 5, "verbos": 3, "veri": [1, 7], "version": 2, "vhat": 2, "via": [1, 2, 5, 7], "wa": [1, 4, 5], "wai": 1, "wandbloggingcallback": [1, 3], "want": 4, "warn": 1, "we": [1, 2, 4, 5, 7], "weight": 1, "what": [1, 2, 5, 6], "when": [1, 3, 5, 7], "where": [1, 2, 5], "whether": 1, "which": [1, 2, 5, 7], "while": [1, 3], "whole": 5, "width": [1, 3], "window": 1, "within": 1, "without": [1, 2], "won": 5, "work": [1, 2, 6], "world": 7, "would": 2, "wrap": 5, "wrapattr": [1, 8], "wrapper": 1, "write": [1, 3, 8], "write_byt": 1, "write_dot": 3, "write_png": 3, "x": [1, 5], "xml": [2, 5, 6], "xml_string": 7, "yet": 2, "yield": 5, "york": [2, 6], "you": [1, 2, 4, 6], "your": [1, 4], "zero": [1, 2, 4, 5], "zero_estim": [1, 5]}, "titles": ["Welcome to ldp\u2019s documentation!", "ldp package", "ldp.agent package", "ldp.alg package", "ldp.alg.optimizer package", "ldp.graph package", "ldp.graph.modules package", "ldp.llms package", "ldp"], "titleterms": {"": 0, "agent": 2, "agent_cli": 2, "alg": [3, 4], "algorithm": 3, "ap": 4, "async_torch": 5, "beam_search": 3, "callback": 3, "chat": 7, "common_op": 5, "content": [0, 1, 2, 3, 4, 5, 6, 7], "data_structur": 1, "dataset": 3, "document": 0, "embed": 7, "exampl": [], "gradient_estim": 5, "graph": [5, 6], "indic": 0, "interactive_ag": 2, "ldp": [0, 1, 2, 3, 4, 5, 6, 7, 8], "llm": 7, "llm_call": 6, "loss_op": 5, "main": 1, "memori": [4, 5], "memory_ag": 2, "modul": [1, 2, 3, 4, 5, 6, 7], "op": 5, "op_util": 5, "opt": 4, "optim": 4, "packag": [1, 2, 3, 4, 5, 6, 7], "paramet": [], "prompt": 7, "react": 6, "react_ag": 2, "refer": [], "reflect": 6, "replay_buff": 4, "return": [], "rollout": 3, "runner": 3, "shim": 1, "simple_ag": 2, "submodul": [1, 2, 3, 4, 5, 6, 7], "subpackag": [1, 3, 5], "tabl": 0, "thought": 6, "torch_op": 5, "tree_of_thoughts_ag": 2, "tree_search": 3, "util": 1, "welcom": 0}}) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..c831fc97 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,25 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "ldp" +author = "FutureHouse" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = ["sphinx.ext.todo", "sphinx.ext.viewcode", "sphinx.ext.autodoc", "sphinx.ext.napoleon"] + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "alabaster" +html_static_path = ["_static"] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..75b5c770 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,23 @@ +.. ldp documentation master file, created by + sphinx-quickstart on Thu Oct 24 14:50:30 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to ldp's documentation! +=============================== + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + modules + + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/ldp.agent.rst b/docs/ldp.agent.rst new file mode 100644 index 00000000..146fe429 --- /dev/null +++ b/docs/ldp.agent.rst @@ -0,0 +1,69 @@ +ldp.agent package +================= + +Submodules +---------- + +ldp.agent.agent module +---------------------- + +.. automodule:: ldp.agent.agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.agent\_client module +------------------------------ + +.. automodule:: ldp.agent.agent_client + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.interactive\_agent module +----------------------------------- + +.. automodule:: ldp.agent.interactive_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.memory\_agent module +------------------------------ + +.. automodule:: ldp.agent.memory_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.react\_agent module +----------------------------- + +.. automodule:: ldp.agent.react_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.simple\_agent module +------------------------------ + +.. automodule:: ldp.agent.simple_agent + :members: + :undoc-members: + :show-inheritance: + +ldp.agent.tree\_of\_thoughts\_agent module +------------------------------------------ + +.. automodule:: ldp.agent.tree_of_thoughts_agent + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.agent + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/ldp.alg.optimizer.rst b/docs/ldp.alg.optimizer.rst new file mode 100644 index 00000000..f05f2c58 --- /dev/null +++ b/docs/ldp.alg.optimizer.rst @@ -0,0 +1,45 @@ +ldp.alg.optimizer package +========================= + +Submodules +---------- + +ldp.alg.optimizer.ape module +---------------------------- + +.. automodule:: ldp.alg.optimizer.ape + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.optimizer.memory module +------------------------------- + +.. automodule:: ldp.alg.optimizer.memory + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.optimizer.opt module +---------------------------- + +.. automodule:: ldp.alg.optimizer.opt + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.optimizer.replay\_buffers module +---------------------------------------- + +.. automodule:: ldp.alg.optimizer.replay_buffers + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.alg.optimizer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/ldp.alg.rst b/docs/ldp.alg.rst new file mode 100644 index 00000000..621e6817 --- /dev/null +++ b/docs/ldp.alg.rst @@ -0,0 +1,77 @@ +ldp.alg package +=============== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + ldp.alg.optimizer + +Submodules +---------- + +ldp.alg.algorithms module +------------------------- + +.. automodule:: ldp.alg.algorithms + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.beam\_search module +--------------------------- + +.. automodule:: ldp.alg.beam_search + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.callbacks module +------------------------ + +.. automodule:: ldp.alg.callbacks + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.datasets module +----------------------- + +.. automodule:: ldp.alg.datasets + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.rollout module +---------------------- + +.. automodule:: ldp.alg.rollout + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.runners module +---------------------- + +.. automodule:: ldp.alg.runners + :members: + :undoc-members: + :show-inheritance: + +ldp.alg.tree\_search module +--------------------------- + +.. automodule:: ldp.alg.tree_search + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.alg + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/ldp.graph.modules.rst b/docs/ldp.graph.modules.rst new file mode 100644 index 00000000..28b36540 --- /dev/null +++ b/docs/ldp.graph.modules.rst @@ -0,0 +1,45 @@ +ldp.graph.modules package +========================= + +Submodules +---------- + +ldp.graph.modules.llm\_call module +---------------------------------- + +.. automodule:: ldp.graph.modules.llm_call + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.modules.react module +------------------------------ + +.. automodule:: ldp.graph.modules.react + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.modules.reflect module +-------------------------------- + +.. automodule:: ldp.graph.modules.reflect + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.modules.thought module +-------------------------------- + +.. automodule:: ldp.graph.modules.thought + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.graph.modules + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/ldp.graph.rst b/docs/ldp.graph.rst new file mode 100644 index 00000000..9fc73995 --- /dev/null +++ b/docs/ldp.graph.rst @@ -0,0 +1,85 @@ +ldp.graph package +================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + ldp.graph.modules + +Submodules +---------- + +ldp.graph.async\_torch module +----------------------------- + +.. automodule:: ldp.graph.async_torch + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.common\_ops module +---------------------------- + +.. automodule:: ldp.graph.common_ops + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.gradient\_estimators module +------------------------------------- + +.. automodule:: ldp.graph.gradient_estimators + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.loss\_ops module +-------------------------- + +.. automodule:: ldp.graph.loss_ops + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.memory module +----------------------- + +.. automodule:: ldp.graph.memory + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.op\_utils module +-------------------------- + +.. automodule:: ldp.graph.op_utils + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.ops module +-------------------- + +.. automodule:: ldp.graph.ops + :members: + :undoc-members: + :show-inheritance: + +ldp.graph.torch\_ops module +--------------------------- + +.. automodule:: ldp.graph.torch_ops + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.graph + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/ldp.llms.rst b/docs/ldp.llms.rst new file mode 100644 index 00000000..31d1b865 --- /dev/null +++ b/docs/ldp.llms.rst @@ -0,0 +1,37 @@ +ldp.llms package +================ + +Submodules +---------- + +ldp.llms.chat module +-------------------- + +.. automodule:: ldp.llms.chat + :members: + :undoc-members: + :show-inheritance: + +ldp.llms.embeddings module +-------------------------- + +.. automodule:: ldp.llms.embeddings + :members: + :undoc-members: + :show-inheritance: + +ldp.llms.prompts module +----------------------- + +.. automodule:: ldp.llms.prompts + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp.llms + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/ldp.rst b/docs/ldp.rst new file mode 100644 index 00000000..df50fc31 --- /dev/null +++ b/docs/ldp.rst @@ -0,0 +1,56 @@ +ldp package +=========== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + ldp.agent + ldp.alg + ldp.graph + ldp.llms + +Submodules +---------- + +ldp.data\_structures module +--------------------------- + +.. automodule:: ldp.data_structures + :members: + :undoc-members: + :show-inheritance: + +ldp.main module +--------------- + +.. automodule:: ldp.main + :members: + :undoc-members: + :show-inheritance: + +ldp.shims module +---------------- + +.. automodule:: ldp.shims + :members: + :undoc-members: + :show-inheritance: + +ldp.utils module +---------------- + +.. automodule:: ldp.utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ldp + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..32bb2452 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 00000000..f473f842 --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +ldp +=== + +.. toctree:: + :maxdepth: 4 + + ldp diff --git a/pyproject.toml b/pyproject.toml index a0d851d2..5aa7ba73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -431,5 +431,6 @@ dev-dependencies = [ "pytest-timer[colorama]", "pytest-xdist", "pytest>=8", # Pin to keep recent - "refurb>=2", # Pin to keep recent + "refurb>=2", # Pin to keep recent, + "sphinx" ]