jl-ecms-client 0.2.5__py3-none-any.whl → 0.2.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jl_ecms_client-0.2.5.dist-info → jl_ecms_client-0.2.19.dist-info}/METADATA +6 -1
- {jl_ecms_client-0.2.5.dist-info → jl_ecms_client-0.2.19.dist-info}/RECORD +29 -22
- mirix/__init__.py +32 -0
- mirix/client/__init__.py +5 -63
- mirix/client/client.py +6 -2195
- mirix/client/utils.py +34 -0
- mirix/constants.py +251 -0
- mirix/errors.py +238 -0
- mirix/helpers/json_helpers.py +3 -3
- mirix/log.py +163 -0
- mirix/schemas/agent.py +5 -4
- mirix/schemas/cloud_file_mapping.py +1 -1
- mirix/schemas/embedding_config.py +0 -3
- mirix/schemas/enums.py +12 -0
- mirix/schemas/episodic_memory.py +1 -1
- mirix/schemas/knowledge_vault.py +1 -1
- mirix/schemas/mirix_response.py +1 -1
- mirix/schemas/organization.py +5 -5
- mirix/schemas/procedural_memory.py +1 -1
- mirix/schemas/resource_memory.py +1 -1
- mirix/schemas/sandbox_config.py +1 -3
- mirix/schemas/semantic_memory.py +1 -1
- mirix/schemas/tool.py +241 -241
- mirix/schemas/user.py +3 -3
- mirix/settings.py +280 -0
- mirix/system.py +261 -0
- {jl_ecms_client-0.2.5.dist-info → jl_ecms_client-0.2.19.dist-info}/WHEEL +0 -0
- {jl_ecms_client-0.2.5.dist-info → jl_ecms_client-0.2.19.dist-info}/licenses/LICENSE +0 -0
- {jl_ecms_client-0.2.5.dist-info → jl_ecms_client-0.2.19.dist-info}/top_level.txt +0 -0
mirix/client/client.py
CHANGED
|
@@ -9,8 +9,6 @@ from urllib.parse import urlparse
|
|
|
9
9
|
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
|
-
import mirix.utils
|
|
13
|
-
|
|
14
12
|
if TYPE_CHECKING:
|
|
15
13
|
try:
|
|
16
14
|
from composio import ActionType
|
|
@@ -24,22 +22,8 @@ if TYPE_CHECKING:
|
|
|
24
22
|
from langchain_core.tools import BaseTool as LangChainBaseTool
|
|
25
23
|
except ImportError:
|
|
26
24
|
LangChainBaseTool = Any # type: ignore
|
|
27
|
-
from mirix.constants import
|
|
28
|
-
|
|
29
|
-
DEFAULT_HUMAN,
|
|
30
|
-
DEFAULT_PERSONA,
|
|
31
|
-
FUNCTION_RETURN_CHAR_LIMIT,
|
|
32
|
-
META_MEMORY_TOOLS,
|
|
33
|
-
)
|
|
34
|
-
from mirix.functions.functions import parse_source_code
|
|
35
|
-
from mirix.interface import QueuingInterface
|
|
36
|
-
from mirix.orm.errors import NoResultFound
|
|
37
|
-
from mirix.schemas.agent import (
|
|
38
|
-
AgentState,
|
|
39
|
-
AgentType,
|
|
40
|
-
CreateAgent,
|
|
41
|
-
CreateMetaAgent,
|
|
42
|
-
)
|
|
25
|
+
from mirix.constants import FUNCTION_RETURN_CHAR_LIMIT
|
|
26
|
+
from mirix.schemas.agent import AgentState, AgentType, CreateAgent, CreateMetaAgent
|
|
43
27
|
from mirix.schemas.block import Block, BlockUpdate, CreateBlock, Human, Persona
|
|
44
28
|
from mirix.schemas.embedding_config import EmbeddingConfig
|
|
45
29
|
|
|
@@ -53,11 +37,7 @@ from mirix.schemas.environment_variables import (
|
|
|
53
37
|
from mirix.schemas.file import FileMetadata
|
|
54
38
|
from mirix.schemas.file import FileMetadata as PydanticFileMetadata
|
|
55
39
|
from mirix.schemas.llm_config import LLMConfig
|
|
56
|
-
from mirix.schemas.memory import
|
|
57
|
-
ArchivalMemorySummary,
|
|
58
|
-
Memory,
|
|
59
|
-
RecallMemorySummary,
|
|
60
|
-
)
|
|
40
|
+
from mirix.schemas.memory import ArchivalMemorySummary, Memory, RecallMemorySummary
|
|
61
41
|
from mirix.schemas.message import Message, MessageCreate
|
|
62
42
|
from mirix.schemas.mirix_message_content import (
|
|
63
43
|
CloudFileContent,
|
|
@@ -77,11 +57,8 @@ from mirix.schemas.sandbox_config import (
|
|
|
77
57
|
)
|
|
78
58
|
from mirix.schemas.tool import Tool, ToolCreate, ToolUpdate
|
|
79
59
|
from mirix.schemas.tool_rule import BaseToolRule
|
|
80
|
-
from mirix.schemas.user import User as PydanticUser
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def create_client():
|
|
84
|
-
return LocalClient()
|
|
60
|
+
from mirix.schemas.user import User as PydanticUser
|
|
61
|
+
from mirix.schemas.user import UserCreate
|
|
85
62
|
|
|
86
63
|
|
|
87
64
|
class AbstractClient(object):
|
|
@@ -109,10 +86,7 @@ class AbstractClient(object):
|
|
|
109
86
|
tool_rules: Optional[List[BaseToolRule]] = None,
|
|
110
87
|
include_base_tools: Optional[bool] = True,
|
|
111
88
|
include_meta_memory_tools: Optional[bool] = False,
|
|
112
|
-
metadata: Optional[Dict] =
|
|
113
|
-
"human:": DEFAULT_HUMAN,
|
|
114
|
-
"persona": DEFAULT_PERSONA,
|
|
115
|
-
},
|
|
89
|
+
metadata: Optional[Dict] = None,
|
|
116
90
|
description: Optional[str] = None,
|
|
117
91
|
initial_message_sequence: Optional[List[Message]] = None,
|
|
118
92
|
tags: Optional[List[str]] = None,
|
|
@@ -429,2166 +403,3 @@ class AbstractClient(object):
|
|
|
429
403
|
List[SandboxEnvironmentVariable]: A list of environment variables.
|
|
430
404
|
"""
|
|
431
405
|
raise NotImplementedError
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
class LocalClient(AbstractClient):
|
|
435
|
-
"""
|
|
436
|
-
A local client for Mirix, which corresponds to a single user.
|
|
437
|
-
|
|
438
|
-
Attributes:
|
|
439
|
-
user_id (str): The user ID.
|
|
440
|
-
debug (bool): Whether to print debug information.
|
|
441
|
-
interface (QueuingInterface): The interface for the client.
|
|
442
|
-
server (SyncServer): The server for the client.
|
|
443
|
-
"""
|
|
444
|
-
|
|
445
|
-
def __init__(
|
|
446
|
-
self,
|
|
447
|
-
user_id: Optional[str] = None,
|
|
448
|
-
org_id: Optional[str] = None,
|
|
449
|
-
debug: bool = False,
|
|
450
|
-
default_llm_config: Optional[LLMConfig] = None,
|
|
451
|
-
default_embedding_config: Optional[EmbeddingConfig] = None,
|
|
452
|
-
):
|
|
453
|
-
"""
|
|
454
|
-
Initializes a new instance of Client class.
|
|
455
|
-
|
|
456
|
-
Args:
|
|
457
|
-
user_id (str): The user ID.
|
|
458
|
-
debug (bool): Whether to print debug information.
|
|
459
|
-
"""
|
|
460
|
-
|
|
461
|
-
from mirix.server.server import SyncServer
|
|
462
|
-
|
|
463
|
-
# set logging levels
|
|
464
|
-
mirix.utils.DEBUG = debug
|
|
465
|
-
logging.getLogger().setLevel(logging.CRITICAL)
|
|
466
|
-
|
|
467
|
-
# save default model config
|
|
468
|
-
self._default_llm_config = default_llm_config
|
|
469
|
-
self._default_embedding_config = default_embedding_config
|
|
470
|
-
|
|
471
|
-
# create server
|
|
472
|
-
self.interface = QueuingInterface(debug=debug)
|
|
473
|
-
self.server = SyncServer(default_interface_factory=lambda: self.interface)
|
|
474
|
-
|
|
475
|
-
# initialize file manager
|
|
476
|
-
from mirix.services.file_manager import FileManager
|
|
477
|
-
|
|
478
|
-
self.file_manager = FileManager()
|
|
479
|
-
|
|
480
|
-
# save org_id that `LocalClient` is associated with
|
|
481
|
-
if org_id:
|
|
482
|
-
self.org_id = org_id
|
|
483
|
-
else:
|
|
484
|
-
self.org_id = self.server.organization_manager.DEFAULT_ORG_ID
|
|
485
|
-
# save user_id that `LocalClient` is associated with
|
|
486
|
-
if user_id:
|
|
487
|
-
self.user_id = user_id
|
|
488
|
-
else:
|
|
489
|
-
# get default user
|
|
490
|
-
self.user_id = self.server.user_manager.DEFAULT_USER_ID
|
|
491
|
-
|
|
492
|
-
self.user = self.server.user_manager.get_user_or_default(self.user_id)
|
|
493
|
-
self.organization = self.server.get_organization_or_default(self.org_id)
|
|
494
|
-
|
|
495
|
-
# get images directory from settings and ensure it exists
|
|
496
|
-
# Can be customized via MIRIX_IMAGES_DIR environment variable
|
|
497
|
-
from mirix.settings import settings
|
|
498
|
-
|
|
499
|
-
self.images_dir = Path(settings.images_dir)
|
|
500
|
-
self.images_dir.mkdir(parents=True, exist_ok=True)
|
|
501
|
-
|
|
502
|
-
def _generate_file_hash(self, content: bytes) -> str:
|
|
503
|
-
"""Generate a unique hash for file content to avoid duplicates."""
|
|
504
|
-
return hashlib.sha256(content).hexdigest()[:16]
|
|
505
|
-
|
|
506
|
-
def _save_image_from_base64(
|
|
507
|
-
self, base64_data: str, detail: str = "auto"
|
|
508
|
-
) -> FileMetadata:
|
|
509
|
-
"""Save an image from base64 data and return FileMetadata."""
|
|
510
|
-
try:
|
|
511
|
-
# Parse the data URL format: data:image/jpeg;base64,{data}
|
|
512
|
-
if base64_data.startswith("data:"):
|
|
513
|
-
header, encoded = base64_data.split(",", 1)
|
|
514
|
-
# Extract MIME type from header
|
|
515
|
-
mime_type = header.split(":")[1].split(";")[0]
|
|
516
|
-
file_extension = mime_type.split("/")[-1]
|
|
517
|
-
else:
|
|
518
|
-
# Assume it's just base64 data without header
|
|
519
|
-
encoded = base64_data
|
|
520
|
-
mime_type = "image/jpeg"
|
|
521
|
-
file_extension = "jpg"
|
|
522
|
-
|
|
523
|
-
# Decode base64 data
|
|
524
|
-
image_data = base64.b64decode(encoded)
|
|
525
|
-
|
|
526
|
-
# Generate unique filename using hash
|
|
527
|
-
file_hash = self._generate_file_hash(image_data)
|
|
528
|
-
file_name = f"image_{file_hash}.{file_extension}"
|
|
529
|
-
file_path = self.images_dir / file_name
|
|
530
|
-
|
|
531
|
-
# Check if file already exists
|
|
532
|
-
if not file_path.exists():
|
|
533
|
-
# Save the image data
|
|
534
|
-
with open(file_path, "wb") as f:
|
|
535
|
-
f.write(image_data)
|
|
536
|
-
|
|
537
|
-
# Create FileMetadata
|
|
538
|
-
file_metadata = self.file_manager.create_file_metadata_from_path(
|
|
539
|
-
file_path=str(file_path), organization_id=self.org_id
|
|
540
|
-
)
|
|
541
|
-
|
|
542
|
-
return file_metadata
|
|
543
|
-
|
|
544
|
-
except Exception as e:
|
|
545
|
-
raise ValueError(f"Failed to save base64 image: {str(e)}")
|
|
546
|
-
|
|
547
|
-
def _save_image_from_url(self, url: str, detail: str = "auto") -> FileMetadata:
|
|
548
|
-
"""Download and save an image from URL and return FileMetadata."""
|
|
549
|
-
try:
|
|
550
|
-
# Download the image
|
|
551
|
-
response = requests.get(url, stream=True, timeout=30)
|
|
552
|
-
response.raise_for_status()
|
|
553
|
-
|
|
554
|
-
# Get content type and determine file extension
|
|
555
|
-
content_type = response.headers.get("content-type", "image/jpeg")
|
|
556
|
-
file_extension = content_type.split("/")[-1]
|
|
557
|
-
if file_extension not in ["jpg", "jpeg", "png", "gif", "webp"]:
|
|
558
|
-
file_extension = "jpg"
|
|
559
|
-
|
|
560
|
-
# Get the image content
|
|
561
|
-
image_data = response.content
|
|
562
|
-
|
|
563
|
-
# Generate unique filename using hash
|
|
564
|
-
file_hash = self._generate_file_hash(image_data)
|
|
565
|
-
file_name = f"image_{file_hash}.{file_extension}"
|
|
566
|
-
file_path = self.images_dir / file_name
|
|
567
|
-
|
|
568
|
-
# Check if file already exists
|
|
569
|
-
if not file_path.exists():
|
|
570
|
-
# Save the image data
|
|
571
|
-
with open(file_path, "wb") as f:
|
|
572
|
-
f.write(image_data)
|
|
573
|
-
|
|
574
|
-
# Create FileMetadata
|
|
575
|
-
file_metadata = self.file_manager.create_file_metadata_from_path(
|
|
576
|
-
file_path=str(file_path), organization_id=self.org_id
|
|
577
|
-
)
|
|
578
|
-
|
|
579
|
-
return file_metadata
|
|
580
|
-
|
|
581
|
-
except Exception as e:
|
|
582
|
-
raise ValueError(
|
|
583
|
-
f"Failed to download and save image from URL {url}: {str(e)}"
|
|
584
|
-
)
|
|
585
|
-
|
|
586
|
-
def _save_image_from_file_uri(self, file_uri: str) -> FileMetadata:
|
|
587
|
-
"""Copy an image from file URI and return FileMetadata."""
|
|
588
|
-
try:
|
|
589
|
-
# Parse file URI (could be file:// or just a local path)
|
|
590
|
-
if file_uri.startswith("file://"):
|
|
591
|
-
source_path = file_uri[7:] # Remove 'file://' prefix
|
|
592
|
-
else:
|
|
593
|
-
source_path = file_uri
|
|
594
|
-
|
|
595
|
-
source_path = Path(source_path)
|
|
596
|
-
|
|
597
|
-
if not source_path.exists():
|
|
598
|
-
raise FileNotFoundError(f"Source file not found: {source_path}")
|
|
599
|
-
|
|
600
|
-
# Read the file content
|
|
601
|
-
with open(source_path, "rb") as f:
|
|
602
|
-
image_data = f.read()
|
|
603
|
-
|
|
604
|
-
# Generate unique filename using hash
|
|
605
|
-
file_hash = self._generate_file_hash(image_data)
|
|
606
|
-
file_extension = source_path.suffix.lstrip(".") or "jpg"
|
|
607
|
-
file_name = f"image_{file_hash}.{file_extension}"
|
|
608
|
-
file_path = self.images_dir / file_name
|
|
609
|
-
|
|
610
|
-
# Check if file already exists
|
|
611
|
-
if not file_path.exists():
|
|
612
|
-
# Copy the file
|
|
613
|
-
shutil.copy2(source_path, file_path)
|
|
614
|
-
|
|
615
|
-
# Create FileMetadata
|
|
616
|
-
file_metadata = self.file_manager.create_file_metadata_from_path(
|
|
617
|
-
file_path=str(file_path), organization_id=self.org_id
|
|
618
|
-
)
|
|
619
|
-
|
|
620
|
-
return file_metadata
|
|
621
|
-
|
|
622
|
-
except Exception as e:
|
|
623
|
-
raise ValueError(f"Failed to copy image from file URI {file_uri}: {str(e)}")
|
|
624
|
-
|
|
625
|
-
def _save_image_from_google_cloud_uri(self, cloud_uri: str) -> FileMetadata:
|
|
626
|
-
"""Create FileMetadata from Google Cloud URI without downloading the image.
|
|
627
|
-
|
|
628
|
-
Google Cloud URIs are not directly downloadable and should be stored as remote references
|
|
629
|
-
in the source_url field, similar to how regular HTTP URLs are handled.
|
|
630
|
-
"""
|
|
631
|
-
# Parse URI to get file name - Google Cloud URIs typically come in the format:
|
|
632
|
-
# https://generativelanguage.googleapis.com/v1beta/files/{file_id}
|
|
633
|
-
|
|
634
|
-
parsed_uri = urlparse(cloud_uri)
|
|
635
|
-
|
|
636
|
-
# Extract file ID from path if available, otherwise use generic name
|
|
637
|
-
file_id = os.path.basename(parsed_uri.path) or "google_cloud_file"
|
|
638
|
-
file_name = f"google_cloud_{file_id}"
|
|
639
|
-
|
|
640
|
-
# Ensure file name has an extension
|
|
641
|
-
if not os.path.splitext(file_name)[1]:
|
|
642
|
-
file_name += ".jpg" # Default to jpg for images without extension
|
|
643
|
-
|
|
644
|
-
# Determine MIME type from extension or default to image/jpeg
|
|
645
|
-
file_extension = os.path.splitext(file_name)[1].lower()
|
|
646
|
-
file_type_map = {
|
|
647
|
-
".jpg": "image/jpeg",
|
|
648
|
-
".jpeg": "image/jpeg",
|
|
649
|
-
".png": "image/png",
|
|
650
|
-
".gif": "image/gif",
|
|
651
|
-
".webp": "image/webp",
|
|
652
|
-
".bmp": "image/bmp",
|
|
653
|
-
".svg": "image/svg+xml",
|
|
654
|
-
}
|
|
655
|
-
file_type = file_type_map.get(file_extension, "image/jpeg")
|
|
656
|
-
|
|
657
|
-
# Create FileMetadata with Google Cloud URI in google_cloud_url field
|
|
658
|
-
file_metadata = self.file_manager.create_file_metadata(
|
|
659
|
-
PydanticFileMetadata(
|
|
660
|
-
organization_id=self.org_id,
|
|
661
|
-
file_name=file_name,
|
|
662
|
-
file_path=None, # No local path for Google Cloud URIs
|
|
663
|
-
source_url=None, # No regular source URL for Google Cloud files
|
|
664
|
-
google_cloud_url=cloud_uri, # Store Google Cloud URI in the dedicated field
|
|
665
|
-
file_type=file_type,
|
|
666
|
-
file_size=None, # Unknown size for remote Google Cloud files
|
|
667
|
-
file_creation_date=None,
|
|
668
|
-
file_last_modified_date=None,
|
|
669
|
-
)
|
|
670
|
-
)
|
|
671
|
-
|
|
672
|
-
return file_metadata
|
|
673
|
-
|
|
674
|
-
def _save_file_from_path(self, file_path: str) -> FileMetadata:
|
|
675
|
-
"""Save a file from local path and return FileMetadata."""
|
|
676
|
-
try:
|
|
677
|
-
file_path = Path(file_path)
|
|
678
|
-
|
|
679
|
-
if not file_path.exists():
|
|
680
|
-
raise FileNotFoundError(f"File not found: {file_path}")
|
|
681
|
-
|
|
682
|
-
# Create FileMetadata using the file manager
|
|
683
|
-
file_metadata = self.file_manager.create_file_metadata_from_path(
|
|
684
|
-
file_path=str(file_path), organization_id=self.org_id
|
|
685
|
-
)
|
|
686
|
-
|
|
687
|
-
return file_metadata
|
|
688
|
-
|
|
689
|
-
except Exception as e:
|
|
690
|
-
raise ValueError(f"Failed to save file from path {file_path}: {str(e)}")
|
|
691
|
-
|
|
692
|
-
def _determine_file_type(self, file_path: str) -> str:
|
|
693
|
-
"""Determine file type from file extension."""
|
|
694
|
-
file_extension = os.path.splitext(file_path)[1].lower()
|
|
695
|
-
file_type_map = {
|
|
696
|
-
# Images
|
|
697
|
-
".jpg": "image/jpeg",
|
|
698
|
-
".jpeg": "image/jpeg",
|
|
699
|
-
".png": "image/png",
|
|
700
|
-
".gif": "image/gif",
|
|
701
|
-
".webp": "image/webp",
|
|
702
|
-
".bmp": "image/bmp",
|
|
703
|
-
".svg": "image/svg+xml",
|
|
704
|
-
# Documents
|
|
705
|
-
".pdf": "application/pdf",
|
|
706
|
-
".doc": "application/msword",
|
|
707
|
-
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
708
|
-
".txt": "text/plain",
|
|
709
|
-
".rtf": "application/rtf",
|
|
710
|
-
".html": "text/html",
|
|
711
|
-
".htm": "text/html",
|
|
712
|
-
# Spreadsheets
|
|
713
|
-
".xls": "application/vnd.ms-excel",
|
|
714
|
-
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
715
|
-
".csv": "text/csv",
|
|
716
|
-
# Presentations
|
|
717
|
-
".ppt": "application/vnd.ms-powerpoint",
|
|
718
|
-
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
719
|
-
# Other common formats
|
|
720
|
-
".json": "application/json",
|
|
721
|
-
".xml": "application/xml",
|
|
722
|
-
".zip": "application/zip",
|
|
723
|
-
}
|
|
724
|
-
return file_type_map.get(file_extension, "application/octet-stream")
|
|
725
|
-
|
|
726
|
-
def _create_file_metadata_from_url(
|
|
727
|
-
self, url: str, detail: str = "auto"
|
|
728
|
-
) -> FileMetadata:
|
|
729
|
-
"""Create FileMetadata from URL without downloading the image.
|
|
730
|
-
|
|
731
|
-
The URL is stored in the source_url field, not file_path, to clearly
|
|
732
|
-
distinguish between local files and remote resources.
|
|
733
|
-
"""
|
|
734
|
-
try:
|
|
735
|
-
# Parse URL to get file name
|
|
736
|
-
from urllib.parse import urlparse
|
|
737
|
-
|
|
738
|
-
parsed_url = urlparse(url)
|
|
739
|
-
file_name = os.path.basename(parsed_url.path) or "remote_image"
|
|
740
|
-
|
|
741
|
-
# Ensure file name has an extension
|
|
742
|
-
if not os.path.splitext(file_name)[1]:
|
|
743
|
-
file_name += ".jpg" # Default to jpg for images without extension
|
|
744
|
-
|
|
745
|
-
# Determine MIME type from extension or default to image/jpeg
|
|
746
|
-
file_extension = os.path.splitext(file_name)[1].lower()
|
|
747
|
-
file_type_map = {
|
|
748
|
-
".jpg": "image/jpeg",
|
|
749
|
-
".jpeg": "image/jpeg",
|
|
750
|
-
".png": "image/png",
|
|
751
|
-
".gif": "image/gif",
|
|
752
|
-
".webp": "image/webp",
|
|
753
|
-
".bmp": "image/bmp",
|
|
754
|
-
".svg": "image/svg+xml",
|
|
755
|
-
}
|
|
756
|
-
file_type = file_type_map.get(file_extension, "image/jpeg")
|
|
757
|
-
|
|
758
|
-
# Create FileMetadata with URL in source_url field
|
|
759
|
-
file_metadata = self.file_manager.create_file_metadata(
|
|
760
|
-
PydanticFileMetadata(
|
|
761
|
-
organization_id=self.org_id,
|
|
762
|
-
file_name=file_name,
|
|
763
|
-
file_path=None, # No local path for remote URLs
|
|
764
|
-
source_url=url, # Store URL in the dedicated field
|
|
765
|
-
file_type=file_type,
|
|
766
|
-
file_size=None, # Unknown size for remote URLs
|
|
767
|
-
file_creation_date=None,
|
|
768
|
-
file_last_modified_date=None,
|
|
769
|
-
)
|
|
770
|
-
)
|
|
771
|
-
|
|
772
|
-
return file_metadata
|
|
773
|
-
|
|
774
|
-
except Exception as e:
|
|
775
|
-
raise ValueError(f"Failed to create file metadata from URL {url}: {str(e)}")
|
|
776
|
-
|
|
777
|
-
# agents
|
|
778
|
-
def list_agents(
|
|
779
|
-
self,
|
|
780
|
-
query_text: Optional[str] = None,
|
|
781
|
-
tags: Optional[List[str]] = None,
|
|
782
|
-
limit: int = 100,
|
|
783
|
-
cursor: Optional[str] = None,
|
|
784
|
-
parent_id: Optional[str] = None,
|
|
785
|
-
) -> List[AgentState]:
|
|
786
|
-
self.interface.clear()
|
|
787
|
-
|
|
788
|
-
return self.server.agent_manager.list_agents(
|
|
789
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
790
|
-
tags=tags,
|
|
791
|
-
query_text=query_text,
|
|
792
|
-
limit=limit,
|
|
793
|
-
cursor=cursor,
|
|
794
|
-
parent_id=parent_id,
|
|
795
|
-
)
|
|
796
|
-
|
|
797
|
-
def agent_exists(
|
|
798
|
-
self, agent_id: Optional[str] = None, agent_name: Optional[str] = None
|
|
799
|
-
) -> bool:
|
|
800
|
-
"""
|
|
801
|
-
Check if an agent exists
|
|
802
|
-
|
|
803
|
-
Args:
|
|
804
|
-
agent_id (str): ID of the agent
|
|
805
|
-
agent_name (str): Name of the agent
|
|
806
|
-
|
|
807
|
-
Returns:
|
|
808
|
-
exists (bool): `True` if the agent exists, `False` otherwise
|
|
809
|
-
"""
|
|
810
|
-
|
|
811
|
-
if not (agent_id or agent_name):
|
|
812
|
-
raise ValueError("Either agent_id or agent_name must be provided")
|
|
813
|
-
if agent_id and agent_name:
|
|
814
|
-
raise ValueError("Only one of agent_id or agent_name can be provided")
|
|
815
|
-
existing = self.list_agents()
|
|
816
|
-
if agent_id:
|
|
817
|
-
return str(agent_id) in [str(agent.id) for agent in existing]
|
|
818
|
-
else:
|
|
819
|
-
return agent_name in [str(agent.name) for agent in existing]
|
|
820
|
-
|
|
821
|
-
def create_agent(
|
|
822
|
-
self,
|
|
823
|
-
name: Optional[str] = None,
|
|
824
|
-
# agent config
|
|
825
|
-
agent_type: Optional[AgentType] = AgentType.chat_agent,
|
|
826
|
-
# model configs
|
|
827
|
-
embedding_config: Optional[EmbeddingConfig] = None,
|
|
828
|
-
llm_config: Optional[LLMConfig] = None,
|
|
829
|
-
# memory
|
|
830
|
-
memory: Optional[Memory] = None,
|
|
831
|
-
block_ids: Optional[List[str]] = None,
|
|
832
|
-
system: Optional[str] = None,
|
|
833
|
-
# tools
|
|
834
|
-
tool_ids: Optional[List[str]] = None,
|
|
835
|
-
tool_rules: Optional[List[BaseToolRule]] = None,
|
|
836
|
-
include_base_tools: Optional[bool] = True,
|
|
837
|
-
include_meta_memory_tools: Optional[bool] = False,
|
|
838
|
-
# metadata
|
|
839
|
-
metadata: Optional[Dict] = {
|
|
840
|
-
"human:": DEFAULT_HUMAN,
|
|
841
|
-
"persona": DEFAULT_PERSONA,
|
|
842
|
-
},
|
|
843
|
-
description: Optional[str] = None,
|
|
844
|
-
initial_message_sequence: Optional[List[Message]] = None,
|
|
845
|
-
tags: Optional[List[str]] = None,
|
|
846
|
-
) -> AgentState:
|
|
847
|
-
"""Create an agent
|
|
848
|
-
|
|
849
|
-
Args:
|
|
850
|
-
name (str): Name of the agent
|
|
851
|
-
embedding_config (EmbeddingConfig): Embedding configuration
|
|
852
|
-
llm_config (LLMConfig): LLM configuration
|
|
853
|
-
memory_blocks (List[Dict]): List of configurations for the memory blocks (placed in core-memory)
|
|
854
|
-
system (str): System configuration
|
|
855
|
-
tools (List[str]): List of tools
|
|
856
|
-
tool_rules (Optional[List[BaseToolRule]]): List of tool rules
|
|
857
|
-
include_base_tools (bool): Include base tools
|
|
858
|
-
metadata (Dict): Metadata
|
|
859
|
-
description (str): Description
|
|
860
|
-
tags (List[str]): Tags for filtering agents
|
|
861
|
-
|
|
862
|
-
Returns:
|
|
863
|
-
agent_state (AgentState): State of the created agent
|
|
864
|
-
"""
|
|
865
|
-
# construct list of tools
|
|
866
|
-
tool_ids = tool_ids or []
|
|
867
|
-
tool_names = []
|
|
868
|
-
if include_base_tools:
|
|
869
|
-
tool_names += BASE_TOOLS
|
|
870
|
-
if include_meta_memory_tools:
|
|
871
|
-
tool_names += META_MEMORY_TOOLS
|
|
872
|
-
tool_ids += [
|
|
873
|
-
self.server.tool_manager.get_tool_by_name(
|
|
874
|
-
tool_name=name,
|
|
875
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
876
|
-
).id
|
|
877
|
-
for name in tool_names
|
|
878
|
-
]
|
|
879
|
-
|
|
880
|
-
# check if default configs are provided
|
|
881
|
-
assert embedding_config or self._default_embedding_config, (
|
|
882
|
-
"Embedding config must be provided"
|
|
883
|
-
)
|
|
884
|
-
assert llm_config or self._default_llm_config, "LLM config must be provided"
|
|
885
|
-
|
|
886
|
-
# TODO: This should not happen here, we need to have clear separation between create/add blocks
|
|
887
|
-
for block in memory.get_blocks():
|
|
888
|
-
self.server.block_manager.create_or_update_block(
|
|
889
|
-
block, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
890
|
-
)
|
|
891
|
-
|
|
892
|
-
# Also get any existing block_ids passed in
|
|
893
|
-
block_ids = block_ids or []
|
|
894
|
-
|
|
895
|
-
# create agent
|
|
896
|
-
# Create the base parameters
|
|
897
|
-
create_params = {
|
|
898
|
-
"description": description,
|
|
899
|
-
"metadata_": metadata,
|
|
900
|
-
"memory_blocks": [],
|
|
901
|
-
"block_ids": [b.id for b in memory.get_blocks()] + block_ids,
|
|
902
|
-
"tool_ids": tool_ids,
|
|
903
|
-
"tool_rules": tool_rules,
|
|
904
|
-
"include_base_tools": include_base_tools,
|
|
905
|
-
"system": system,
|
|
906
|
-
"agent_type": agent_type,
|
|
907
|
-
"llm_config": llm_config if llm_config else self._default_llm_config,
|
|
908
|
-
"embedding_config": embedding_config
|
|
909
|
-
if embedding_config
|
|
910
|
-
else self._default_embedding_config,
|
|
911
|
-
"initial_message_sequence": initial_message_sequence,
|
|
912
|
-
"tags": tags,
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
# Only add name if it's not None
|
|
916
|
-
if name is not None:
|
|
917
|
-
create_params["name"] = name
|
|
918
|
-
|
|
919
|
-
agent_state = self.server.create_agent(
|
|
920
|
-
CreateAgent(**create_params),
|
|
921
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
922
|
-
)
|
|
923
|
-
|
|
924
|
-
# TODO: get full agent state
|
|
925
|
-
return self.server.agent_manager.get_agent_by_id(
|
|
926
|
-
agent_state.id, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
927
|
-
)
|
|
928
|
-
|
|
929
|
-
def create_user(self, user_id: str, user_name: str) -> PydanticUser:
|
|
930
|
-
return self.server.user_manager.create_user(UserCreate(id=user_id, name=user_name))
|
|
931
|
-
|
|
932
|
-
def create_meta_agent(self, config: dict):
|
|
933
|
-
"""Create a MetaAgent for memory management operations.
|
|
934
|
-
|
|
935
|
-
Args:
|
|
936
|
-
config (dict): Configuration dictionary for creating the MetaAgent.
|
|
937
|
-
Can include: name, agents, system_prompts_folder, system_prompts,
|
|
938
|
-
llm_config, embedding_config, memory_blocks, description.
|
|
939
|
-
|
|
940
|
-
Returns:
|
|
941
|
-
MetaAgent: The initialized MetaAgent instance
|
|
942
|
-
"""
|
|
943
|
-
# Create MetaAgent through server
|
|
944
|
-
return self.server.create_meta_agent(
|
|
945
|
-
request=CreateMetaAgent(**config),
|
|
946
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
947
|
-
)
|
|
948
|
-
|
|
949
|
-
def get_tools_from_agent(self, agent_id: str) -> List[Tool]:
|
|
950
|
-
"""
|
|
951
|
-
Get tools from an existing agent.
|
|
952
|
-
|
|
953
|
-
Args:
|
|
954
|
-
agent_id (str): ID of the agent
|
|
955
|
-
|
|
956
|
-
Returns:
|
|
957
|
-
List[Tool]: A list of Tool objs
|
|
958
|
-
"""
|
|
959
|
-
self.interface.clear()
|
|
960
|
-
return self.server.agent_manager.get_agent_by_id(
|
|
961
|
-
agent_id=agent_id,
|
|
962
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
963
|
-
).tools
|
|
964
|
-
|
|
965
|
-
def add_tool_to_agent(self, agent_id: str, tool_id: str):
|
|
966
|
-
"""
|
|
967
|
-
Add tool to an existing agent
|
|
968
|
-
|
|
969
|
-
Args:
|
|
970
|
-
agent_id (str): ID of the agent
|
|
971
|
-
tool_id (str): A tool id
|
|
972
|
-
|
|
973
|
-
Returns:
|
|
974
|
-
agent_state (AgentState): State of the updated agent
|
|
975
|
-
"""
|
|
976
|
-
self.interface.clear()
|
|
977
|
-
agent_state = self.server.agent_manager.attach_tool(
|
|
978
|
-
agent_id=agent_id,
|
|
979
|
-
tool_id=tool_id,
|
|
980
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
981
|
-
)
|
|
982
|
-
return agent_state
|
|
983
|
-
|
|
984
|
-
def remove_tool_from_agent(self, agent_id: str, tool_id: str):
|
|
985
|
-
"""
|
|
986
|
-
Removes tools from an existing agent
|
|
987
|
-
|
|
988
|
-
Args:
|
|
989
|
-
agent_id (str): ID of the agent
|
|
990
|
-
tool_id (str): The tool id
|
|
991
|
-
|
|
992
|
-
Returns:
|
|
993
|
-
agent_state (AgentState): State of the updated agent
|
|
994
|
-
"""
|
|
995
|
-
self.interface.clear()
|
|
996
|
-
agent_state = self.server.agent_manager.detach_tool(
|
|
997
|
-
agent_id=agent_id,
|
|
998
|
-
tool_id=tool_id,
|
|
999
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1000
|
-
)
|
|
1001
|
-
return agent_state
|
|
1002
|
-
|
|
1003
|
-
def rename_agent(self, agent_id: str, new_name: str):
|
|
1004
|
-
"""
|
|
1005
|
-
Rename an agent
|
|
1006
|
-
|
|
1007
|
-
Args:
|
|
1008
|
-
agent_id (str): ID of the agent
|
|
1009
|
-
new_name (str): New name for the agent
|
|
1010
|
-
"""
|
|
1011
|
-
self.update_agent(agent_id, name=new_name)
|
|
1012
|
-
|
|
1013
|
-
def delete_agent(self, agent_id: str):
|
|
1014
|
-
"""
|
|
1015
|
-
Delete an agent
|
|
1016
|
-
|
|
1017
|
-
Args:
|
|
1018
|
-
agent_id (str): ID of the agent to delete
|
|
1019
|
-
"""
|
|
1020
|
-
self.server.agent_manager.delete_agent(
|
|
1021
|
-
agent_id=agent_id,
|
|
1022
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1023
|
-
)
|
|
1024
|
-
|
|
1025
|
-
def get_agent_by_name(self, agent_name: str) -> AgentState:
|
|
1026
|
-
"""
|
|
1027
|
-
Get an agent by its name
|
|
1028
|
-
|
|
1029
|
-
Args:
|
|
1030
|
-
agent_name (str): Name of the agent
|
|
1031
|
-
|
|
1032
|
-
Returns:
|
|
1033
|
-
agent_state (AgentState): State of the agent
|
|
1034
|
-
"""
|
|
1035
|
-
self.interface.clear()
|
|
1036
|
-
return self.server.agent_manager.get_agent_by_name(
|
|
1037
|
-
agent_name=agent_name,
|
|
1038
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1039
|
-
)
|
|
1040
|
-
|
|
1041
|
-
def get_agent(self, agent_id: str) -> AgentState:
|
|
1042
|
-
"""
|
|
1043
|
-
Get an agent's state by its ID.
|
|
1044
|
-
|
|
1045
|
-
Args:
|
|
1046
|
-
agent_id (str): ID of the agent
|
|
1047
|
-
|
|
1048
|
-
Returns:
|
|
1049
|
-
agent_state (AgentState): State representation of the agent
|
|
1050
|
-
"""
|
|
1051
|
-
self.interface.clear()
|
|
1052
|
-
return self.server.agent_manager.get_agent_by_id(
|
|
1053
|
-
agent_id=agent_id,
|
|
1054
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1055
|
-
)
|
|
1056
|
-
|
|
1057
|
-
def get_agent_id(self, agent_name: str) -> Optional[str]:
|
|
1058
|
-
"""
|
|
1059
|
-
Get the ID of an agent by name (names are unique per user)
|
|
1060
|
-
|
|
1061
|
-
Args:
|
|
1062
|
-
agent_name (str): Name of the agent
|
|
1063
|
-
|
|
1064
|
-
Returns:
|
|
1065
|
-
agent_id (str): ID of the agent
|
|
1066
|
-
"""
|
|
1067
|
-
|
|
1068
|
-
self.interface.clear()
|
|
1069
|
-
assert agent_name, "Agent name must be provided"
|
|
1070
|
-
|
|
1071
|
-
# TODO: Refactor this futher to not have downstream users expect Optionals - this should just error
|
|
1072
|
-
try:
|
|
1073
|
-
return self.server.agent_manager.get_agent_by_name(
|
|
1074
|
-
agent_name=agent_name,
|
|
1075
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1076
|
-
).id
|
|
1077
|
-
except NoResultFound:
|
|
1078
|
-
return None
|
|
1079
|
-
|
|
1080
|
-
# memory
|
|
1081
|
-
def get_in_context_memory(self, agent_id: str) -> Memory:
|
|
1082
|
-
"""
|
|
1083
|
-
Get the in-context (i.e. core) memory of an agent
|
|
1084
|
-
|
|
1085
|
-
Args:
|
|
1086
|
-
agent_id (str): ID of the agent
|
|
1087
|
-
|
|
1088
|
-
Returns:
|
|
1089
|
-
memory (Memory): In-context memory of the agent
|
|
1090
|
-
"""
|
|
1091
|
-
memory = self.server.get_agent_memory(
|
|
1092
|
-
agent_id=agent_id,
|
|
1093
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1094
|
-
)
|
|
1095
|
-
return memory
|
|
1096
|
-
|
|
1097
|
-
def get_core_memory(self, agent_id: str) -> Memory:
|
|
1098
|
-
return self.get_in_context_memory(agent_id)
|
|
1099
|
-
|
|
1100
|
-
def update_in_context_memory(
|
|
1101
|
-
self, agent_id: str, section: str, value: Union[List[str], str]
|
|
1102
|
-
) -> Memory:
|
|
1103
|
-
"""
|
|
1104
|
-
Update the in-context memory of an agent
|
|
1105
|
-
|
|
1106
|
-
Args:
|
|
1107
|
-
agent_id (str): ID of the agent
|
|
1108
|
-
|
|
1109
|
-
Returns:
|
|
1110
|
-
memory (Memory): The updated in-context memory of the agent
|
|
1111
|
-
|
|
1112
|
-
"""
|
|
1113
|
-
# TODO: implement this (not sure what it should look like)
|
|
1114
|
-
memory = self.server.update_agent_core_memory(
|
|
1115
|
-
agent_id=agent_id,
|
|
1116
|
-
label=section,
|
|
1117
|
-
value=value,
|
|
1118
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1119
|
-
)
|
|
1120
|
-
return memory
|
|
1121
|
-
|
|
1122
|
-
def get_archival_memory_summary(self, agent_id: str) -> ArchivalMemorySummary:
|
|
1123
|
-
"""
|
|
1124
|
-
Get a summary of the archival memory of an agent
|
|
1125
|
-
|
|
1126
|
-
Args:
|
|
1127
|
-
agent_id (str): ID of the agent
|
|
1128
|
-
|
|
1129
|
-
Returns:
|
|
1130
|
-
summary (ArchivalMemorySummary): Summary of the archival memory
|
|
1131
|
-
|
|
1132
|
-
"""
|
|
1133
|
-
return self.server.get_archival_memory_summary(
|
|
1134
|
-
agent_id=agent_id,
|
|
1135
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1136
|
-
)
|
|
1137
|
-
|
|
1138
|
-
def get_recall_memory_summary(self, agent_id: str) -> RecallMemorySummary:
|
|
1139
|
-
"""
|
|
1140
|
-
Get a summary of the recall memory of an agent
|
|
1141
|
-
|
|
1142
|
-
Args:
|
|
1143
|
-
agent_id (str): ID of the agent
|
|
1144
|
-
|
|
1145
|
-
Returns:
|
|
1146
|
-
summary (RecallMemorySummary): Summary of the recall memory
|
|
1147
|
-
"""
|
|
1148
|
-
return self.server.get_recall_memory_summary(
|
|
1149
|
-
agent_id=agent_id,
|
|
1150
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1151
|
-
)
|
|
1152
|
-
|
|
1153
|
-
def get_in_context_messages(self, agent_id: str) -> List[Message]:
|
|
1154
|
-
"""
|
|
1155
|
-
Get in-context messages of an agent
|
|
1156
|
-
|
|
1157
|
-
Args:
|
|
1158
|
-
agent_id (str): ID of the agent
|
|
1159
|
-
|
|
1160
|
-
Returns:
|
|
1161
|
-
messages (List[Message]): List of in-context messages
|
|
1162
|
-
"""
|
|
1163
|
-
return self.server.agent_manager.get_in_context_messages(
|
|
1164
|
-
agent_id=agent_id,
|
|
1165
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1166
|
-
)
|
|
1167
|
-
|
|
1168
|
-
# agent interactions
|
|
1169
|
-
|
|
1170
|
-
def construct_system_message(
|
|
1171
|
-
self, agent_id: str, message: str, user_id: str
|
|
1172
|
-
) -> str:
|
|
1173
|
-
"""
|
|
1174
|
-
Construct a system message from a message.
|
|
1175
|
-
"""
|
|
1176
|
-
return self.server.construct_system_message(
|
|
1177
|
-
agent_id=agent_id,
|
|
1178
|
-
message=message,
|
|
1179
|
-
actor=self.server.user_manager.get_user_by_id(user_id),
|
|
1180
|
-
)
|
|
1181
|
-
|
|
1182
|
-
def extract_memory_for_system_prompt(
|
|
1183
|
-
self, agent_id: str, message: str, user_id: str
|
|
1184
|
-
) -> str:
|
|
1185
|
-
"""
|
|
1186
|
-
Extract memory for system prompt from a message.
|
|
1187
|
-
"""
|
|
1188
|
-
return self.server.extract_memory_for_system_prompt(
|
|
1189
|
-
agent_id=agent_id,
|
|
1190
|
-
message=message,
|
|
1191
|
-
actor=self.server.user_manager.get_user_by_id(user_id),
|
|
1192
|
-
)
|
|
1193
|
-
|
|
1194
|
-
def send_messages(
|
|
1195
|
-
self,
|
|
1196
|
-
agent_id: str,
|
|
1197
|
-
messages: List[Union[Message | MessageCreate]],
|
|
1198
|
-
):
|
|
1199
|
-
"""
|
|
1200
|
-
Send pre-packed messages to an agent.
|
|
1201
|
-
|
|
1202
|
-
Args:
|
|
1203
|
-
agent_id (str): ID of the agent
|
|
1204
|
-
messages (List[Union[Message | MessageCreate]]): List of messages to send
|
|
1205
|
-
|
|
1206
|
-
Returns:
|
|
1207
|
-
response (MirixResponse): Response from the agent
|
|
1208
|
-
"""
|
|
1209
|
-
self.interface.clear()
|
|
1210
|
-
usage = self.server.send_messages(
|
|
1211
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1212
|
-
agent_id=agent_id,
|
|
1213
|
-
input_messages=messages,
|
|
1214
|
-
)
|
|
1215
|
-
|
|
1216
|
-
# format messages
|
|
1217
|
-
return MirixResponse(messages=messages, usage=usage)
|
|
1218
|
-
|
|
1219
|
-
def send_message(
|
|
1220
|
-
self,
|
|
1221
|
-
message: str | list[dict],
|
|
1222
|
-
role: str,
|
|
1223
|
-
name: Optional[str] = None,
|
|
1224
|
-
agent_id: Optional[str] = None,
|
|
1225
|
-
agent_name: Optional[str] = None,
|
|
1226
|
-
stream_steps: bool = False,
|
|
1227
|
-
stream_tokens: bool = False,
|
|
1228
|
-
chaining: Optional[bool] = None,
|
|
1229
|
-
verbose: Optional[bool] = None,
|
|
1230
|
-
) -> MirixResponse:
|
|
1231
|
-
"""
|
|
1232
|
-
Send a message to an agent
|
|
1233
|
-
|
|
1234
|
-
Args:
|
|
1235
|
-
message (str): Message to send
|
|
1236
|
-
role (str): Role of the message
|
|
1237
|
-
agent_id (str): ID of the agent
|
|
1238
|
-
name(str): Name of the sender
|
|
1239
|
-
stream_steps (bool): Stream the steps (default: `False`)
|
|
1240
|
-
stream_tokens (bool): Stream the tokens (default: `False`)
|
|
1241
|
-
chaining (bool): Whether to enable chaining for this message
|
|
1242
|
-
verbose (bool): Whether to print verbose logging (default: `None`, which inherits from MIRIX_VERBOSE env var)
|
|
1243
|
-
|
|
1244
|
-
Returns:
|
|
1245
|
-
response (MirixResponse): Response from the agent
|
|
1246
|
-
"""
|
|
1247
|
-
|
|
1248
|
-
if not agent_id:
|
|
1249
|
-
# lookup agent by name
|
|
1250
|
-
assert agent_name, "Either agent_id or agent_name must be provided"
|
|
1251
|
-
agent_id = self.get_agent_id(agent_name=agent_name)
|
|
1252
|
-
assert agent_id, f"Agent with name {agent_name} not found"
|
|
1253
|
-
|
|
1254
|
-
if stream_steps or stream_tokens:
|
|
1255
|
-
# TODO: implement streaming with stream=True/False
|
|
1256
|
-
raise NotImplementedError
|
|
1257
|
-
self.interface.clear()
|
|
1258
|
-
|
|
1259
|
-
if isinstance(message, str):
|
|
1260
|
-
content = [TextContent(text=message)]
|
|
1261
|
-
input_messages = [
|
|
1262
|
-
MessageCreate(role=MessageRole(role), content=content, name=name)
|
|
1263
|
-
]
|
|
1264
|
-
elif isinstance(message, list):
|
|
1265
|
-
|
|
1266
|
-
def convert_message(m):
|
|
1267
|
-
if m["type"] == "text":
|
|
1268
|
-
return TextContent(**m)
|
|
1269
|
-
elif m["type"] == "image_url":
|
|
1270
|
-
url = m["image_url"]["url"]
|
|
1271
|
-
detail = m["image_url"].get("detail", "auto")
|
|
1272
|
-
|
|
1273
|
-
# Handle the image based on URL type
|
|
1274
|
-
if url.startswith("data:"):
|
|
1275
|
-
# Base64 encoded image - save locally
|
|
1276
|
-
file_metadata = self._save_image_from_base64(url, detail)
|
|
1277
|
-
else:
|
|
1278
|
-
# HTTP URL - just create FileMetadata without downloading
|
|
1279
|
-
file_metadata = self._create_file_metadata_from_url(url, detail)
|
|
1280
|
-
|
|
1281
|
-
return ImageContent(
|
|
1282
|
-
type=MessageContentType.image_url,
|
|
1283
|
-
image_id=file_metadata.id,
|
|
1284
|
-
detail=detail,
|
|
1285
|
-
)
|
|
1286
|
-
|
|
1287
|
-
elif m["type"] == "image_data":
|
|
1288
|
-
# Base64 image data (new format)
|
|
1289
|
-
data = m["image_data"]["data"]
|
|
1290
|
-
detail = m["image_data"].get("detail", "auto")
|
|
1291
|
-
|
|
1292
|
-
# Save the base64 image to file_manager
|
|
1293
|
-
file_metadata = self._save_image_from_base64(data, detail)
|
|
1294
|
-
|
|
1295
|
-
return ImageContent(
|
|
1296
|
-
type=MessageContentType.image_url,
|
|
1297
|
-
image_id=file_metadata.id,
|
|
1298
|
-
detail=detail,
|
|
1299
|
-
)
|
|
1300
|
-
elif m["type"] == "file_uri":
|
|
1301
|
-
# File URI (local file path)
|
|
1302
|
-
file_path = m["file_uri"]
|
|
1303
|
-
|
|
1304
|
-
# Check if it's an image or other file type
|
|
1305
|
-
file_type = self._determine_file_type(file_path)
|
|
1306
|
-
|
|
1307
|
-
if file_type.startswith("image/"):
|
|
1308
|
-
# Handle as image
|
|
1309
|
-
file_metadata = self._save_image_from_file_uri(file_path)
|
|
1310
|
-
return ImageContent(
|
|
1311
|
-
type=MessageContentType.image_url,
|
|
1312
|
-
image_id=file_metadata.id,
|
|
1313
|
-
detail="auto",
|
|
1314
|
-
)
|
|
1315
|
-
else:
|
|
1316
|
-
# Handle as general file (e.g., PDF, DOC, etc.)
|
|
1317
|
-
file_metadata = self._save_file_from_path(file_path)
|
|
1318
|
-
return FileContent(
|
|
1319
|
-
type=MessageContentType.file_uri, file_id=file_metadata.id
|
|
1320
|
-
)
|
|
1321
|
-
|
|
1322
|
-
elif m["type"] == "google_cloud_file_uri":
|
|
1323
|
-
# Google Cloud file URI
|
|
1324
|
-
# Handle both the typo version and the correct version from the test file
|
|
1325
|
-
file_uri = m.get("google_cloud_file_uri") or m.get("file_uri")
|
|
1326
|
-
|
|
1327
|
-
file_metadata = self._save_image_from_google_cloud_uri(file_uri)
|
|
1328
|
-
return CloudFileContent(
|
|
1329
|
-
type=MessageContentType.google_cloud_file_uri,
|
|
1330
|
-
cloud_file_uri=file_metadata.id,
|
|
1331
|
-
)
|
|
1332
|
-
|
|
1333
|
-
elif m["type"] == "database_image_id":
|
|
1334
|
-
return ImageContent(
|
|
1335
|
-
type=MessageContentType.image_url,
|
|
1336
|
-
image_id=m["image_id"],
|
|
1337
|
-
detail="auto",
|
|
1338
|
-
)
|
|
1339
|
-
|
|
1340
|
-
elif m["type"] == "database_file_id":
|
|
1341
|
-
return FileContent(
|
|
1342
|
-
type=MessageContentType.file_uri,
|
|
1343
|
-
file_id=m["file_id"],
|
|
1344
|
-
)
|
|
1345
|
-
|
|
1346
|
-
elif m["type"] == "database_google_cloud_file_uri":
|
|
1347
|
-
return CloudFileContent(
|
|
1348
|
-
type=MessageContentType.google_cloud_file_uri,
|
|
1349
|
-
cloud_file_uri=m["cloud_file_uri"],
|
|
1350
|
-
)
|
|
1351
|
-
|
|
1352
|
-
else:
|
|
1353
|
-
raise ValueError(f"Unknown message type: {m['type']}")
|
|
1354
|
-
|
|
1355
|
-
content = [convert_message(m) for m in message]
|
|
1356
|
-
input_messages = [
|
|
1357
|
-
MessageCreate(role=MessageRole(role), content=content, name=name)
|
|
1358
|
-
]
|
|
1359
|
-
if extra_messages is not None:
|
|
1360
|
-
extra_messages = [
|
|
1361
|
-
MessageCreate(
|
|
1362
|
-
role=MessageRole(role),
|
|
1363
|
-
content=[convert_message(m) for m in extra_messages],
|
|
1364
|
-
name=name,
|
|
1365
|
-
)
|
|
1366
|
-
]
|
|
1367
|
-
|
|
1368
|
-
else:
|
|
1369
|
-
raise ValueError(f"Invalid message type: {type(message)}")
|
|
1370
|
-
|
|
1371
|
-
usage = self.server.send_messages(
|
|
1372
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1373
|
-
agent_id=agent_id,
|
|
1374
|
-
input_messages=input_messages,
|
|
1375
|
-
chaining=chaining,
|
|
1376
|
-
verbose=verbose,
|
|
1377
|
-
)
|
|
1378
|
-
|
|
1379
|
-
# format messages
|
|
1380
|
-
messages = self.interface.to_list()
|
|
1381
|
-
|
|
1382
|
-
mirix_messages = []
|
|
1383
|
-
for m in messages:
|
|
1384
|
-
mirix_messages += m.to_mirix_message()
|
|
1385
|
-
|
|
1386
|
-
return MirixResponse(messages=mirix_messages, usage=usage)
|
|
1387
|
-
|
|
1388
|
-
def user_message(self, agent_id: str, message: str) -> MirixResponse:
|
|
1389
|
-
"""
|
|
1390
|
-
Send a message to an agent as a user
|
|
1391
|
-
|
|
1392
|
-
Args:
|
|
1393
|
-
agent_id (str): ID of the agent
|
|
1394
|
-
message (str): Message to send
|
|
1395
|
-
|
|
1396
|
-
Returns:
|
|
1397
|
-
response (MirixResponse): Response from the agent
|
|
1398
|
-
"""
|
|
1399
|
-
self.interface.clear()
|
|
1400
|
-
return self.send_message(role="user", agent_id=agent_id, message=message)
|
|
1401
|
-
|
|
1402
|
-
def run_command(self, agent_id: str, command: str) -> MirixResponse:
|
|
1403
|
-
"""
|
|
1404
|
-
Run a command on the agent
|
|
1405
|
-
|
|
1406
|
-
Args:
|
|
1407
|
-
agent_id (str): The agent ID
|
|
1408
|
-
command (str): The command to run
|
|
1409
|
-
|
|
1410
|
-
Returns:
|
|
1411
|
-
MirixResponse: The response from the agent
|
|
1412
|
-
|
|
1413
|
-
"""
|
|
1414
|
-
self.interface.clear()
|
|
1415
|
-
usage = self.server.run_command(
|
|
1416
|
-
user_id=self.user_id, agent_id=agent_id, command=command
|
|
1417
|
-
)
|
|
1418
|
-
|
|
1419
|
-
# NOTE: messages/usage may be empty, depending on the command
|
|
1420
|
-
return MirixResponse(messages=self.interface.to_list(), usage=usage)
|
|
1421
|
-
|
|
1422
|
-
# archival memory
|
|
1423
|
-
|
|
1424
|
-
# humans / personas
|
|
1425
|
-
|
|
1426
|
-
def get_block_id(self, name: str, label: str) -> str:
|
|
1427
|
-
block = self.server.block_manager.get_blocks(
|
|
1428
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1429
|
-
label=label,
|
|
1430
|
-
)
|
|
1431
|
-
if not block:
|
|
1432
|
-
return None
|
|
1433
|
-
return block[0].id
|
|
1434
|
-
|
|
1435
|
-
def create_human(self, name: str, text: str):
|
|
1436
|
-
"""
|
|
1437
|
-
Create a human block template (saved human string to pre-fill `ChatMemory`)
|
|
1438
|
-
|
|
1439
|
-
Args:
|
|
1440
|
-
name (str): Name of the human block
|
|
1441
|
-
text (str): Text of the human block
|
|
1442
|
-
|
|
1443
|
-
Returns:
|
|
1444
|
-
human (Human): Human block
|
|
1445
|
-
"""
|
|
1446
|
-
return self.server.block_manager.create_or_update_block(
|
|
1447
|
-
Human(value=text),
|
|
1448
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1449
|
-
)
|
|
1450
|
-
|
|
1451
|
-
def create_persona(self, name: str, text: str):
|
|
1452
|
-
"""
|
|
1453
|
-
Create a persona block template (saved persona string to pre-fill `ChatMemory`)
|
|
1454
|
-
|
|
1455
|
-
Args:
|
|
1456
|
-
name (str): Name of the persona block
|
|
1457
|
-
text (str): Text of the persona block
|
|
1458
|
-
|
|
1459
|
-
Returns:
|
|
1460
|
-
persona (Persona): Persona block
|
|
1461
|
-
"""
|
|
1462
|
-
return self.server.block_manager.create_or_update_block(
|
|
1463
|
-
Persona(value=text),
|
|
1464
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1465
|
-
)
|
|
1466
|
-
|
|
1467
|
-
def list_humans(self):
|
|
1468
|
-
"""
|
|
1469
|
-
List available human block templates
|
|
1470
|
-
|
|
1471
|
-
Returns:
|
|
1472
|
-
humans (List[Human]): List of human blocks
|
|
1473
|
-
"""
|
|
1474
|
-
return self.server.block_manager.get_blocks(
|
|
1475
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1476
|
-
label="human",
|
|
1477
|
-
)
|
|
1478
|
-
|
|
1479
|
-
def list_personas(self) -> List[Persona]:
|
|
1480
|
-
"""
|
|
1481
|
-
List available persona block templates
|
|
1482
|
-
|
|
1483
|
-
Returns:
|
|
1484
|
-
personas (List[Persona]): List of persona blocks
|
|
1485
|
-
"""
|
|
1486
|
-
return self.server.block_manager.get_blocks(
|
|
1487
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1488
|
-
label="persona",
|
|
1489
|
-
)
|
|
1490
|
-
|
|
1491
|
-
def update_human(self, human_id: str, text: str):
|
|
1492
|
-
"""
|
|
1493
|
-
Update a human block template
|
|
1494
|
-
|
|
1495
|
-
Args:
|
|
1496
|
-
human_id (str): ID of the human block
|
|
1497
|
-
text (str): Text of the human block
|
|
1498
|
-
|
|
1499
|
-
Returns:
|
|
1500
|
-
human (Human): Updated human block
|
|
1501
|
-
"""
|
|
1502
|
-
|
|
1503
|
-
return self.server.block_manager.update_block(
|
|
1504
|
-
block_id=human_id,
|
|
1505
|
-
block_update=BlockUpdate(value=text),
|
|
1506
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1507
|
-
)
|
|
1508
|
-
|
|
1509
|
-
def update_persona(self, persona_id: str, text: str):
|
|
1510
|
-
"""
|
|
1511
|
-
Update a persona block template
|
|
1512
|
-
|
|
1513
|
-
Args:
|
|
1514
|
-
persona_id (str): ID of the persona block
|
|
1515
|
-
text (str): Text of the persona block
|
|
1516
|
-
|
|
1517
|
-
Returns:
|
|
1518
|
-
persona (Persona): Updated persona block
|
|
1519
|
-
"""
|
|
1520
|
-
blocks = self.server.block_manager.get_blocks(self.user)
|
|
1521
|
-
persona_block = [block for block in blocks if block.label == "persona"][0]
|
|
1522
|
-
return self.server.block_manager.update_block(
|
|
1523
|
-
block_id=persona_block.id,
|
|
1524
|
-
block_update=BlockUpdate(value=text),
|
|
1525
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1526
|
-
)
|
|
1527
|
-
|
|
1528
|
-
def update_persona_text(self, persona_name: str, text: str):
|
|
1529
|
-
"""
|
|
1530
|
-
Update a persona block template by template name
|
|
1531
|
-
|
|
1532
|
-
Args:
|
|
1533
|
-
persona_name (str): Name of the persona template
|
|
1534
|
-
text (str): Text of the persona block
|
|
1535
|
-
|
|
1536
|
-
Returns:
|
|
1537
|
-
persona (Persona): Updated persona block
|
|
1538
|
-
"""
|
|
1539
|
-
persona_id = self.get_persona_id(persona_name)
|
|
1540
|
-
if persona_id:
|
|
1541
|
-
# Update existing persona
|
|
1542
|
-
return self.server.block_manager.update_block(
|
|
1543
|
-
block_id=persona_id,
|
|
1544
|
-
block_update=BlockUpdate(value=text),
|
|
1545
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1546
|
-
)
|
|
1547
|
-
else:
|
|
1548
|
-
# Create new persona if it doesn't exist
|
|
1549
|
-
return self.create_persona(persona_name, text)
|
|
1550
|
-
|
|
1551
|
-
def get_persona(self, id: str) -> Persona:
|
|
1552
|
-
"""
|
|
1553
|
-
Get a persona block template
|
|
1554
|
-
|
|
1555
|
-
Args:
|
|
1556
|
-
id (str): ID of the persona block
|
|
1557
|
-
|
|
1558
|
-
Returns:
|
|
1559
|
-
persona (Persona): Persona block
|
|
1560
|
-
"""
|
|
1561
|
-
assert id, "Persona ID must be provided"
|
|
1562
|
-
return Persona(
|
|
1563
|
-
**self.server.block_manager.get_block_by_id(
|
|
1564
|
-
id, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1565
|
-
).model_dump()
|
|
1566
|
-
)
|
|
1567
|
-
|
|
1568
|
-
def get_human(self, id: str) -> Human:
|
|
1569
|
-
"""
|
|
1570
|
-
Get a human block template
|
|
1571
|
-
|
|
1572
|
-
Args:
|
|
1573
|
-
id (str): ID of the human block
|
|
1574
|
-
|
|
1575
|
-
Returns:
|
|
1576
|
-
human (Human): Human block
|
|
1577
|
-
"""
|
|
1578
|
-
assert id, "Human ID must be provided"
|
|
1579
|
-
return Human(
|
|
1580
|
-
**self.server.block_manager.get_block_by_id(
|
|
1581
|
-
id, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1582
|
-
).model_dump()
|
|
1583
|
-
)
|
|
1584
|
-
|
|
1585
|
-
def get_persona_id(self, name: str) -> str:
|
|
1586
|
-
"""
|
|
1587
|
-
Get the ID of a persona block template
|
|
1588
|
-
|
|
1589
|
-
Args:
|
|
1590
|
-
name (str): Name of the persona block
|
|
1591
|
-
|
|
1592
|
-
Returns:
|
|
1593
|
-
id (str): ID of the persona block
|
|
1594
|
-
"""
|
|
1595
|
-
persona = self.server.block_manager.get_blocks(
|
|
1596
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1597
|
-
label="persona",
|
|
1598
|
-
)
|
|
1599
|
-
if not persona:
|
|
1600
|
-
return None
|
|
1601
|
-
return persona[0].id
|
|
1602
|
-
|
|
1603
|
-
def get_human_id(self, name: str) -> str:
|
|
1604
|
-
"""
|
|
1605
|
-
Get the ID of a human block template
|
|
1606
|
-
|
|
1607
|
-
Args:
|
|
1608
|
-
name (str): Name of the human block
|
|
1609
|
-
|
|
1610
|
-
Returns:
|
|
1611
|
-
id (str): ID of the human block
|
|
1612
|
-
"""
|
|
1613
|
-
human = self.server.block_manager.get_blocks(
|
|
1614
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1615
|
-
label="human",
|
|
1616
|
-
)
|
|
1617
|
-
if not human:
|
|
1618
|
-
return None
|
|
1619
|
-
return human[0].id
|
|
1620
|
-
|
|
1621
|
-
def delete_persona(self, id: str):
|
|
1622
|
-
"""
|
|
1623
|
-
Delete a persona block template
|
|
1624
|
-
|
|
1625
|
-
Args:
|
|
1626
|
-
id (str): ID of the persona block
|
|
1627
|
-
"""
|
|
1628
|
-
self.delete_block(id)
|
|
1629
|
-
|
|
1630
|
-
def delete_human(self, id: str):
|
|
1631
|
-
"""
|
|
1632
|
-
Delete a human block template
|
|
1633
|
-
|
|
1634
|
-
Args:
|
|
1635
|
-
id (str): ID of the human block
|
|
1636
|
-
"""
|
|
1637
|
-
self.delete_block(id)
|
|
1638
|
-
|
|
1639
|
-
# tools
|
|
1640
|
-
def load_langchain_tool(
|
|
1641
|
-
self,
|
|
1642
|
-
langchain_tool: "LangChainBaseTool",
|
|
1643
|
-
additional_imports_module_attr_map: dict[str, str] = None,
|
|
1644
|
-
) -> Tool:
|
|
1645
|
-
tool_create = ToolCreate.from_langchain(
|
|
1646
|
-
langchain_tool=langchain_tool,
|
|
1647
|
-
additional_imports_module_attr_map=additional_imports_module_attr_map,
|
|
1648
|
-
)
|
|
1649
|
-
return self.server.tool_manager.create_or_update_tool(
|
|
1650
|
-
pydantic_tool=Tool(**tool_create.model_dump()),
|
|
1651
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1652
|
-
)
|
|
1653
|
-
|
|
1654
|
-
def load_crewai_tool(
|
|
1655
|
-
self,
|
|
1656
|
-
crewai_tool: "CrewAIBaseTool",
|
|
1657
|
-
additional_imports_module_attr_map: dict[str, str] = None,
|
|
1658
|
-
) -> Tool:
|
|
1659
|
-
tool_create = ToolCreate.from_crewai(
|
|
1660
|
-
crewai_tool=crewai_tool,
|
|
1661
|
-
additional_imports_module_attr_map=additional_imports_module_attr_map,
|
|
1662
|
-
)
|
|
1663
|
-
return self.server.tool_manager.create_or_update_tool(
|
|
1664
|
-
pydantic_tool=Tool(**tool_create.model_dump()),
|
|
1665
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1666
|
-
)
|
|
1667
|
-
|
|
1668
|
-
def load_composio_tool(self, action: "ActionType") -> Tool:
|
|
1669
|
-
tool_create = ToolCreate.from_composio(action_name=action.name)
|
|
1670
|
-
return self.server.tool_manager.create_or_update_tool(
|
|
1671
|
-
pydantic_tool=Tool(**tool_create.model_dump()),
|
|
1672
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1673
|
-
)
|
|
1674
|
-
|
|
1675
|
-
def create_tool(
|
|
1676
|
-
self,
|
|
1677
|
-
func,
|
|
1678
|
-
name: Optional[str] = None,
|
|
1679
|
-
tags: Optional[List[str]] = None,
|
|
1680
|
-
description: Optional[str] = None,
|
|
1681
|
-
return_char_limit: int = FUNCTION_RETURN_CHAR_LIMIT,
|
|
1682
|
-
) -> Tool:
|
|
1683
|
-
"""
|
|
1684
|
-
Create a tool. This stores the source code of function on the server, so that the server can execute the function and generate an OpenAI JSON schemas for it when using with an agent.
|
|
1685
|
-
|
|
1686
|
-
Args:
|
|
1687
|
-
func (callable): The function to create a tool for.
|
|
1688
|
-
name: (str): Name of the tool (must be unique per-user.)
|
|
1689
|
-
tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
|
|
1690
|
-
description (str, optional): The description.
|
|
1691
|
-
return_char_limit (int): The character limit for the tool's return value. Defaults to FUNCTION_RETURN_CHAR_LIMIT.
|
|
1692
|
-
|
|
1693
|
-
Returns:
|
|
1694
|
-
tool (Tool): The created tool.
|
|
1695
|
-
"""
|
|
1696
|
-
# TODO: check if tool already exists
|
|
1697
|
-
# TODO: how to load modules?
|
|
1698
|
-
# parse source code/schema
|
|
1699
|
-
source_code = parse_source_code(func)
|
|
1700
|
-
source_type = "python"
|
|
1701
|
-
if not tags:
|
|
1702
|
-
tags = []
|
|
1703
|
-
|
|
1704
|
-
# call server function
|
|
1705
|
-
return self.server.tool_manager.create_tool(
|
|
1706
|
-
Tool(
|
|
1707
|
-
source_type=source_type,
|
|
1708
|
-
source_code=source_code,
|
|
1709
|
-
name=name,
|
|
1710
|
-
tags=tags,
|
|
1711
|
-
description=description,
|
|
1712
|
-
return_char_limit=return_char_limit,
|
|
1713
|
-
),
|
|
1714
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1715
|
-
)
|
|
1716
|
-
|
|
1717
|
-
def create_or_update_tool(
|
|
1718
|
-
self,
|
|
1719
|
-
func,
|
|
1720
|
-
name: Optional[str] = None,
|
|
1721
|
-
tags: Optional[List[str]] = None,
|
|
1722
|
-
description: Optional[str] = None,
|
|
1723
|
-
return_char_limit: int = FUNCTION_RETURN_CHAR_LIMIT,
|
|
1724
|
-
) -> Tool:
|
|
1725
|
-
"""
|
|
1726
|
-
Creates or updates a tool. This stores the source code of function on the server, so that the server can execute the function and generate an OpenAI JSON schemas for it when using with an agent.
|
|
1727
|
-
|
|
1728
|
-
Args:
|
|
1729
|
-
func (callable): The function to create a tool for.
|
|
1730
|
-
name: (str): Name of the tool (must be unique per-user.)
|
|
1731
|
-
tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
|
|
1732
|
-
description (str, optional): The description.
|
|
1733
|
-
return_char_limit (int): The character limit for the tool's return value. Defaults to FUNCTION_RETURN_CHAR_LIMIT.
|
|
1734
|
-
|
|
1735
|
-
Returns:
|
|
1736
|
-
tool (Tool): The created tool.
|
|
1737
|
-
"""
|
|
1738
|
-
source_code = parse_source_code(func)
|
|
1739
|
-
source_type = "python"
|
|
1740
|
-
if not tags:
|
|
1741
|
-
tags = []
|
|
1742
|
-
|
|
1743
|
-
# call server function
|
|
1744
|
-
return self.server.tool_manager.create_or_update_tool(
|
|
1745
|
-
Tool(
|
|
1746
|
-
source_type=source_type,
|
|
1747
|
-
source_code=source_code,
|
|
1748
|
-
name=name,
|
|
1749
|
-
tags=tags,
|
|
1750
|
-
description=description,
|
|
1751
|
-
return_char_limit=return_char_limit,
|
|
1752
|
-
),
|
|
1753
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1754
|
-
)
|
|
1755
|
-
|
|
1756
|
-
def update_tool(
|
|
1757
|
-
self,
|
|
1758
|
-
id: str,
|
|
1759
|
-
name: Optional[str] = None,
|
|
1760
|
-
description: Optional[str] = None,
|
|
1761
|
-
func: Optional[callable] = None,
|
|
1762
|
-
tags: Optional[List[str]] = None,
|
|
1763
|
-
return_char_limit: int = FUNCTION_RETURN_CHAR_LIMIT,
|
|
1764
|
-
) -> Tool:
|
|
1765
|
-
"""
|
|
1766
|
-
Update a tool with provided parameters (name, func, tags)
|
|
1767
|
-
|
|
1768
|
-
Args:
|
|
1769
|
-
id (str): ID of the tool
|
|
1770
|
-
name (str): Name of the tool
|
|
1771
|
-
func (callable): Function to wrap in a tool
|
|
1772
|
-
tags (List[str]): Tags for the tool
|
|
1773
|
-
return_char_limit (int): The character limit for the tool's return value. Defaults to FUNCTION_RETURN_CHAR_LIMIT.
|
|
1774
|
-
|
|
1775
|
-
Returns:
|
|
1776
|
-
tool (Tool): Updated tool
|
|
1777
|
-
"""
|
|
1778
|
-
update_data = {
|
|
1779
|
-
"source_type": "python", # Always include source_type
|
|
1780
|
-
"source_code": parse_source_code(func) if func else None,
|
|
1781
|
-
"tags": tags,
|
|
1782
|
-
"name": name,
|
|
1783
|
-
"description": description,
|
|
1784
|
-
"return_char_limit": return_char_limit,
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
# Filter out any None values from the dictionary
|
|
1788
|
-
update_data = {
|
|
1789
|
-
key: value for key, value in update_data.items() if value is not None
|
|
1790
|
-
}
|
|
1791
|
-
|
|
1792
|
-
return self.server.tool_manager.update_tool_by_id(
|
|
1793
|
-
tool_id=id,
|
|
1794
|
-
tool_update=ToolUpdate(**update_data),
|
|
1795
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1796
|
-
)
|
|
1797
|
-
|
|
1798
|
-
def list_tools(
|
|
1799
|
-
self, cursor: Optional[str] = None, limit: Optional[int] = 50
|
|
1800
|
-
) -> List[Tool]:
|
|
1801
|
-
"""
|
|
1802
|
-
List available tools for the user.
|
|
1803
|
-
|
|
1804
|
-
Returns:
|
|
1805
|
-
tools (List[Tool]): List of tools
|
|
1806
|
-
"""
|
|
1807
|
-
return self.server.tool_manager.list_tools(
|
|
1808
|
-
cursor=cursor,
|
|
1809
|
-
limit=limit,
|
|
1810
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1811
|
-
)
|
|
1812
|
-
|
|
1813
|
-
def get_tool(self, id: str) -> Optional[Tool]:
|
|
1814
|
-
"""
|
|
1815
|
-
Get a tool given its ID.
|
|
1816
|
-
|
|
1817
|
-
Args:
|
|
1818
|
-
id (str): ID of the tool
|
|
1819
|
-
|
|
1820
|
-
Returns:
|
|
1821
|
-
tool (Tool): Tool
|
|
1822
|
-
"""
|
|
1823
|
-
return self.server.tool_manager.get_tool_by_id(
|
|
1824
|
-
id, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1825
|
-
)
|
|
1826
|
-
|
|
1827
|
-
def delete_tool(self, id: str):
|
|
1828
|
-
"""
|
|
1829
|
-
Delete a tool given the ID.
|
|
1830
|
-
|
|
1831
|
-
Args:
|
|
1832
|
-
id (str): ID of the tool
|
|
1833
|
-
"""
|
|
1834
|
-
return self.server.tool_manager.delete_tool_by_id(
|
|
1835
|
-
id, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1836
|
-
)
|
|
1837
|
-
|
|
1838
|
-
def get_tool_id(self, name: str) -> Optional[str]:
|
|
1839
|
-
"""
|
|
1840
|
-
Get the ID of a tool from its name. The client will use the org_id it is configured with.
|
|
1841
|
-
|
|
1842
|
-
Args:
|
|
1843
|
-
name (str): Name of the tool
|
|
1844
|
-
|
|
1845
|
-
Returns:
|
|
1846
|
-
id (str): ID of the tool (`None` if not found)
|
|
1847
|
-
"""
|
|
1848
|
-
tool = self.server.tool_manager.get_tool_by_name(
|
|
1849
|
-
tool_name=name, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1850
|
-
)
|
|
1851
|
-
return tool.id if tool else None
|
|
1852
|
-
|
|
1853
|
-
# recall memory
|
|
1854
|
-
|
|
1855
|
-
def get_messages(
|
|
1856
|
-
self, agent_id: str, cursor: Optional[str] = None, limit: Optional[int] = 1000
|
|
1857
|
-
) -> List[Message]:
|
|
1858
|
-
"""
|
|
1859
|
-
Get messages from an agent with pagination.
|
|
1860
|
-
|
|
1861
|
-
Args:
|
|
1862
|
-
agent_id (str): ID of the agent
|
|
1863
|
-
cursor (str): Get messages after a certain time
|
|
1864
|
-
limit (int): Limit number of messages
|
|
1865
|
-
|
|
1866
|
-
Returns:
|
|
1867
|
-
messages (List[Message]): List of messages
|
|
1868
|
-
"""
|
|
1869
|
-
|
|
1870
|
-
self.interface.clear()
|
|
1871
|
-
return self.server.get_agent_recall_cursor(
|
|
1872
|
-
user_id=self.user_id,
|
|
1873
|
-
agent_id=agent_id,
|
|
1874
|
-
before=cursor,
|
|
1875
|
-
limit=limit,
|
|
1876
|
-
reverse=True,
|
|
1877
|
-
)
|
|
1878
|
-
|
|
1879
|
-
def list_blocks(
|
|
1880
|
-
self, label: Optional[str] = None, templates_only: Optional[bool] = True
|
|
1881
|
-
) -> List[Block]:
|
|
1882
|
-
"""
|
|
1883
|
-
List available blocks
|
|
1884
|
-
|
|
1885
|
-
Args:
|
|
1886
|
-
label (str): Label of the block
|
|
1887
|
-
templates_only (bool): List only templates
|
|
1888
|
-
|
|
1889
|
-
Returns:
|
|
1890
|
-
blocks (List[Block]): List of blocks
|
|
1891
|
-
"""
|
|
1892
|
-
blocks = self.server.block_manager.get_blocks(
|
|
1893
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
1894
|
-
label=label,
|
|
1895
|
-
)
|
|
1896
|
-
return blocks
|
|
1897
|
-
|
|
1898
|
-
def create_block(
|
|
1899
|
-
self,
|
|
1900
|
-
label: str,
|
|
1901
|
-
value: str,
|
|
1902
|
-
limit: Optional[int] = None,
|
|
1903
|
-
) -> Block: #
|
|
1904
|
-
"""
|
|
1905
|
-
Create a block
|
|
1906
|
-
|
|
1907
|
-
Args:
|
|
1908
|
-
label (str): Label of the block
|
|
1909
|
-
text (str): Text of the block
|
|
1910
|
-
limit (int): Character of the block
|
|
1911
|
-
|
|
1912
|
-
Returns:
|
|
1913
|
-
block (Block): Created block
|
|
1914
|
-
"""
|
|
1915
|
-
block = Block(
|
|
1916
|
-
label=label,
|
|
1917
|
-
value=value,
|
|
1918
|
-
limit=limit,
|
|
1919
|
-
)
|
|
1920
|
-
# if limit:
|
|
1921
|
-
# block.limit = limit
|
|
1922
|
-
return self.server.block_manager.create_or_update_block(
|
|
1923
|
-
block, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1924
|
-
)
|
|
1925
|
-
|
|
1926
|
-
def get_block(self, block_id: str) -> Block:
|
|
1927
|
-
"""
|
|
1928
|
-
Get a block
|
|
1929
|
-
|
|
1930
|
-
Args:
|
|
1931
|
-
block_id (str): ID of the block
|
|
1932
|
-
|
|
1933
|
-
Returns:
|
|
1934
|
-
block (Block): Block
|
|
1935
|
-
"""
|
|
1936
|
-
return self.server.block_manager.get_block_by_id(
|
|
1937
|
-
block_id, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1938
|
-
)
|
|
1939
|
-
|
|
1940
|
-
def delete_block(self, id: str) -> Block:
|
|
1941
|
-
"""
|
|
1942
|
-
Delete a block
|
|
1943
|
-
|
|
1944
|
-
Args:
|
|
1945
|
-
id (str): ID of the block
|
|
1946
|
-
|
|
1947
|
-
Returns:
|
|
1948
|
-
block (Block): Deleted block
|
|
1949
|
-
"""
|
|
1950
|
-
return self.server.block_manager.delete_block(
|
|
1951
|
-
id, actor=self.server.user_manager.get_user_by_id(self.user.id)
|
|
1952
|
-
)
|
|
1953
|
-
|
|
1954
|
-
def set_default_llm_config(self, llm_config: LLMConfig):
|
|
1955
|
-
"""
|
|
1956
|
-
Set the default LLM configuration for agents.
|
|
1957
|
-
|
|
1958
|
-
Args:
|
|
1959
|
-
llm_config (LLMConfig): LLM configuration
|
|
1960
|
-
"""
|
|
1961
|
-
self._default_llm_config = llm_config
|
|
1962
|
-
|
|
1963
|
-
def set_default_embedding_config(self, embedding_config: EmbeddingConfig):
|
|
1964
|
-
"""
|
|
1965
|
-
Set the default embedding configuration for agents.
|
|
1966
|
-
|
|
1967
|
-
Args:
|
|
1968
|
-
embedding_config (EmbeddingConfig): Embedding configuration
|
|
1969
|
-
"""
|
|
1970
|
-
self._default_embedding_config = embedding_config
|
|
1971
|
-
|
|
1972
|
-
def list_llm_configs(self) -> List[LLMConfig]:
|
|
1973
|
-
"""
|
|
1974
|
-
List available LLM configurations
|
|
1975
|
-
|
|
1976
|
-
Returns:
|
|
1977
|
-
configs (List[LLMConfig]): List of LLM configurations
|
|
1978
|
-
"""
|
|
1979
|
-
return self.server.list_llm_models()
|
|
1980
|
-
|
|
1981
|
-
def list_embedding_configs(self) -> List[EmbeddingConfig]:
|
|
1982
|
-
"""
|
|
1983
|
-
List available embedding configurations
|
|
1984
|
-
|
|
1985
|
-
Returns:
|
|
1986
|
-
configs (List[EmbeddingConfig]): List of embedding configurations
|
|
1987
|
-
"""
|
|
1988
|
-
return self.server.list_embedding_models()
|
|
1989
|
-
|
|
1990
|
-
def create_org(self, name: Optional[str] = None) -> Organization:
|
|
1991
|
-
return self.server.organization_manager.create_organization(
|
|
1992
|
-
pydantic_org=Organization(name=name)
|
|
1993
|
-
)
|
|
1994
|
-
|
|
1995
|
-
def list_orgs(
|
|
1996
|
-
self, cursor: Optional[str] = None, limit: Optional[int] = 50
|
|
1997
|
-
) -> List[Organization]:
|
|
1998
|
-
return self.server.organization_manager.list_organizations(
|
|
1999
|
-
cursor=cursor, limit=limit
|
|
2000
|
-
)
|
|
2001
|
-
|
|
2002
|
-
def delete_org(self, org_id: str) -> Organization:
|
|
2003
|
-
return self.server.organization_manager.delete_organization_by_id(org_id=org_id)
|
|
2004
|
-
|
|
2005
|
-
def create_sandbox_config(
|
|
2006
|
-
self, config: Union[LocalSandboxConfig, E2BSandboxConfig]
|
|
2007
|
-
) -> SandboxConfig:
|
|
2008
|
-
"""
|
|
2009
|
-
Create a new sandbox configuration.
|
|
2010
|
-
"""
|
|
2011
|
-
config_create = SandboxConfigCreate(config=config)
|
|
2012
|
-
return self.server.sandbox_config_manager.create_or_update_sandbox_config(
|
|
2013
|
-
sandbox_config_create=config_create,
|
|
2014
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2015
|
-
)
|
|
2016
|
-
|
|
2017
|
-
def update_sandbox_config(
|
|
2018
|
-
self,
|
|
2019
|
-
sandbox_config_id: str,
|
|
2020
|
-
config: Union[LocalSandboxConfig, E2BSandboxConfig],
|
|
2021
|
-
) -> SandboxConfig:
|
|
2022
|
-
"""
|
|
2023
|
-
Update an existing sandbox configuration.
|
|
2024
|
-
"""
|
|
2025
|
-
sandbox_update = SandboxConfigUpdate(config=config)
|
|
2026
|
-
return self.server.sandbox_config_manager.update_sandbox_config(
|
|
2027
|
-
sandbox_config_id=sandbox_config_id,
|
|
2028
|
-
sandbox_update=sandbox_update,
|
|
2029
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2030
|
-
)
|
|
2031
|
-
|
|
2032
|
-
def delete_sandbox_config(self, sandbox_config_id: str) -> None:
|
|
2033
|
-
"""
|
|
2034
|
-
Delete a sandbox configuration.
|
|
2035
|
-
"""
|
|
2036
|
-
return self.server.sandbox_config_manager.delete_sandbox_config(
|
|
2037
|
-
sandbox_config_id=sandbox_config_id,
|
|
2038
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2039
|
-
)
|
|
2040
|
-
|
|
2041
|
-
def list_sandbox_configs(
|
|
2042
|
-
self, limit: int = 50, cursor: Optional[str] = None
|
|
2043
|
-
) -> List[SandboxConfig]:
|
|
2044
|
-
"""
|
|
2045
|
-
List all sandbox configurations.
|
|
2046
|
-
"""
|
|
2047
|
-
return self.server.sandbox_config_manager.list_sandbox_configs(
|
|
2048
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2049
|
-
limit=limit,
|
|
2050
|
-
cursor=cursor,
|
|
2051
|
-
)
|
|
2052
|
-
|
|
2053
|
-
def create_sandbox_env_var(
|
|
2054
|
-
self,
|
|
2055
|
-
sandbox_config_id: str,
|
|
2056
|
-
key: str,
|
|
2057
|
-
value: str,
|
|
2058
|
-
description: Optional[str] = None,
|
|
2059
|
-
) -> SandboxEnvironmentVariable:
|
|
2060
|
-
"""
|
|
2061
|
-
Create a new environment variable for a sandbox configuration.
|
|
2062
|
-
"""
|
|
2063
|
-
env_var_create = SandboxEnvironmentVariableCreate(
|
|
2064
|
-
key=key, value=value, description=description
|
|
2065
|
-
)
|
|
2066
|
-
return self.server.sandbox_config_manager.create_sandbox_env_var(
|
|
2067
|
-
env_var_create=env_var_create,
|
|
2068
|
-
sandbox_config_id=sandbox_config_id,
|
|
2069
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2070
|
-
)
|
|
2071
|
-
|
|
2072
|
-
def update_sandbox_env_var(
|
|
2073
|
-
self,
|
|
2074
|
-
env_var_id: str,
|
|
2075
|
-
key: Optional[str] = None,
|
|
2076
|
-
value: Optional[str] = None,
|
|
2077
|
-
description: Optional[str] = None,
|
|
2078
|
-
) -> SandboxEnvironmentVariable:
|
|
2079
|
-
"""
|
|
2080
|
-
Update an existing environment variable.
|
|
2081
|
-
"""
|
|
2082
|
-
env_var_update = SandboxEnvironmentVariableUpdate(
|
|
2083
|
-
key=key, value=value, description=description
|
|
2084
|
-
)
|
|
2085
|
-
return self.server.sandbox_config_manager.update_sandbox_env_var(
|
|
2086
|
-
env_var_id=env_var_id,
|
|
2087
|
-
env_var_update=env_var_update,
|
|
2088
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2089
|
-
)
|
|
2090
|
-
|
|
2091
|
-
def delete_sandbox_env_var(self, env_var_id: str) -> None:
|
|
2092
|
-
"""
|
|
2093
|
-
Delete an environment variable by its ID.
|
|
2094
|
-
"""
|
|
2095
|
-
return self.server.sandbox_config_manager.delete_sandbox_env_var(
|
|
2096
|
-
env_var_id=env_var_id,
|
|
2097
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2098
|
-
)
|
|
2099
|
-
|
|
2100
|
-
def list_sandbox_env_vars(
|
|
2101
|
-
self, sandbox_config_id: str, limit: int = 50, cursor: Optional[str] = None
|
|
2102
|
-
) -> List[SandboxEnvironmentVariable]:
|
|
2103
|
-
"""
|
|
2104
|
-
List all environment variables associated with a sandbox configuration.
|
|
2105
|
-
"""
|
|
2106
|
-
return self.server.sandbox_config_manager.list_sandbox_env_vars(
|
|
2107
|
-
sandbox_config_id=sandbox_config_id,
|
|
2108
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2109
|
-
limit=limit,
|
|
2110
|
-
cursor=cursor,
|
|
2111
|
-
)
|
|
2112
|
-
|
|
2113
|
-
# file management methods
|
|
2114
|
-
def save_file(
|
|
2115
|
-
self, file_path: str, source_id: Optional[str] = None
|
|
2116
|
-
) -> FileMetadata:
|
|
2117
|
-
"""
|
|
2118
|
-
Save a file to the file manager and return its metadata.
|
|
2119
|
-
|
|
2120
|
-
Args:
|
|
2121
|
-
file_path (str): Path to the file to save
|
|
2122
|
-
source_id (Optional[str]): Optional source ID to associate with the file
|
|
2123
|
-
|
|
2124
|
-
Returns:
|
|
2125
|
-
FileMetadata: The created file metadata
|
|
2126
|
-
"""
|
|
2127
|
-
return self.file_manager.create_file_metadata_from_path(
|
|
2128
|
-
file_path=file_path, organization_id=self.org_id, source_id=source_id
|
|
2129
|
-
)
|
|
2130
|
-
|
|
2131
|
-
def list_files(
|
|
2132
|
-
self, cursor: Optional[str] = None, limit: Optional[int] = 50
|
|
2133
|
-
) -> List[FileMetadata]:
|
|
2134
|
-
"""
|
|
2135
|
-
List files for the current organization.
|
|
2136
|
-
|
|
2137
|
-
Args:
|
|
2138
|
-
cursor (Optional[str]): Pagination cursor
|
|
2139
|
-
limit (Optional[int]): Maximum number of files to return
|
|
2140
|
-
|
|
2141
|
-
Returns:
|
|
2142
|
-
List[FileMetadata]: List of file metadata
|
|
2143
|
-
"""
|
|
2144
|
-
return self.file_manager.get_files_by_organization_id(
|
|
2145
|
-
organization_id=self.org_id, cursor=cursor, limit=limit
|
|
2146
|
-
)
|
|
2147
|
-
|
|
2148
|
-
def get_file(self, file_id: str) -> FileMetadata:
|
|
2149
|
-
"""
|
|
2150
|
-
Get file metadata by ID.
|
|
2151
|
-
|
|
2152
|
-
Args:
|
|
2153
|
-
file_id (str): ID of the file
|
|
2154
|
-
|
|
2155
|
-
Returns:
|
|
2156
|
-
FileMetadata: The file metadata
|
|
2157
|
-
"""
|
|
2158
|
-
return self.file_manager.get_file_metadata_by_id(file_id)
|
|
2159
|
-
|
|
2160
|
-
def delete_file(self, file_id: str) -> None:
|
|
2161
|
-
"""
|
|
2162
|
-
Delete a file by ID.
|
|
2163
|
-
|
|
2164
|
-
Args:
|
|
2165
|
-
file_id (str): ID of the file to delete
|
|
2166
|
-
"""
|
|
2167
|
-
self.file_manager.delete_file_metadata(file_id)
|
|
2168
|
-
|
|
2169
|
-
def search_files(self, name_pattern: str) -> List[FileMetadata]:
|
|
2170
|
-
"""
|
|
2171
|
-
Search files by name pattern.
|
|
2172
|
-
|
|
2173
|
-
Args:
|
|
2174
|
-
name_pattern (str): Pattern to search for in file names
|
|
2175
|
-
|
|
2176
|
-
Returns:
|
|
2177
|
-
List[FileMetadata]: List of matching files
|
|
2178
|
-
"""
|
|
2179
|
-
return self.file_manager.search_files_by_name(
|
|
2180
|
-
file_name=name_pattern, organization_id=self.org_id
|
|
2181
|
-
)
|
|
2182
|
-
|
|
2183
|
-
def get_file_stats(self) -> dict:
|
|
2184
|
-
"""
|
|
2185
|
-
Get file statistics for the current organization.
|
|
2186
|
-
|
|
2187
|
-
Returns:
|
|
2188
|
-
dict: File statistics including total files, size, and types
|
|
2189
|
-
"""
|
|
2190
|
-
return self.file_manager.get_file_stats(organization_id=self.org_id)
|
|
2191
|
-
|
|
2192
|
-
def update_agent_memory_block_label(
|
|
2193
|
-
self, agent_id: str, current_label: str, new_label: str
|
|
2194
|
-
) -> Memory:
|
|
2195
|
-
"""Rename a block in the agent's core memory
|
|
2196
|
-
|
|
2197
|
-
Args:
|
|
2198
|
-
agent_id (str): The agent ID
|
|
2199
|
-
current_label (str): The current label of the block
|
|
2200
|
-
new_label (str): The new label of the block
|
|
2201
|
-
|
|
2202
|
-
Returns:
|
|
2203
|
-
memory (Memory): The updated memory
|
|
2204
|
-
"""
|
|
2205
|
-
block = self.get_agent_memory_block(agent_id, current_label)
|
|
2206
|
-
return self.update_block(block.id, label=new_label)
|
|
2207
|
-
|
|
2208
|
-
# TODO: remove this
|
|
2209
|
-
def add_agent_memory_block(
|
|
2210
|
-
self, agent_id: str, create_block: CreateBlock
|
|
2211
|
-
) -> Memory:
|
|
2212
|
-
"""
|
|
2213
|
-
Create and link a memory block to an agent's core memory
|
|
2214
|
-
|
|
2215
|
-
Args:
|
|
2216
|
-
agent_id (str): The agent ID
|
|
2217
|
-
create_block (CreateBlock): The block to create
|
|
2218
|
-
|
|
2219
|
-
Returns:
|
|
2220
|
-
memory (Memory): The updated memory
|
|
2221
|
-
"""
|
|
2222
|
-
block_req = Block(**create_block.model_dump())
|
|
2223
|
-
block = self.server.block_manager.create_or_update_block(
|
|
2224
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id), block=block_req
|
|
2225
|
-
)
|
|
2226
|
-
# Link the block to the agent
|
|
2227
|
-
agent = self.server.agent_manager.attach_block(
|
|
2228
|
-
agent_id=agent_id,
|
|
2229
|
-
block_id=block.id,
|
|
2230
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2231
|
-
)
|
|
2232
|
-
return agent.memory
|
|
2233
|
-
|
|
2234
|
-
def link_agent_memory_block(self, agent_id: str, block_id: str) -> Memory:
|
|
2235
|
-
"""
|
|
2236
|
-
Link a block to an agent's core memory
|
|
2237
|
-
|
|
2238
|
-
Args:
|
|
2239
|
-
agent_id (str): The agent ID
|
|
2240
|
-
block_id (str): The block ID
|
|
2241
|
-
|
|
2242
|
-
Returns:
|
|
2243
|
-
memory (Memory): The updated memory
|
|
2244
|
-
"""
|
|
2245
|
-
return self.server.agent_manager.attach_block(
|
|
2246
|
-
agent_id=agent_id,
|
|
2247
|
-
block_id=block_id,
|
|
2248
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2249
|
-
)
|
|
2250
|
-
|
|
2251
|
-
def remove_agent_memory_block(self, agent_id: str, block_label: str) -> Memory:
|
|
2252
|
-
"""
|
|
2253
|
-
Unlike a block from the agent's core memory
|
|
2254
|
-
|
|
2255
|
-
Args:
|
|
2256
|
-
agent_id (str): The agent ID
|
|
2257
|
-
block_label (str): The block label
|
|
2258
|
-
|
|
2259
|
-
Returns:
|
|
2260
|
-
memory (Memory): The updated memory
|
|
2261
|
-
"""
|
|
2262
|
-
return self.server.agent_manager.detach_block_with_label(
|
|
2263
|
-
agent_id=agent_id,
|
|
2264
|
-
block_label=block_label,
|
|
2265
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2266
|
-
)
|
|
2267
|
-
|
|
2268
|
-
def list_agent_memory_blocks(self, agent_id: str) -> List[Block]:
|
|
2269
|
-
"""
|
|
2270
|
-
Get all the blocks in the agent's core memory
|
|
2271
|
-
|
|
2272
|
-
Args:
|
|
2273
|
-
agent_id (str): The agent ID
|
|
2274
|
-
|
|
2275
|
-
Returns:
|
|
2276
|
-
blocks (List[Block]): The blocks in the agent's core memory
|
|
2277
|
-
"""
|
|
2278
|
-
agent = self.server.agent_manager.get_agent_by_id(
|
|
2279
|
-
agent_id=agent_id,
|
|
2280
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2281
|
-
)
|
|
2282
|
-
return agent.memory.blocks
|
|
2283
|
-
|
|
2284
|
-
def get_agent_memory_block(self, agent_id: str, label: str) -> Block:
|
|
2285
|
-
"""
|
|
2286
|
-
Get a block in the agent's core memory by its label
|
|
2287
|
-
|
|
2288
|
-
Args:
|
|
2289
|
-
agent_id (str): The agent ID
|
|
2290
|
-
label (str): The label in the agent's core memory
|
|
2291
|
-
|
|
2292
|
-
Returns:
|
|
2293
|
-
block (Block): The block corresponding to the label
|
|
2294
|
-
"""
|
|
2295
|
-
return self.server.agent_manager.get_block_with_label(
|
|
2296
|
-
agent_id=agent_id,
|
|
2297
|
-
block_label=label,
|
|
2298
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2299
|
-
)
|
|
2300
|
-
|
|
2301
|
-
def update_agent_memory_block(
|
|
2302
|
-
self,
|
|
2303
|
-
agent_id: str,
|
|
2304
|
-
label: str,
|
|
2305
|
-
value: Optional[str] = None,
|
|
2306
|
-
limit: Optional[int] = None,
|
|
2307
|
-
):
|
|
2308
|
-
"""
|
|
2309
|
-
Update a block in the agent's core memory by specifying its label
|
|
2310
|
-
|
|
2311
|
-
Args:
|
|
2312
|
-
agent_id (str): The agent ID
|
|
2313
|
-
label (str): The label of the block
|
|
2314
|
-
value (str): The new value of the block
|
|
2315
|
-
limit (int): The new limit of the block
|
|
2316
|
-
|
|
2317
|
-
Returns:
|
|
2318
|
-
block (Block): The updated block
|
|
2319
|
-
"""
|
|
2320
|
-
block = self.get_agent_memory_block(agent_id, label)
|
|
2321
|
-
data = {}
|
|
2322
|
-
if value:
|
|
2323
|
-
data["value"] = value
|
|
2324
|
-
if limit:
|
|
2325
|
-
data["limit"] = limit
|
|
2326
|
-
return self.server.block_manager.update_block(
|
|
2327
|
-
block.id,
|
|
2328
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2329
|
-
block_update=BlockUpdate(**data),
|
|
2330
|
-
)
|
|
2331
|
-
|
|
2332
|
-
def update_block(
|
|
2333
|
-
self,
|
|
2334
|
-
block_id: str,
|
|
2335
|
-
label: Optional[str] = None,
|
|
2336
|
-
value: Optional[str] = None,
|
|
2337
|
-
limit: Optional[int] = None,
|
|
2338
|
-
):
|
|
2339
|
-
"""
|
|
2340
|
-
Update a block given the ID with the provided fields
|
|
2341
|
-
|
|
2342
|
-
Args:
|
|
2343
|
-
block_id (str): ID of the block
|
|
2344
|
-
label (str): Label to assign to the block
|
|
2345
|
-
value (str): Value to assign to the block
|
|
2346
|
-
limit (int): Token limit to assign to the block
|
|
2347
|
-
|
|
2348
|
-
Returns:
|
|
2349
|
-
block (Block): Updated block
|
|
2350
|
-
"""
|
|
2351
|
-
data = {}
|
|
2352
|
-
if value:
|
|
2353
|
-
data["value"] = value
|
|
2354
|
-
if limit:
|
|
2355
|
-
data["limit"] = limit
|
|
2356
|
-
if label:
|
|
2357
|
-
data["label"] = label
|
|
2358
|
-
return self.server.block_manager.update_block(
|
|
2359
|
-
block_id,
|
|
2360
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2361
|
-
block_update=BlockUpdate(**data),
|
|
2362
|
-
)
|
|
2363
|
-
|
|
2364
|
-
def get_tags(
|
|
2365
|
-
self,
|
|
2366
|
-
cursor: str = None,
|
|
2367
|
-
limit: int = 100,
|
|
2368
|
-
query_text: str = None,
|
|
2369
|
-
) -> List[str]:
|
|
2370
|
-
"""
|
|
2371
|
-
Get all tags.
|
|
2372
|
-
|
|
2373
|
-
Returns:
|
|
2374
|
-
tags (List[str]): List of tags
|
|
2375
|
-
"""
|
|
2376
|
-
return self.server.agent_manager.list_tags(
|
|
2377
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2378
|
-
cursor=cursor,
|
|
2379
|
-
limit=limit,
|
|
2380
|
-
query_text=query_text,
|
|
2381
|
-
)
|
|
2382
|
-
|
|
2383
|
-
def retrieve_memory(
|
|
2384
|
-
self,
|
|
2385
|
-
agent_id: str,
|
|
2386
|
-
query: str,
|
|
2387
|
-
memory_type: str = "all",
|
|
2388
|
-
search_field: str = "null",
|
|
2389
|
-
search_method: str = "embedding",
|
|
2390
|
-
timezone_str: str = "UTC",
|
|
2391
|
-
limit: int = 10,
|
|
2392
|
-
) -> dict:
|
|
2393
|
-
"""
|
|
2394
|
-
Retrieve memories by searching across different memory types.
|
|
2395
|
-
|
|
2396
|
-
Args:
|
|
2397
|
-
agent_id (str): ID of the agent to retrieve memories for
|
|
2398
|
-
query (str): The keywords/query used to search in the memory
|
|
2399
|
-
memory_type (str): The type of memory to search in. Options: "episodic", "resource", "procedural",
|
|
2400
|
-
"knowledge_vault", "semantic", "all". Defaults to "all".
|
|
2401
|
-
search_field (str): The field to search in the memory. For "episodic": 'summary', 'details';
|
|
2402
|
-
for "resource": 'summary', 'content'; for "procedural": 'summary', 'steps';
|
|
2403
|
-
for "knowledge_vault": 'secret_value', 'caption'; for "semantic": 'name', 'summary', 'details'.
|
|
2404
|
-
Use "null" for default fields. Defaults to "null".
|
|
2405
|
-
search_method (str): The method to search. Options: 'bm25' (keyword-based), 'embedding' (semantic).
|
|
2406
|
-
Defaults to "embedding".
|
|
2407
|
-
timezone_str (str): Timezone string for time-based operations. Defaults to "UTC".
|
|
2408
|
-
limit (int): Maximum number of results to return per memory type. Defaults to 10.
|
|
2409
|
-
|
|
2410
|
-
Returns:
|
|
2411
|
-
dict: Dictionary containing 'results' (list of memories) and 'count' (total number of results)
|
|
2412
|
-
"""
|
|
2413
|
-
# Import here to avoid circular imports
|
|
2414
|
-
|
|
2415
|
-
# Validate inputs
|
|
2416
|
-
if (
|
|
2417
|
-
memory_type == "resource"
|
|
2418
|
-
and search_field == "content"
|
|
2419
|
-
and search_method == "embedding"
|
|
2420
|
-
):
|
|
2421
|
-
raise ValueError(
|
|
2422
|
-
"embedding is not supported for resource memory's 'content' field."
|
|
2423
|
-
)
|
|
2424
|
-
if (
|
|
2425
|
-
memory_type == "knowledge_vault"
|
|
2426
|
-
and search_field == "secret_value"
|
|
2427
|
-
and search_method == "embedding"
|
|
2428
|
-
):
|
|
2429
|
-
raise ValueError(
|
|
2430
|
-
"embedding is not supported for knowledge_vault memory's 'secret_value' field."
|
|
2431
|
-
)
|
|
2432
|
-
|
|
2433
|
-
# Get the agent to access its memory managers
|
|
2434
|
-
agent_state = self.server.agent_manager.get_agent_by_id(
|
|
2435
|
-
agent_id=agent_id,
|
|
2436
|
-
actor=self.server.user_manager.get_user_by_id(self.user.id),
|
|
2437
|
-
)
|
|
2438
|
-
|
|
2439
|
-
if memory_type == "all":
|
|
2440
|
-
search_field = "null"
|
|
2441
|
-
|
|
2442
|
-
# Initialize result lists
|
|
2443
|
-
formatted_results = []
|
|
2444
|
-
|
|
2445
|
-
# Search episodic memory
|
|
2446
|
-
if memory_type == "episodic" or memory_type == "all":
|
|
2447
|
-
episodic_memory = self.server.episodic_memory_manager.list_episodic_memory(
|
|
2448
|
-
actor=self.user,
|
|
2449
|
-
agent_state=agent_state,
|
|
2450
|
-
query=query,
|
|
2451
|
-
search_field=search_field if search_field != "null" else "summary",
|
|
2452
|
-
search_method=search_method,
|
|
2453
|
-
limit=limit,
|
|
2454
|
-
timezone_str=timezone_str,
|
|
2455
|
-
)
|
|
2456
|
-
formatted_results_episodic = [
|
|
2457
|
-
{
|
|
2458
|
-
"memory_type": "episodic",
|
|
2459
|
-
"id": x.id,
|
|
2460
|
-
"timestamp": x.occurred_at,
|
|
2461
|
-
"event_type": x.event_type,
|
|
2462
|
-
"actor": x.actor,
|
|
2463
|
-
"summary": x.summary,
|
|
2464
|
-
"details": x.details,
|
|
2465
|
-
}
|
|
2466
|
-
for x in episodic_memory
|
|
2467
|
-
]
|
|
2468
|
-
if memory_type == "episodic":
|
|
2469
|
-
return {
|
|
2470
|
-
"results": formatted_results_episodic,
|
|
2471
|
-
"count": len(formatted_results_episodic),
|
|
2472
|
-
}
|
|
2473
|
-
formatted_results.extend(formatted_results_episodic)
|
|
2474
|
-
|
|
2475
|
-
# Search resource memory
|
|
2476
|
-
if memory_type == "resource" or memory_type == "all":
|
|
2477
|
-
resource_memories = self.server.resource_memory_manager.list_resources(
|
|
2478
|
-
actor=self.user,
|
|
2479
|
-
agent_state=agent_state,
|
|
2480
|
-
query=query,
|
|
2481
|
-
search_field=search_field
|
|
2482
|
-
if search_field != "null"
|
|
2483
|
-
else ("summary" if search_method == "embedding" else "content"),
|
|
2484
|
-
search_method=search_method,
|
|
2485
|
-
limit=limit,
|
|
2486
|
-
timezone_str=timezone_str,
|
|
2487
|
-
)
|
|
2488
|
-
formatted_results_resource = [
|
|
2489
|
-
{
|
|
2490
|
-
"memory_type": "resource",
|
|
2491
|
-
"id": x.id,
|
|
2492
|
-
"resource_type": x.resource_type,
|
|
2493
|
-
"summary": x.summary,
|
|
2494
|
-
"content": x.content,
|
|
2495
|
-
}
|
|
2496
|
-
for x in resource_memories
|
|
2497
|
-
]
|
|
2498
|
-
if memory_type == "resource":
|
|
2499
|
-
return {
|
|
2500
|
-
"results": formatted_results_resource,
|
|
2501
|
-
"count": len(formatted_results_resource),
|
|
2502
|
-
}
|
|
2503
|
-
formatted_results.extend(formatted_results_resource)
|
|
2504
|
-
|
|
2505
|
-
# Search procedural memory
|
|
2506
|
-
if memory_type == "procedural" or memory_type == "all":
|
|
2507
|
-
procedural_memories = self.server.procedural_memory_manager.list_procedures(
|
|
2508
|
-
actor=self.user,
|
|
2509
|
-
agent_state=agent_state,
|
|
2510
|
-
query=query,
|
|
2511
|
-
search_field=search_field if search_field != "null" else "summary",
|
|
2512
|
-
search_method=search_method,
|
|
2513
|
-
limit=limit,
|
|
2514
|
-
timezone_str=timezone_str,
|
|
2515
|
-
)
|
|
2516
|
-
formatted_results_procedural = [
|
|
2517
|
-
{
|
|
2518
|
-
"memory_type": "procedural",
|
|
2519
|
-
"id": x.id,
|
|
2520
|
-
"entry_type": x.entry_type,
|
|
2521
|
-
"summary": x.summary,
|
|
2522
|
-
"steps": x.steps,
|
|
2523
|
-
}
|
|
2524
|
-
for x in procedural_memories
|
|
2525
|
-
]
|
|
2526
|
-
if memory_type == "procedural":
|
|
2527
|
-
return {
|
|
2528
|
-
"results": formatted_results_procedural,
|
|
2529
|
-
"count": len(formatted_results_procedural),
|
|
2530
|
-
}
|
|
2531
|
-
formatted_results.extend(formatted_results_procedural)
|
|
2532
|
-
|
|
2533
|
-
# Search knowledge vault
|
|
2534
|
-
if memory_type == "knowledge_vault" or memory_type == "all":
|
|
2535
|
-
knowledge_vault_memories = (
|
|
2536
|
-
self.server.knowledge_vault_manager.list_knowledge(
|
|
2537
|
-
actor=self.user,
|
|
2538
|
-
agent_state=agent_state,
|
|
2539
|
-
query=query,
|
|
2540
|
-
search_field=search_field if search_field != "null" else "caption",
|
|
2541
|
-
search_method=search_method,
|
|
2542
|
-
limit=limit,
|
|
2543
|
-
timezone_str=timezone_str,
|
|
2544
|
-
)
|
|
2545
|
-
)
|
|
2546
|
-
formatted_results_knowledge_vault = [
|
|
2547
|
-
{
|
|
2548
|
-
"memory_type": "knowledge_vault",
|
|
2549
|
-
"id": x.id,
|
|
2550
|
-
"entry_type": x.entry_type,
|
|
2551
|
-
"source": x.source,
|
|
2552
|
-
"sensitivity": x.sensitivity,
|
|
2553
|
-
"secret_value": x.secret_value,
|
|
2554
|
-
"caption": x.caption,
|
|
2555
|
-
}
|
|
2556
|
-
for x in knowledge_vault_memories
|
|
2557
|
-
]
|
|
2558
|
-
if memory_type == "knowledge_vault":
|
|
2559
|
-
return {
|
|
2560
|
-
"results": formatted_results_knowledge_vault,
|
|
2561
|
-
"count": len(formatted_results_knowledge_vault),
|
|
2562
|
-
}
|
|
2563
|
-
formatted_results.extend(formatted_results_knowledge_vault)
|
|
2564
|
-
|
|
2565
|
-
# Search semantic memory
|
|
2566
|
-
if memory_type == "semantic" or memory_type == "all":
|
|
2567
|
-
semantic_memories = self.server.semantic_memory_manager.list_semantic_items(
|
|
2568
|
-
actor=self.user,
|
|
2569
|
-
agent_state=agent_state,
|
|
2570
|
-
query=query,
|
|
2571
|
-
search_field=search_field if search_field != "null" else "summary",
|
|
2572
|
-
search_method=search_method,
|
|
2573
|
-
limit=limit,
|
|
2574
|
-
timezone_str=timezone_str,
|
|
2575
|
-
)
|
|
2576
|
-
formatted_results_semantic = [
|
|
2577
|
-
{
|
|
2578
|
-
"memory_type": "semantic",
|
|
2579
|
-
"id": x.id,
|
|
2580
|
-
"name": x.name,
|
|
2581
|
-
"summary": x.summary,
|
|
2582
|
-
"details": x.details,
|
|
2583
|
-
"source": x.source,
|
|
2584
|
-
}
|
|
2585
|
-
for x in semantic_memories
|
|
2586
|
-
]
|
|
2587
|
-
if memory_type == "semantic":
|
|
2588
|
-
return {
|
|
2589
|
-
"results": formatted_results_semantic,
|
|
2590
|
-
"count": len(formatted_results_semantic),
|
|
2591
|
-
}
|
|
2592
|
-
formatted_results.extend(formatted_results_semantic)
|
|
2593
|
-
|
|
2594
|
-
return {"results": formatted_results, "count": len(formatted_results)}
|