mirror of
https://github.com/cpacker/MemGPT.git
synced 2025-06-03 04:30:22 +00:00
feat: Improve agent creation time (#1792)
This commit is contained in:
parent
e625cc67da
commit
4aca83df8e
@ -1,8 +1,10 @@
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, List, Optional, Set, Tuple
|
||||
|
||||
import numpy as np
|
||||
from sqlalchemy import Select, and_, func, literal, or_, select, union_all
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import Select, and_, func, insert, literal, or_, select, union_all
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
|
||||
from letta.constants import (
|
||||
BASE_MEMORY_TOOLS,
|
||||
@ -19,13 +21,17 @@ from letta.log import get_logger
|
||||
from letta.orm import Agent as AgentModel
|
||||
from letta.orm import AgentPassage, AgentsTags
|
||||
from letta.orm import Block as BlockModel
|
||||
from letta.orm import BlocksAgents
|
||||
from letta.orm import Group as GroupModel
|
||||
from letta.orm import IdentitiesAgents
|
||||
from letta.orm import Identity as IdentityModel
|
||||
from letta.orm import Source as SourceModel
|
||||
from letta.orm import SourcePassage, SourcesAgents
|
||||
from letta.orm import Tool as ToolModel
|
||||
from letta.orm import ToolsAgents
|
||||
from letta.orm.enums import ToolType
|
||||
from letta.orm.errors import NoResultFound
|
||||
from letta.orm.sandbox_config import AgentEnvironmentVariable
|
||||
from letta.orm.sandbox_config import AgentEnvironmentVariable as AgentEnvironmentVariableModel
|
||||
from letta.orm.sqlalchemy_base import AccessType
|
||||
from letta.orm.sqlite_functions import adapt_array
|
||||
@ -36,16 +42,14 @@ from letta.schemas.block import BlockUpdate
|
||||
from letta.schemas.embedding_config import EmbeddingConfig
|
||||
from letta.schemas.group import Group as PydanticGroup
|
||||
from letta.schemas.group import ManagerType
|
||||
from letta.schemas.llm_config import LLMConfig
|
||||
from letta.schemas.memory import Memory
|
||||
from letta.schemas.message import Message
|
||||
from letta.schemas.message import Message as PydanticMessage
|
||||
from letta.schemas.message import MessageCreate, MessageUpdate
|
||||
from letta.schemas.passage import Passage as PydanticPassage
|
||||
from letta.schemas.source import Source as PydanticSource
|
||||
from letta.schemas.tool import Tool as PydanticTool
|
||||
from letta.schemas.tool_rule import ContinueToolRule as PydanticContinueToolRule
|
||||
from letta.schemas.tool_rule import TerminalToolRule as PydanticTerminalToolRule
|
||||
from letta.schemas.tool_rule import ToolRule as PydanticToolRule
|
||||
from letta.schemas.tool_rule import ContinueToolRule, TerminalToolRule
|
||||
from letta.schemas.user import User as PydanticUser
|
||||
from letta.serialize_schemas import MarshmallowAgentSchema
|
||||
from letta.serialize_schemas.marshmallow_message import SerializedMessageSchema
|
||||
@ -77,7 +81,6 @@ from letta.utils import enforce_types, united_diff
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
# Agent Manager Class
|
||||
class AgentManager:
|
||||
"""Manager class to handle business logic related to Agents."""
|
||||
|
||||
@ -92,124 +95,206 @@ class AgentManager:
|
||||
self.passage_manager = PassageManager()
|
||||
self.identity_manager = IdentityManager()
|
||||
|
||||
@staticmethod
|
||||
def _resolve_tools(session, names: Set[str], ids: Set[str], org_id: str) -> Tuple[Dict[str, str], Dict[str, str]]:
|
||||
"""
|
||||
Bulk‑fetch all ToolModel rows matching either name ∈ names or id ∈ ids
|
||||
(and scoped to this organization), and return two maps:
|
||||
name_to_id, id_to_name.
|
||||
Raises if any requested name or id was not found.
|
||||
"""
|
||||
stmt = select(ToolModel.id, ToolModel.name).where(
|
||||
ToolModel.organization_id == org_id,
|
||||
or_(
|
||||
ToolModel.name.in_(names),
|
||||
ToolModel.id.in_(ids),
|
||||
),
|
||||
)
|
||||
rows = session.execute(stmt).all()
|
||||
name_to_id = {name: tid for tid, name in rows}
|
||||
id_to_name = {tid: name for tid, name in rows}
|
||||
|
||||
missing_names = names - set(name_to_id.keys())
|
||||
missing_ids = ids - set(id_to_name.keys())
|
||||
if missing_names:
|
||||
raise ValueError(f"Tools not found by name: {missing_names}")
|
||||
if missing_ids:
|
||||
raise ValueError(f"Tools not found by id: {missing_ids}")
|
||||
|
||||
return name_to_id, id_to_name
|
||||
|
||||
@staticmethod
|
||||
@trace_method
|
||||
def _bulk_insert_pivot(session, table, rows: list[dict]):
|
||||
if not rows:
|
||||
return
|
||||
|
||||
dialect = session.bind.dialect.name
|
||||
if dialect == "postgresql":
|
||||
stmt = pg_insert(table).values(rows).on_conflict_do_nothing()
|
||||
elif dialect == "sqlite":
|
||||
stmt = sa.insert(table).values(rows).prefix_with("OR IGNORE")
|
||||
else:
|
||||
# fallback: filter out exact-duplicate dicts in Python
|
||||
seen = set()
|
||||
filtered = []
|
||||
for row in rows:
|
||||
key = tuple(sorted(row.items()))
|
||||
if key not in seen:
|
||||
seen.add(key)
|
||||
filtered.append(row)
|
||||
stmt = sa.insert(table).values(filtered)
|
||||
|
||||
session.execute(stmt)
|
||||
|
||||
# ======================================================================================================================
|
||||
# Basic CRUD operations
|
||||
# ======================================================================================================================
|
||||
@trace_method
|
||||
@enforce_types
|
||||
def create_agent(
|
||||
self,
|
||||
agent_create: CreateAgent,
|
||||
actor: PydanticUser,
|
||||
) -> PydanticAgentState:
|
||||
system = derive_system_message(
|
||||
agent_type=agent_create.agent_type,
|
||||
enable_sleeptime=agent_create.enable_sleeptime,
|
||||
system=agent_create.system,
|
||||
)
|
||||
|
||||
def create_agent(self, agent_create: CreateAgent, actor: PydanticUser) -> PydanticAgentState:
|
||||
# validate required configs
|
||||
if not agent_create.llm_config or not agent_create.embedding_config:
|
||||
raise ValueError("llm_config and embedding_config are required")
|
||||
|
||||
# create blocks (note: cannot be linked into the agent_id is created)
|
||||
block_ids = list(agent_create.block_ids or []) # Create a local copy to avoid modifying the original
|
||||
# blocks
|
||||
block_ids = list(agent_create.block_ids or [])
|
||||
if agent_create.memory_blocks:
|
||||
for create_block in agent_create.memory_blocks:
|
||||
block = self.block_manager.create_or_update_block(PydanticBlock(**create_block.model_dump(to_orm=True)), actor=actor)
|
||||
block_ids.append(block.id)
|
||||
|
||||
# add passed in `tools`
|
||||
tool_names = agent_create.tools or []
|
||||
|
||||
# add base tools
|
||||
if agent_create.include_base_tools:
|
||||
if agent_create.agent_type == AgentType.sleeptime_agent:
|
||||
tool_names.extend(BASE_SLEEPTIME_TOOLS)
|
||||
else:
|
||||
if agent_create.enable_sleeptime:
|
||||
tool_names.extend(BASE_SLEEPTIME_CHAT_TOOLS)
|
||||
else:
|
||||
tool_names.extend(BASE_TOOLS + BASE_MEMORY_TOOLS)
|
||||
if agent_create.include_multi_agent_tools:
|
||||
tool_names.extend(MULTI_AGENT_TOOLS)
|
||||
|
||||
# remove duplicates
|
||||
tool_names = list(set(tool_names))
|
||||
|
||||
# convert tool names to ids
|
||||
tool_ids = []
|
||||
for tool_name in tool_names:
|
||||
tool = self.tool_manager.get_tool_by_name(tool_name=tool_name, actor=actor)
|
||||
if not tool:
|
||||
raise ValueError(f"Tool {tool_name} not found")
|
||||
tool_ids.append(tool.id)
|
||||
|
||||
# add passed in `tool_ids`
|
||||
for tool_id in agent_create.tool_ids or []:
|
||||
if tool_id not in tool_ids:
|
||||
tool = self.tool_manager.get_tool_by_id(tool_id=tool_id, actor=actor)
|
||||
if tool:
|
||||
tool_ids.append(tool.id)
|
||||
tool_names.append(tool.name)
|
||||
else:
|
||||
raise ValueError(f"Tool {tool_id} not found")
|
||||
|
||||
# add default tool rules
|
||||
tool_rules = agent_create.tool_rules or []
|
||||
if agent_create.include_base_tool_rules:
|
||||
# apply default tool rules
|
||||
for tool_name in tool_names:
|
||||
if tool_name == "send_message" or tool_name == "send_message_to_agent_async" or tool_name == "memory_finish_edits":
|
||||
tool_rules.append(PydanticTerminalToolRule(tool_name=tool_name))
|
||||
elif tool_name in BASE_TOOLS + BASE_MEMORY_TOOLS + BASE_SLEEPTIME_TOOLS:
|
||||
tool_rules.append(PydanticContinueToolRule(tool_name=tool_name))
|
||||
|
||||
# if custom rules, check tool rules are valid
|
||||
if agent_create.tool_rules:
|
||||
check_supports_structured_output(model=agent_create.llm_config.model, tool_rules=agent_create.tool_rules)
|
||||
|
||||
# Create the agent
|
||||
agent_state = self._create_agent(
|
||||
name=agent_create.name,
|
||||
system=system,
|
||||
agent_type=agent_create.agent_type,
|
||||
llm_config=agent_create.llm_config,
|
||||
embedding_config=agent_create.embedding_config,
|
||||
block_ids=block_ids,
|
||||
tool_ids=tool_ids,
|
||||
source_ids=agent_create.source_ids or [],
|
||||
tags=agent_create.tags or [],
|
||||
identity_ids=agent_create.identity_ids or [],
|
||||
description=agent_create.description,
|
||||
metadata=agent_create.metadata,
|
||||
tool_rules=tool_rules,
|
||||
actor=actor,
|
||||
project_id=agent_create.project_id,
|
||||
template_id=agent_create.template_id,
|
||||
base_template_id=agent_create.base_template_id,
|
||||
message_buffer_autoclear=agent_create.message_buffer_autoclear,
|
||||
enable_sleeptime=agent_create.enable_sleeptime,
|
||||
)
|
||||
|
||||
# If there are provided environment variables, add them in
|
||||
if agent_create.tool_exec_environment_variables:
|
||||
agent_state = self._set_environment_variables(
|
||||
agent_id=agent_state.id,
|
||||
env_vars=agent_create.tool_exec_environment_variables,
|
||||
pydantic_blocks = [PydanticBlock(**b.model_dump(to_orm=True)) for b in agent_create.memory_blocks]
|
||||
created_blocks = self.block_manager.batch_create_blocks(
|
||||
pydantic_blocks,
|
||||
actor=actor,
|
||||
)
|
||||
block_ids.extend([blk.id for blk in created_blocks])
|
||||
|
||||
return self.append_initial_message_sequence_to_in_context_messages(actor, agent_state, agent_create.initial_message_sequence)
|
||||
# tools
|
||||
tool_names = set(agent_create.tools or [])
|
||||
if agent_create.include_base_tools:
|
||||
if agent_create.agent_type == AgentType.sleeptime_agent:
|
||||
tool_names |= set(BASE_SLEEPTIME_TOOLS)
|
||||
elif agent_create.enable_sleeptime:
|
||||
tool_names |= set(BASE_SLEEPTIME_CHAT_TOOLS)
|
||||
else:
|
||||
tool_names |= set(BASE_TOOLS + BASE_MEMORY_TOOLS)
|
||||
if agent_create.include_multi_agent_tools:
|
||||
tool_names |= set(MULTI_AGENT_TOOLS)
|
||||
|
||||
supplied_ids = set(agent_create.tool_ids or [])
|
||||
|
||||
source_ids = agent_create.source_ids or []
|
||||
identity_ids = agent_create.identity_ids or []
|
||||
tag_values = agent_create.tags or []
|
||||
|
||||
with self.session_maker() as session:
|
||||
with session.begin():
|
||||
name_to_id, id_to_name = self._resolve_tools(
|
||||
session,
|
||||
tool_names,
|
||||
supplied_ids,
|
||||
actor.organization_id,
|
||||
)
|
||||
|
||||
tool_ids = set(name_to_id.values()) | set(id_to_name.keys())
|
||||
tool_names = set(name_to_id.keys()) # now canonical
|
||||
|
||||
tool_rules = list(agent_create.tool_rules or [])
|
||||
if agent_create.include_base_tool_rules:
|
||||
for tn in tool_names:
|
||||
if tn in {"send_message", "send_message_to_agent_async", "memory_finish_edits"}:
|
||||
tool_rules.append(TerminalToolRule(tool_name=tn))
|
||||
elif tn in (BASE_TOOLS + BASE_MEMORY_TOOLS + BASE_SLEEPTIME_TOOLS):
|
||||
tool_rules.append(ContinueToolRule(tool_name=tn))
|
||||
|
||||
if tool_rules:
|
||||
check_supports_structured_output(model=agent_create.llm_config.model, tool_rules=tool_rules)
|
||||
|
||||
new_agent = AgentModel(
|
||||
name=agent_create.name,
|
||||
system=derive_system_message(
|
||||
agent_type=agent_create.agent_type,
|
||||
enable_sleeptime=agent_create.enable_sleeptime,
|
||||
system=agent_create.system,
|
||||
),
|
||||
agent_type=agent_create.agent_type,
|
||||
llm_config=agent_create.llm_config,
|
||||
embedding_config=agent_create.embedding_config,
|
||||
organization_id=actor.organization_id,
|
||||
description=agent_create.description,
|
||||
metadata_=agent_create.metadata,
|
||||
tool_rules=tool_rules,
|
||||
project_id=agent_create.project_id,
|
||||
template_id=agent_create.template_id,
|
||||
base_template_id=agent_create.base_template_id,
|
||||
message_buffer_autoclear=agent_create.message_buffer_autoclear,
|
||||
enable_sleeptime=agent_create.enable_sleeptime,
|
||||
created_by_id=actor.id,
|
||||
last_updated_by_id=actor.id,
|
||||
)
|
||||
session.add(new_agent)
|
||||
session.flush()
|
||||
aid = new_agent.id
|
||||
|
||||
self._bulk_insert_pivot(
|
||||
session,
|
||||
ToolsAgents.__table__,
|
||||
[{"agent_id": aid, "tool_id": tid} for tid in tool_ids],
|
||||
)
|
||||
|
||||
if block_ids:
|
||||
rows = [
|
||||
{"agent_id": aid, "block_id": bid, "block_label": lbl}
|
||||
for bid, lbl in session.execute(select(BlockModel.id, BlockModel.label).where(BlockModel.id.in_(block_ids))).all()
|
||||
]
|
||||
self._bulk_insert_pivot(session, BlocksAgents.__table__, rows)
|
||||
|
||||
self._bulk_insert_pivot(
|
||||
session,
|
||||
SourcesAgents.__table__,
|
||||
[{"agent_id": aid, "source_id": sid} for sid in source_ids],
|
||||
)
|
||||
self._bulk_insert_pivot(
|
||||
session,
|
||||
AgentsTags.__table__,
|
||||
[{"agent_id": aid, "tag": tag} for tag in tag_values],
|
||||
)
|
||||
self._bulk_insert_pivot(
|
||||
session,
|
||||
IdentitiesAgents.__table__,
|
||||
[{"agent_id": aid, "identity_id": iid} for iid in identity_ids],
|
||||
)
|
||||
|
||||
if agent_create.tool_exec_environment_variables:
|
||||
env_rows = [
|
||||
{
|
||||
"agent_id": aid,
|
||||
"key": key,
|
||||
"value": val,
|
||||
"organization_id": actor.organization_id,
|
||||
}
|
||||
for key, val in agent_create.tool_exec_environment_variables.items()
|
||||
]
|
||||
session.execute(insert(AgentEnvironmentVariable).values(env_rows))
|
||||
|
||||
# initial message sequence
|
||||
init_messages = self._generate_initial_message_sequence(
|
||||
actor,
|
||||
agent_state=new_agent.to_pydantic(include_relationships={"memory"}),
|
||||
supplied_initial_message_sequence=agent_create.initial_message_sequence,
|
||||
)
|
||||
new_agent.message_ids = [msg.id for msg in init_messages]
|
||||
|
||||
session.refresh(new_agent)
|
||||
|
||||
self.message_manager.create_many_messages(pydantic_msgs=init_messages, actor=actor)
|
||||
return new_agent.to_pydantic()
|
||||
|
||||
@enforce_types
|
||||
def append_initial_message_sequence_to_in_context_messages(
|
||||
self, actor: PydanticUser, agent_state: PydanticAgentState, initial_message_sequence: Optional[List[MessageCreate]] = None
|
||||
) -> PydanticAgentState:
|
||||
def _generate_initial_message_sequence(
|
||||
self, actor: PydanticUser, agent_state: PydanticAgentState, supplied_initial_message_sequence: Optional[List[MessageCreate]] = None
|
||||
) -> List[Message]:
|
||||
init_messages = initialize_message_sequence(
|
||||
agent_state=agent_state, memory_edit_timestamp=get_utc_time(), include_initial_boot_message=True
|
||||
)
|
||||
|
||||
if initial_message_sequence is not None:
|
||||
if supplied_initial_message_sequence is not None:
|
||||
# We always need the system prompt up front
|
||||
system_message_obj = PydanticMessage.dict_to_message(
|
||||
agent_id=agent_state.id,
|
||||
@ -219,7 +304,7 @@ class AgentManager:
|
||||
# Don't use anything else in the pregen sequence, instead use the provided sequence
|
||||
init_messages = [system_message_obj]
|
||||
init_messages.extend(
|
||||
package_initial_message_sequence(agent_state.id, initial_message_sequence, agent_state.llm_config.model, actor)
|
||||
package_initial_message_sequence(agent_state.id, supplied_initial_message_sequence, agent_state.llm_config.model, actor)
|
||||
)
|
||||
else:
|
||||
init_messages = [
|
||||
@ -227,63 +312,14 @@ class AgentManager:
|
||||
for msg in init_messages
|
||||
]
|
||||
|
||||
return self.append_to_in_context_messages(init_messages, agent_id=agent_state.id, actor=actor)
|
||||
return init_messages
|
||||
|
||||
@enforce_types
|
||||
def _create_agent(
|
||||
self,
|
||||
actor: PydanticUser,
|
||||
name: str,
|
||||
system: str,
|
||||
agent_type: AgentType,
|
||||
llm_config: LLMConfig,
|
||||
embedding_config: EmbeddingConfig,
|
||||
block_ids: List[str],
|
||||
tool_ids: List[str],
|
||||
source_ids: List[str],
|
||||
tags: List[str],
|
||||
identity_ids: List[str],
|
||||
description: Optional[str] = None,
|
||||
metadata: Optional[Dict] = None,
|
||||
tool_rules: Optional[List[PydanticToolRule]] = None,
|
||||
project_id: Optional[str] = None,
|
||||
template_id: Optional[str] = None,
|
||||
base_template_id: Optional[str] = None,
|
||||
message_buffer_autoclear: bool = False,
|
||||
enable_sleeptime: Optional[bool] = None,
|
||||
def append_initial_message_sequence_to_in_context_messages(
|
||||
self, actor: PydanticUser, agent_state: PydanticAgentState, initial_message_sequence: Optional[List[MessageCreate]] = None
|
||||
) -> PydanticAgentState:
|
||||
"""Create a new agent."""
|
||||
with self.session_maker() as session:
|
||||
# Prepare the agent data
|
||||
data = {
|
||||
"name": name,
|
||||
"system": system,
|
||||
"agent_type": agent_type,
|
||||
"llm_config": llm_config,
|
||||
"embedding_config": embedding_config,
|
||||
"organization_id": actor.organization_id,
|
||||
"description": description,
|
||||
"metadata_": metadata,
|
||||
"tool_rules": tool_rules,
|
||||
"project_id": project_id,
|
||||
"template_id": template_id,
|
||||
"base_template_id": base_template_id,
|
||||
"message_buffer_autoclear": message_buffer_autoclear,
|
||||
"enable_sleeptime": enable_sleeptime,
|
||||
}
|
||||
|
||||
# Create the new agent using SqlalchemyBase.create
|
||||
new_agent = AgentModel(**data)
|
||||
_process_relationship(session, new_agent, "tools", ToolModel, tool_ids, replace=True)
|
||||
_process_relationship(session, new_agent, "sources", SourceModel, source_ids, replace=True)
|
||||
_process_relationship(session, new_agent, "core_memory", BlockModel, block_ids, replace=True)
|
||||
_process_tags(new_agent, tags, replace=True)
|
||||
_process_relationship(session, new_agent, "identities", IdentityModel, identity_ids, replace=True)
|
||||
|
||||
new_agent.create(session, actor=actor)
|
||||
|
||||
# Convert to PydanticAgentState and return
|
||||
return new_agent.to_pydantic()
|
||||
init_messages = self._generate_initial_message_sequence(actor, agent_state, initial_message_sequence)
|
||||
return self.append_to_in_context_messages(init_messages, agent_id=agent_state.id, actor=actor)
|
||||
|
||||
@enforce_types
|
||||
def update_agent(self, agent_id: str, agent_update: UpdateAgent, actor: PydanticUser) -> PydanticAgentState:
|
||||
|
@ -37,6 +37,29 @@ class BlockManager:
|
||||
block.create(session, actor=actor)
|
||||
return block.to_pydantic()
|
||||
|
||||
@enforce_types
|
||||
def batch_create_blocks(self, blocks: List[PydanticBlock], actor: PydanticUser) -> List[PydanticBlock]:
|
||||
"""
|
||||
Batch-create multiple Blocks in one transaction for better performance.
|
||||
Args:
|
||||
blocks: List of PydanticBlock schemas to create
|
||||
actor: The user performing the operation
|
||||
Returns:
|
||||
List of created PydanticBlock instances (with IDs, timestamps, etc.)
|
||||
"""
|
||||
if not blocks:
|
||||
return []
|
||||
|
||||
with self.session_maker() as session:
|
||||
block_models = [
|
||||
BlockModel(**block.model_dump(to_orm=True, exclude_none=True), organization_id=actor.organization_id) for block in blocks
|
||||
]
|
||||
|
||||
created_models = BlockModel.batch_create(items=block_models, db_session=session, actor=actor)
|
||||
|
||||
# Convert back to Pydantic
|
||||
return [m.to_pydantic() for m in created_models]
|
||||
|
||||
@enforce_types
|
||||
def update_block(self, block_id: str, block_update: BlockUpdate, actor: PydanticUser) -> PydanticBlock:
|
||||
"""Update a block by its ID with the given BlockUpdate object."""
|
||||
|
@ -21,9 +21,11 @@ from letta.schemas.passage import Passage as PydanticPassage
|
||||
from letta.schemas.tool_rule import ToolRule
|
||||
from letta.schemas.user import User
|
||||
from letta.system import get_initial_boot_messages, get_login_event
|
||||
from letta.tracing import trace_method
|
||||
|
||||
|
||||
# Static methods
|
||||
@trace_method
|
||||
def _process_relationship(
|
||||
session, agent: AgentModel, relationship_name: str, model_class, item_ids: List[str], allow_partial=False, replace=True
|
||||
):
|
||||
|
@ -5,6 +5,8 @@ import time
|
||||
import uuid
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import pytest
|
||||
from dotenv import load_dotenv
|
||||
from letta_client import Letta
|
||||
@ -131,10 +133,9 @@ def agent_state(client, roll_dice_tool, weather_tool, rethink_tool):
|
||||
# --- Load Test --- #
|
||||
|
||||
|
||||
def create_agents_for_user(client, roll_dice_tool, rethink_tool, user_index: int) -> float:
|
||||
"""Create agents and return E2E latency in seconds."""
|
||||
start_time = time.time()
|
||||
|
||||
def create_agents_for_user(client, roll_dice_tool, rethink_tool, user_index: int) -> tuple:
|
||||
"""Create agents and return E2E latencies in seconds along with user index."""
|
||||
# Setup blocks first
|
||||
num_blocks = 10
|
||||
blocks = []
|
||||
for i in range(num_blocks):
|
||||
@ -148,8 +149,12 @@ def create_agents_for_user(client, roll_dice_tool, rethink_tool, user_index: int
|
||||
blocks.append(block)
|
||||
block_ids = [b.id for b in blocks]
|
||||
|
||||
# Now create agents and track individual latencies
|
||||
agent_latencies = []
|
||||
num_agents_per_user = 100
|
||||
for i in range(num_agents_per_user):
|
||||
start_time = time.time()
|
||||
|
||||
client.agents.create(
|
||||
name=f"user{user_index}_agent_{str(uuid.uuid4())[5:]}",
|
||||
tool_ids=[roll_dice_tool.id, rethink_tool.id],
|
||||
@ -163,16 +168,94 @@ def create_agents_for_user(client, roll_dice_tool, rethink_tool, user_index: int
|
||||
block_ids=block_ids,
|
||||
)
|
||||
|
||||
end_time = time.time()
|
||||
return end_time - start_time
|
||||
end_time = time.time()
|
||||
latency = end_time - start_time
|
||||
agent_latencies.append({"user_index": user_index, "agent_index": i, "latency": latency})
|
||||
|
||||
return user_index, agent_latencies
|
||||
|
||||
|
||||
def plot_agent_creation_latencies(latency_data):
|
||||
"""
|
||||
Plot the distribution of agent creation latencies.
|
||||
|
||||
Args:
|
||||
latency_data: List of dictionaries with latency information
|
||||
"""
|
||||
# Convert to DataFrame for easier analysis
|
||||
df = pd.DataFrame(latency_data)
|
||||
|
||||
# Overall latency distribution
|
||||
plt.figure(figsize=(12, 10))
|
||||
|
||||
# Plot 1: Overall latency histogram
|
||||
plt.subplot(2, 2, 1)
|
||||
plt.hist(df["latency"], bins=30, alpha=0.7, color="blue")
|
||||
plt.title(f"Agent Creation Latency Distribution (n={len(df)})")
|
||||
plt.xlabel("Latency (seconds)")
|
||||
plt.ylabel("Frequency")
|
||||
plt.grid(True, alpha=0.3)
|
||||
|
||||
# Plot 2: Latency by user (boxplot)
|
||||
plt.subplot(2, 2, 2)
|
||||
user_groups = df.groupby("user_index")
|
||||
plt.boxplot([group["latency"] for _, group in user_groups])
|
||||
plt.title("Latency Distribution by User")
|
||||
plt.xlabel("User Index")
|
||||
plt.ylabel("Latency (seconds)")
|
||||
plt.xticks(range(1, len(user_groups) + 1), sorted(df["user_index"].unique()))
|
||||
plt.grid(True, alpha=0.3)
|
||||
|
||||
# Plot 3: Time series of latencies
|
||||
plt.subplot(2, 1, 2)
|
||||
for user_idx in sorted(df["user_index"].unique()):
|
||||
user_data = df[df["user_index"] == user_idx]
|
||||
plt.plot(user_data["agent_index"], user_data["latency"], marker=".", linestyle="-", alpha=0.7, label=f"User {user_idx}")
|
||||
|
||||
plt.title("Agent Creation Latency Over Time")
|
||||
plt.xlabel("Agent Creation Sequence")
|
||||
plt.ylabel("Latency (seconds)")
|
||||
plt.legend(loc="upper right")
|
||||
plt.grid(True, alpha=0.3)
|
||||
|
||||
# Add statistics as text
|
||||
stats_text = (
|
||||
f"Mean: {df['latency'].mean():.2f}s\n"
|
||||
f"Median: {df['latency'].median():.2f}s\n"
|
||||
f"Min: {df['latency'].min():.2f}s\n"
|
||||
f"Max: {df['latency'].max():.2f}s\n"
|
||||
f"Std Dev: {df['latency'].std():.2f}s"
|
||||
)
|
||||
plt.figtext(0.02, 0.02, stats_text, fontsize=10, bbox=dict(facecolor="white", alpha=0.8))
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
# Save the plot
|
||||
plot_file = f"agent_creation_latency_plot_{time.strftime('%Y%m%d_%H%M%S')}.png"
|
||||
plt.savefig(plot_file)
|
||||
plt.close()
|
||||
|
||||
print(f"Latency plot saved to {plot_file}")
|
||||
|
||||
# Return statistics for reporting
|
||||
return {
|
||||
"mean": df["latency"].mean(),
|
||||
"median": df["latency"].median(),
|
||||
"min": df["latency"].min(),
|
||||
"max": df["latency"].max(),
|
||||
"std": df["latency"].std(),
|
||||
"count": len(df),
|
||||
"plot_file": plot_file,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_parallel_create_many_agents(client, roll_dice_tool, rethink_tool):
|
||||
num_users = 10
|
||||
num_users = 7
|
||||
max_workers = min(num_users, 20)
|
||||
|
||||
latencies = []
|
||||
# To collect all latency data across users
|
||||
all_latency_data = []
|
||||
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
futures = {
|
||||
@ -182,15 +265,30 @@ def test_parallel_create_many_agents(client, roll_dice_tool, rethink_tool):
|
||||
|
||||
with tqdm(total=num_users, desc="Creating agents") as pbar:
|
||||
for future in as_completed(futures):
|
||||
user_idx = futures[future]
|
||||
try:
|
||||
latency = future.result()
|
||||
latencies.append(latency)
|
||||
tqdm.write(f"[User {user_idx}] Agent creation latency: {latency:.2f} seconds")
|
||||
user_idx, user_latencies = future.result()
|
||||
all_latency_data.extend(user_latencies)
|
||||
|
||||
# Calculate and display per-user statistics
|
||||
latencies = [data["latency"] for data in user_latencies]
|
||||
avg_latency = sum(latencies) / len(latencies)
|
||||
tqdm.write(f"[User {user_idx}] Completed {len(latencies)} agents")
|
||||
tqdm.write(f"[User {user_idx}] Avg: {avg_latency:.2f}s, Min: {min(latencies):.2f}s, Max: {max(latencies):.2f}s")
|
||||
except Exception as e:
|
||||
user_idx = futures[future]
|
||||
tqdm.write(f"[User {user_idx}] Error during agent creation: {str(e)}")
|
||||
pbar.update(1)
|
||||
|
||||
if latencies:
|
||||
avg_latency = sum(latencies) / len(latencies)
|
||||
print(f"Average agent creation latency per user: {avg_latency:.2f} seconds")
|
||||
if all_latency_data:
|
||||
# Plot all collected latency data
|
||||
stats = plot_agent_creation_latencies(all_latency_data)
|
||||
|
||||
print("\n===== Agent Creation Latency Statistics =====")
|
||||
print(f"Total agents created: {stats['count']}")
|
||||
print(f"Mean latency: {stats['mean']:.2f} seconds")
|
||||
print(f"Median latency: {stats['median']:.2f} seconds")
|
||||
print(f"Min latency: {stats['min']:.2f} seconds")
|
||||
print(f"Max latency: {stats['max']:.2f} seconds")
|
||||
print(f"Standard deviation: {stats['std']:.2f} seconds")
|
||||
print(f"Latency plot saved to: {stats['plot_file']}")
|
||||
print("============================================")
|
||||
|
326
poetry.lock
generated
326
poetry.lock
generated
@ -963,6 +963,82 @@ files = [
|
||||
test = ["PyYAML", "mock", "pytest"]
|
||||
yaml = ["PyYAML"]
|
||||
|
||||
[[package]]
|
||||
name = "contourpy"
|
||||
version = "1.3.2"
|
||||
description = "Python library for calculating contours of 2D quadrilateral grids"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
files = [
|
||||
{file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0"},
|
||||
{file = "contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f"},
|
||||
{file = "contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912"},
|
||||
{file = "contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1"},
|
||||
{file = "contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69"},
|
||||
{file = "contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c"},
|
||||
{file = "contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16"},
|
||||
{file = "contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad"},
|
||||
{file = "contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0"},
|
||||
{file = "contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5"},
|
||||
{file = "contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5"},
|
||||
{file = "contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = ">=1.23"
|
||||
|
||||
[package.extras]
|
||||
bokeh = ["bokeh", "selenium"]
|
||||
docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"]
|
||||
mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.15.0)", "types-Pillow"]
|
||||
test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
|
||||
test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "44.0.2"
|
||||
@ -1020,6 +1096,21 @@ ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi (>=2024)", "cryptography-vectors (==44.0.2)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[[package]]
|
||||
name = "cycler"
|
||||
version = "0.12.1"
|
||||
description = "Composable style cycles"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"},
|
||||
{file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["ipython", "matplotlib", "numpydoc", "sphinx"]
|
||||
tests = ["pytest", "pytest-cov", "pytest-xdist"]
|
||||
|
||||
[[package]]
|
||||
name = "dataclasses-json"
|
||||
version = "0.6.7"
|
||||
@ -1438,6 +1529,79 @@ files = [
|
||||
Flask = ">=1.0.4"
|
||||
Werkzeug = ">=1.0.1"
|
||||
|
||||
[[package]]
|
||||
name = "fonttools"
|
||||
version = "4.57.0"
|
||||
description = "Tools to manipulate font files"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fonttools-4.57.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41"},
|
||||
{file = "fonttools-4.57.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02"},
|
||||
{file = "fonttools-4.57.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e"},
|
||||
{file = "fonttools-4.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab"},
|
||||
{file = "fonttools-4.57.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1"},
|
||||
{file = "fonttools-4.57.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f"},
|
||||
{file = "fonttools-4.57.0-cp310-cp310-win32.whl", hash = "sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec"},
|
||||
{file = "fonttools-4.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-win32.whl", hash = "sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36"},
|
||||
{file = "fonttools-4.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-win32.whl", hash = "sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac"},
|
||||
{file = "fonttools-4.57.0-cp312-cp312-win_amd64.whl", hash = "sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-win32.whl", hash = "sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199"},
|
||||
{file = "fonttools-4.57.0-cp313-cp313-win_amd64.whl", hash = "sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-win32.whl", hash = "sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6"},
|
||||
{file = "fonttools-4.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7339e6a3283e4b0ade99cade51e97cde3d54cd6d1c3744459e886b66d630c8b3"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:05efceb2cb5f6ec92a4180fcb7a64aa8d3385fd49cfbbe459350229d1974f0b1"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a97bb05eb24637714a04dee85bdf0ad1941df64fe3b802ee4ac1c284a5f97b7c"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:541cb48191a19ceb1a2a4b90c1fcebd22a1ff7491010d3cf840dd3a68aebd654"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:cdef9a056c222d0479a1fdb721430f9efd68268014c54e8166133d2643cb05d9"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3cf97236b192a50a4bf200dc5ba405aa78d4f537a2c6e4c624bb60466d5b03bd"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-win32.whl", hash = "sha256:e952c684274a7714b3160f57ec1d78309f955c6335c04433f07d36c5eb27b1f9"},
|
||||
{file = "fonttools-4.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2a722c0e4bfd9966a11ff55c895c817158fcce1b2b6700205a376403b546ad9"},
|
||||
{file = "fonttools-4.57.0-py3-none-any.whl", hash = "sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f"},
|
||||
{file = "fonttools-4.57.0.tar.gz", hash = "sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"]
|
||||
graphite = ["lz4 (>=1.7.4.2)"]
|
||||
interpolatable = ["munkres", "pycairo", "scipy"]
|
||||
lxml = ["lxml (>=4.0)"]
|
||||
pathops = ["skia-pathops (>=0.5.0)"]
|
||||
plot = ["matplotlib"]
|
||||
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||
symfont = ["sympy"]
|
||||
type1 = ["xattr"]
|
||||
ufo = ["fs (>=2.2.0,<3)"]
|
||||
unicode = ["unicodedata2 (>=15.1.0)"]
|
||||
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "frozenlist"
|
||||
version = "1.5.0"
|
||||
@ -2608,6 +2772,95 @@ traitlets = ">=5.3"
|
||||
docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"]
|
||||
test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"]
|
||||
|
||||
[[package]]
|
||||
name = "kiwisolver"
|
||||
version = "1.4.8"
|
||||
description = "A fast implementation of the Cassowary constraint solver"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
files = [
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce2cf1e5688edcb727fdf7cd1bbd0b6416758996826a8be1d958f91880d0809d"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c8bf637892dc6e6aad2bc6d4d69d08764166e5e3f69d469e55427b6ac001b19d"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:034d2c891f76bd3edbdb3ea11140d8510dca675443da7304205a2eaa45d8334c"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47b28d1dfe0793d5e96bce90835e17edf9a499b53969b03c6c47ea5985844c3"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb158fe28ca0c29f2260cca8c43005329ad58452c36f0edf298204de32a9a3ed"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5536185fce131780ebd809f8e623bf4030ce1b161353166c49a3c74c287897f"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:369b75d40abedc1da2c1f4de13f3482cb99e3237b38726710f4a793432b1c5ff"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:641f2ddf9358c80faa22e22eb4c9f54bd3f0e442e038728f500e3b978d00aa7d"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d561d2d8883e0819445cfe58d7ddd673e4015c3c57261d7bdcd3710d0d14005c"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1732e065704b47c9afca7ffa272f845300a4eb959276bf6970dc07265e73b605"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bcb1ebc3547619c3b58a39e2448af089ea2ef44b37988caf432447374941574e"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-win_amd64.whl", hash = "sha256:89c107041f7b27844179ea9c85d6da275aa55ecf28413e87624d033cf1f6b751"},
|
||||
{file = "kiwisolver-1.4.8-cp310-cp310-win_arm64.whl", hash = "sha256:b5773efa2be9eb9fcf5415ea3ab70fc785d598729fd6057bea38d539ead28271"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2b9a96e0f326205af81a15718a9073328df1173a2619a68553decb7097fd5d7"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5020c83e8553f770cb3b5fc13faac40f17e0b205bd237aebd21d53d733adb03"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dace81d28c787956bfbfbbfd72fdcef014f37d9b48830829e488fdb32b49d954"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11e1022b524bd48ae56c9b4f9296bce77e15a2e42a502cceba602f804b32bb79"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b9b4d2892fefc886f30301cdd80debd8bb01ecdf165a449eb6e78f79f0fabd6"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a96c0e790ee875d65e340ab383700e2b4891677b7fcd30a699146f9384a2bb0"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23454ff084b07ac54ca8be535f4174170c1094a4cff78fbae4f73a4bcc0d4dab"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:87b287251ad6488e95b4f0b4a79a6d04d3ea35fde6340eb38fbd1ca9cd35bbbc"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b21dbe165081142b1232a240fc6383fd32cdd877ca6cc89eab93e5f5883e1c25"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:768cade2c2df13db52475bd28d3a3fac8c9eff04b0e9e2fda0f3760f20b3f7fc"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-win_amd64.whl", hash = "sha256:ed33ca2002a779a2e20eeb06aea7721b6e47f2d4b8a8ece979d8ba9e2a167e34"},
|
||||
{file = "kiwisolver-1.4.8-cp311-cp311-win_arm64.whl", hash = "sha256:16523b40aab60426ffdebe33ac374457cf62863e330a90a0383639ce14bf44b2"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50"},
|
||||
{file = "kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90"},
|
||||
{file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85"},
|
||||
{file = "kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e7a019419b7b510f0f7c9dceff8c5eae2392037eae483a7f9162625233802b0a"},
|
||||
{file = "kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:286b18e86682fd2217a48fc6be6b0f20c1d0ed10958d8dc53453ad58d7be0bf8"},
|
||||
{file = "kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4191ee8dfd0be1c3666ccbac178c5a05d5f8d689bbe3fc92f3c4abec817f8fe0"},
|
||||
{file = "kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd2785b9391f2873ad46088ed7599a6a71e762e1ea33e87514b1a441ed1da1c"},
|
||||
{file = "kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07b29089b7ba090b6f1a669f1411f27221c3662b3a1b7010e67b59bb5a6f10b"},
|
||||
{file = "kiwisolver-1.4.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:65ea09a5a3faadd59c2ce96dc7bf0f364986a315949dc6374f04396b0d60e09b"},
|
||||
{file = "kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "langchain"
|
||||
version = "0.3.23"
|
||||
@ -3242,6 +3495,63 @@ dev = ["marshmallow-sqlalchemy[tests]", "pre-commit (>=3.5,<5.0)", "tox"]
|
||||
docs = ["furo (==2024.8.6)", "sphinx (==8.2.3)", "sphinx-copybutton (==0.5.2)", "sphinx-design (==0.6.1)", "sphinx-issues (==5.0.0)", "sphinxext-opengraph (==0.10.0)"]
|
||||
tests = ["pytest (<9)", "pytest-lazy-fixtures"]
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib"
|
||||
version = "3.10.1"
|
||||
description = "Python plotting package"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
files = [
|
||||
{file = "matplotlib-3.10.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ff2ae14910be903f4a24afdbb6d7d3a6c44da210fc7d42790b87aeac92238a16"},
|
||||
{file = "matplotlib-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0721a3fd3d5756ed593220a8b86808a36c5031fce489adb5b31ee6dbb47dd5b2"},
|
||||
{file = "matplotlib-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0673b4b8f131890eb3a1ad058d6e065fb3c6e71f160089b65f8515373394698"},
|
||||
{file = "matplotlib-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e875b95ac59a7908978fe307ecdbdd9a26af7fa0f33f474a27fcf8c99f64a19"},
|
||||
{file = "matplotlib-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2589659ea30726284c6c91037216f64a506a9822f8e50592d48ac16a2f29e044"},
|
||||
{file = "matplotlib-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a97ff127f295817bc34517255c9db6e71de8eddaab7f837b7d341dee9f2f587f"},
|
||||
{file = "matplotlib-3.10.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:057206ff2d6ab82ff3e94ebd94463d084760ca682ed5f150817b859372ec4401"},
|
||||
{file = "matplotlib-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a144867dd6bf8ba8cb5fc81a158b645037e11b3e5cf8a50bd5f9917cb863adfe"},
|
||||
{file = "matplotlib-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56c5d9fcd9879aa8040f196a235e2dcbdf7dd03ab5b07c0696f80bc6cf04bedd"},
|
||||
{file = "matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f69dc9713e4ad2fb21a1c30e37bd445d496524257dfda40ff4a8efb3604ab5c"},
|
||||
{file = "matplotlib-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c59af3e8aca75d7744b68e8e78a669e91ccbcf1ac35d0102a7b1b46883f1dd7"},
|
||||
{file = "matplotlib-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:11b65088c6f3dae784bc72e8d039a2580186285f87448babb9ddb2ad0082993a"},
|
||||
{file = "matplotlib-3.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:66e907a06e68cb6cfd652c193311d61a12b54f56809cafbed9736ce5ad92f107"},
|
||||
{file = "matplotlib-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b4bb156abb8fa5e5b2b460196f7db7264fc6d62678c03457979e7d5254b7be"},
|
||||
{file = "matplotlib-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1985ad3d97f51307a2cbfc801a930f120def19ba22864182dacef55277102ba6"},
|
||||
{file = "matplotlib-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c96f2c2f825d1257e437a1482c5a2cf4fee15db4261bd6fc0750f81ba2b4ba3d"},
|
||||
{file = "matplotlib-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35e87384ee9e488d8dd5a2dd7baf471178d38b90618d8ea147aced4ab59c9bea"},
|
||||
{file = "matplotlib-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfd414bce89cc78a7e1d25202e979b3f1af799e416010a20ab2b5ebb3a02425c"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42eee41e1b60fd83ee3292ed83a97a5f2a8239b10c26715d8a6172226988d7b"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4f0647b17b667ae745c13721602b540f7aadb2a32c5b96e924cd4fea5dcb90f1"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa3854b5f9473564ef40a41bc922be978fab217776e9ae1545c9b3a5cf2092a3"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e496c01441be4c7d5f96d4e40f7fca06e20dcb40e44c8daa2e740e1757ad9e6"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5d45d3f5245be5b469843450617dcad9af75ca50568acf59997bed9311131a0b"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:8e8e25b1209161d20dfe93037c8a7f7ca796ec9aa326e6e4588d8c4a5dd1e473"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:19b06241ad89c3ae9469e07d77efa87041eac65d78df4fcf9cac318028009b01"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01e63101ebb3014e6e9f80d9cf9ee361a8599ddca2c3e166c563628b39305dbb"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f06bad951eea6422ac4e8bdebcf3a70c59ea0a03338c5d2b109f57b64eb3972"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfb036f34873b46978f55e240cff7a239f6c4409eac62d8145bad3fc6ba5a3"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dc6ab14a7ab3b4d813b88ba957fc05c79493a037f54e246162033591e770de6f"},
|
||||
{file = "matplotlib-3.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bc411ebd5889a78dabbc457b3fa153203e22248bfa6eedc6797be5df0164dbf9"},
|
||||
{file = "matplotlib-3.10.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:648406f1899f9a818cef8c0231b44dcfc4ff36f167101c3fd1c9151f24220fdc"},
|
||||
{file = "matplotlib-3.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:02582304e352f40520727984a5a18f37e8187861f954fea9be7ef06569cf85b4"},
|
||||
{file = "matplotlib-3.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3809916157ba871bcdd33d3493acd7fe3037db5daa917ca6e77975a94cef779"},
|
||||
{file = "matplotlib-3.10.1.tar.gz", hash = "sha256:e8d2d0e3881b129268585bf4765ad3ee73a4591d77b9a18c214ac7e3a79fb2ba"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
contourpy = ">=1.0.1"
|
||||
cycler = ">=0.10"
|
||||
fonttools = ">=4.22.0"
|
||||
kiwisolver = ">=1.3.1"
|
||||
numpy = ">=1.23"
|
||||
packaging = ">=20.0"
|
||||
pillow = ">=8"
|
||||
pyparsing = ">=2.3.1"
|
||||
python-dateutil = ">=2.7"
|
||||
|
||||
[package.extras]
|
||||
dev = ["meson-python (>=0.13.1,<0.17.0)", "pybind11 (>=2.13.2,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"]
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib-inline"
|
||||
version = "0.1.7"
|
||||
@ -4793,6 +5103,20 @@ cffi = ">=1.4.1"
|
||||
docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
|
||||
tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.2.3"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"},
|
||||
{file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pypdf"
|
||||
version = "5.4.0"
|
||||
@ -6846,4 +7170,4 @@ tests = ["wikipedia"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "<3.14,>=3.10"
|
||||
content-hash = "16f6a0c089d3eeca4107a9191201138340570cd40d52ca21a827ac0189fbf15d"
|
||||
content-hash = "5fd927f0519033fb00c3769ab81d682019e532697a374457c50faf4f75bdca02"
|
||||
|
@ -90,6 +90,7 @@ mcp = "^1.3.0"
|
||||
firecrawl-py = "^1.15.0"
|
||||
apscheduler = "^3.11.0"
|
||||
aiomultiprocess = "^0.9.1"
|
||||
matplotlib = "^3.10.1"
|
||||
|
||||
|
||||
[tool.poetry.extras]
|
||||
|
@ -435,7 +435,7 @@ def sarah_agent(server: SyncServer, default_user, default_organization):
|
||||
agent_create=CreateAgent(
|
||||
name="sarah_agent",
|
||||
memory_blocks=[],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -451,7 +451,7 @@ def charles_agent(server: SyncServer, default_user, default_organization):
|
||||
agent_create=CreateAgent(
|
||||
name="charles_agent",
|
||||
memory_blocks=[CreateBlock(label="human", value="Charles"), CreateBlock(label="persona", value="I am a helpful assistant")],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -466,7 +466,7 @@ def comprehensive_test_agent_fixture(server: SyncServer, default_user, print_too
|
||||
create_agent_request = CreateAgent(
|
||||
system="test system",
|
||||
memory_blocks=memory_blocks,
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
block_ids=[default_block.id],
|
||||
tool_ids=[print_tool.id],
|
||||
@ -586,7 +586,7 @@ def agent_with_tags(server: SyncServer, default_user):
|
||||
|
||||
@pytest.fixture
|
||||
def dummy_llm_config() -> LLMConfig:
|
||||
return LLMConfig.default_config("gpt-4")
|
||||
return LLMConfig.default_config("gpt-4o-mini")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -655,7 +655,7 @@ def test_create_agent_passed_in_initial_messages(server: SyncServer, default_use
|
||||
create_agent_request = CreateAgent(
|
||||
system="test system",
|
||||
memory_blocks=memory_blocks,
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
block_ids=[default_block.id],
|
||||
tags=["a", "b"],
|
||||
@ -669,6 +669,7 @@ def test_create_agent_passed_in_initial_messages(server: SyncServer, default_use
|
||||
)
|
||||
assert server.message_manager.size(agent_id=agent_state.id, actor=default_user) == 2
|
||||
init_messages = server.agent_manager.get_in_context_messages(agent_id=agent_state.id, actor=default_user)
|
||||
|
||||
# Check that the system appears in the first initial message
|
||||
assert create_agent_request.system in init_messages[0].content[0].text
|
||||
assert create_agent_request.memory_blocks[0].value in init_messages[0].content[0].text
|
||||
@ -682,7 +683,7 @@ def test_create_agent_default_initial_message(server: SyncServer, default_user,
|
||||
create_agent_request = CreateAgent(
|
||||
system="test system",
|
||||
memory_blocks=memory_blocks,
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
block_ids=[default_block.id],
|
||||
tags=["a", "b"],
|
||||
@ -710,7 +711,7 @@ def test_create_agent_with_json_in_system_message(server: SyncServer, default_us
|
||||
)
|
||||
create_agent_request = CreateAgent(
|
||||
system=system_prompt,
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
block_ids=[default_block.id],
|
||||
tags=["a", "b"],
|
||||
@ -858,7 +859,7 @@ def test_list_agents_ascending(server: SyncServer, default_user):
|
||||
agent1 = server.agent_manager.create_agent(
|
||||
agent_create=CreateAgent(
|
||||
name="agent_oldest",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
memory_blocks=[],
|
||||
include_base_tools=False,
|
||||
@ -872,7 +873,7 @@ def test_list_agents_ascending(server: SyncServer, default_user):
|
||||
agent2 = server.agent_manager.create_agent(
|
||||
agent_create=CreateAgent(
|
||||
name="agent_newest",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
memory_blocks=[],
|
||||
include_base_tools=False,
|
||||
@ -890,7 +891,7 @@ def test_list_agents_descending(server: SyncServer, default_user):
|
||||
agent1 = server.agent_manager.create_agent(
|
||||
agent_create=CreateAgent(
|
||||
name="agent_oldest",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
memory_blocks=[],
|
||||
include_base_tools=False,
|
||||
@ -904,7 +905,7 @@ def test_list_agents_descending(server: SyncServer, default_user):
|
||||
agent2 = server.agent_manager.create_agent(
|
||||
agent_create=CreateAgent(
|
||||
name="agent_newest",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
memory_blocks=[],
|
||||
include_base_tools=False,
|
||||
@ -927,7 +928,7 @@ def test_list_agents_ordering_and_pagination(server: SyncServer, default_user):
|
||||
agent_create=CreateAgent(
|
||||
name=name,
|
||||
memory_blocks=[],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -1288,7 +1289,7 @@ def test_list_agents_by_tags_pagination(server: SyncServer, default_user, defaul
|
||||
agent_create=CreateAgent(
|
||||
name="agent1",
|
||||
tags=["pagination_test", "tag1"],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
memory_blocks=[],
|
||||
include_base_tools=False,
|
||||
@ -1304,7 +1305,7 @@ def test_list_agents_by_tags_pagination(server: SyncServer, default_user, defaul
|
||||
agent_create=CreateAgent(
|
||||
name="agent2",
|
||||
tags=["pagination_test", "tag2"],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
memory_blocks=[],
|
||||
include_base_tools=False,
|
||||
@ -1346,7 +1347,7 @@ def test_list_agents_query_text_pagination(server: SyncServer, default_user, def
|
||||
name="Search Agent One",
|
||||
memory_blocks=[],
|
||||
description="This is a search agent for testing",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -1358,7 +1359,7 @@ def test_list_agents_query_text_pagination(server: SyncServer, default_user, def
|
||||
name="Search Agent Two",
|
||||
memory_blocks=[],
|
||||
description="Another search agent for testing",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -1370,7 +1371,7 @@ def test_list_agents_query_text_pagination(server: SyncServer, default_user, def
|
||||
name="Different Agent",
|
||||
memory_blocks=[],
|
||||
description="This is a different agent",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -1700,7 +1701,7 @@ def test_refresh_memory(server: SyncServer, default_user):
|
||||
agent = server.agent_manager.create_agent(
|
||||
CreateAgent(
|
||||
name="test",
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -2706,6 +2707,36 @@ def test_get_agents_for_block(server: SyncServer, sarah_agent, charles_agent, de
|
||||
assert charles_agent.id in agent_state_ids
|
||||
|
||||
|
||||
def test_batch_create_multiple_blocks(server: SyncServer, default_user):
|
||||
block_manager = BlockManager()
|
||||
num_blocks = 10
|
||||
|
||||
# Prepare distinct blocks
|
||||
blocks_to_create = [PydanticBlock(label=f"batch_label_{i}", value=f"batch_value_{i}") for i in range(num_blocks)]
|
||||
|
||||
# Create the blocks
|
||||
created_blocks = block_manager.batch_create_blocks(blocks_to_create, actor=default_user)
|
||||
assert len(created_blocks) == num_blocks
|
||||
|
||||
# Map created blocks by label for lookup
|
||||
created_by_label = {blk.label: blk for blk in created_blocks}
|
||||
|
||||
# Assert all blocks were created correctly
|
||||
for i in range(num_blocks):
|
||||
label = f"batch_label_{i}"
|
||||
value = f"batch_value_{i}"
|
||||
assert label in created_by_label, f"Missing label: {label}"
|
||||
blk = created_by_label[label]
|
||||
assert blk.value == value
|
||||
assert blk.organization_id == default_user.organization_id
|
||||
assert blk.id is not None
|
||||
|
||||
# Confirm all created blocks exist in the full list from get_blocks
|
||||
all_labels = {blk.label for blk in block_manager.get_blocks(actor=default_user)}
|
||||
expected_labels = {f"batch_label_{i}" for i in range(num_blocks)}
|
||||
assert expected_labels.issubset(all_labels)
|
||||
|
||||
|
||||
# ======================================================================================================================
|
||||
# Block Manager Tests - Checkpointing
|
||||
# ======================================================================================================================
|
||||
@ -3401,7 +3432,7 @@ def test_get_set_agents_for_identities(server: SyncServer, sarah_agent, charles_
|
||||
agent_with_identity = server.create_agent(
|
||||
CreateAgent(
|
||||
memory_blocks=[],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
identity_ids=[identity.id],
|
||||
include_base_tools=False,
|
||||
@ -3411,7 +3442,7 @@ def test_get_set_agents_for_identities(server: SyncServer, sarah_agent, charles_
|
||||
agent_without_identity = server.create_agent(
|
||||
CreateAgent(
|
||||
memory_blocks=[],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
include_base_tools=False,
|
||||
),
|
||||
@ -4618,7 +4649,7 @@ def test_job_usage_stats_add_and_get(server: SyncServer, sarah_agent, default_jo
|
||||
step_manager.log_step(
|
||||
agent_id=sarah_agent.id,
|
||||
provider_name="openai",
|
||||
model="gpt-4",
|
||||
model="gpt-4o-mini",
|
||||
model_endpoint="https://api.openai.com/v1",
|
||||
context_window_limit=8192,
|
||||
job_id=default_job.id,
|
||||
@ -4669,7 +4700,7 @@ def test_job_usage_stats_add_multiple(server: SyncServer, sarah_agent, default_j
|
||||
step_manager.log_step(
|
||||
agent_id=sarah_agent.id,
|
||||
provider_name="openai",
|
||||
model="gpt-4",
|
||||
model="gpt-4o-mini",
|
||||
model_endpoint="https://api.openai.com/v1",
|
||||
context_window_limit=8192,
|
||||
job_id=default_job.id,
|
||||
@ -4685,7 +4716,7 @@ def test_job_usage_stats_add_multiple(server: SyncServer, sarah_agent, default_j
|
||||
step_manager.log_step(
|
||||
agent_id=sarah_agent.id,
|
||||
provider_name="openai",
|
||||
model="gpt-4",
|
||||
model="gpt-4o-mini",
|
||||
model_endpoint="https://api.openai.com/v1",
|
||||
context_window_limit=8192,
|
||||
job_id=default_job.id,
|
||||
@ -4731,7 +4762,7 @@ def test_job_usage_stats_add_nonexistent_job(server: SyncServer, sarah_agent, de
|
||||
step_manager.log_step(
|
||||
agent_id=sarah_agent.id,
|
||||
provider_name="openai",
|
||||
model="gpt-4",
|
||||
model="gpt-4o-mini",
|
||||
model_endpoint="https://api.openai.com/v1",
|
||||
context_window_limit=8192,
|
||||
job_id="nonexistent_job",
|
||||
@ -4757,7 +4788,7 @@ def test_list_tags(server: SyncServer, default_user, default_organization):
|
||||
agent_create=CreateAgent(
|
||||
name="tag_agent_" + str(i),
|
||||
memory_blocks=[],
|
||||
llm_config=LLMConfig.default_config("gpt-4"),
|
||||
llm_config=LLMConfig.default_config("gpt-4o-mini"),
|
||||
embedding_config=EmbeddingConfig.default_config(provider="openai"),
|
||||
tags=tags[i : i + 3], # Each agent gets 3 consecutive tags
|
||||
include_base_tools=False,
|
||||
|
Loading…
Reference in New Issue
Block a user