letta-nightly 0.6.1.dev20241205211219__py3-none-any.whl → 0.6.1.dev20241207104149__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.
Potentially problematic release.
This version of letta-nightly might be problematic. Click here for more details.
- letta/agent.py +54 -37
- letta/agent_store/db.py +1 -77
- letta/agent_store/storage.py +0 -5
- letta/chat_only_agent.py +103 -0
- letta/cli/cli.py +0 -1
- letta/client/client.py +3 -7
- letta/constants.py +1 -0
- letta/functions/function_sets/base.py +37 -9
- letta/main.py +2 -2
- letta/memory.py +4 -82
- letta/metadata.py +0 -35
- letta/o1_agent.py +7 -2
- letta/offline_memory_agent.py +180 -0
- letta/orm/__init__.py +3 -0
- letta/orm/file.py +1 -1
- letta/orm/message.py +66 -0
- letta/orm/mixins.py +16 -0
- letta/orm/organization.py +1 -0
- letta/orm/sqlalchemy_base.py +118 -26
- letta/orm/tool.py +22 -1
- letta/orm/tools_agents.py +32 -0
- letta/personas/examples/offline_memory_persona.txt +4 -0
- letta/prompts/system/memgpt_convo_only.txt +14 -0
- letta/prompts/system/memgpt_offline_memory.txt +23 -0
- letta/prompts/system/memgpt_offline_memory_chat.txt +35 -0
- letta/schemas/agent.py +3 -2
- letta/schemas/letta_base.py +7 -6
- letta/schemas/message.py +1 -7
- letta/schemas/tools_agents.py +32 -0
- letta/server/rest_api/app.py +11 -0
- letta/server/rest_api/routers/v1/agents.py +2 -2
- letta/server/rest_api/routers/v1/blocks.py +2 -2
- letta/server/server.py +63 -47
- letta/server/static_files/assets/index-43ab4d62.css +1 -0
- letta/server/static_files/assets/index-4848e3d7.js +40 -0
- letta/server/static_files/index.html +2 -2
- letta/services/block_manager.py +1 -1
- letta/services/message_manager.py +182 -0
- letta/services/organization_manager.py +6 -9
- letta/services/source_manager.py +1 -1
- letta/services/tool_manager.py +2 -2
- letta/services/tools_agents_manager.py +94 -0
- letta/services/user_manager.py +1 -1
- {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/METADATA +2 -1
- {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/RECORD +48 -39
- letta/agent_store/lancedb.py +0 -177
- letta/persistence_manager.py +0 -149
- letta/server/static_files/assets/index-3ab03d5b.css +0 -1
- letta/server/static_files/assets/index-9fa459a2.js +0 -271
- {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/LICENSE +0 -0
- {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/WHEEL +0 -0
- {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/entry_points.txt +0 -0
letta/server/server.py
CHANGED
|
@@ -18,6 +18,7 @@ import letta.system as system
|
|
|
18
18
|
from letta.agent import Agent, save_agent
|
|
19
19
|
from letta.agent_store.db import attach_base
|
|
20
20
|
from letta.agent_store.storage import StorageConnector, TableType
|
|
21
|
+
from letta.chat_only_agent import ChatOnlyAgent
|
|
21
22
|
from letta.credentials import LettaCredentials
|
|
22
23
|
from letta.data_sources.connectors import DataConnector, load_data
|
|
23
24
|
|
|
@@ -27,6 +28,7 @@ from letta.interface import CLIInterface # for printing to terminal
|
|
|
27
28
|
from letta.log import get_logger
|
|
28
29
|
from letta.metadata import MetadataStore
|
|
29
30
|
from letta.o1_agent import O1Agent
|
|
31
|
+
from letta.offline_memory_agent import OfflineMemoryAgent
|
|
30
32
|
from letta.orm import Base
|
|
31
33
|
from letta.orm.errors import NoResultFound
|
|
32
34
|
from letta.prompts import gpt_system
|
|
@@ -76,12 +78,14 @@ from letta.services.agents_tags_manager import AgentsTagsManager
|
|
|
76
78
|
from letta.services.block_manager import BlockManager
|
|
77
79
|
from letta.services.blocks_agents_manager import BlocksAgentsManager
|
|
78
80
|
from letta.services.job_manager import JobManager
|
|
81
|
+
from letta.services.message_manager import MessageManager
|
|
79
82
|
from letta.services.organization_manager import OrganizationManager
|
|
80
83
|
from letta.services.per_agent_lock_manager import PerAgentLockManager
|
|
81
84
|
from letta.services.sandbox_config_manager import SandboxConfigManager
|
|
82
85
|
from letta.services.source_manager import SourceManager
|
|
83
86
|
from letta.services.tool_execution_sandbox import ToolExecutionSandbox
|
|
84
87
|
from letta.services.tool_manager import ToolManager
|
|
88
|
+
from letta.services.tools_agents_manager import ToolsAgentsManager
|
|
85
89
|
from letta.services.user_manager import UserManager
|
|
86
90
|
from letta.utils import create_random_username, get_utc_time, json_dumps, json_loads
|
|
87
91
|
|
|
@@ -257,6 +261,8 @@ class SyncServer(Server):
|
|
|
257
261
|
self.agents_tags_manager = AgentsTagsManager()
|
|
258
262
|
self.sandbox_config_manager = SandboxConfigManager(tool_settings)
|
|
259
263
|
self.blocks_agents_manager = BlocksAgentsManager()
|
|
264
|
+
self.message_manager = MessageManager()
|
|
265
|
+
self.tools_agents_manager = ToolsAgentsManager()
|
|
260
266
|
self.job_manager = JobManager()
|
|
261
267
|
|
|
262
268
|
# Managers that interface with parallelism
|
|
@@ -404,8 +410,14 @@ class SyncServer(Server):
|
|
|
404
410
|
interface = interface or self.default_interface_factory()
|
|
405
411
|
if agent_state.agent_type == AgentType.memgpt_agent:
|
|
406
412
|
agent = Agent(agent_state=agent_state, interface=interface, user=actor)
|
|
407
|
-
|
|
413
|
+
elif agent_state.agent_type == AgentType.o1_agent:
|
|
408
414
|
agent = O1Agent(agent_state=agent_state, interface=interface, user=actor)
|
|
415
|
+
elif agent_state.agent_type == AgentType.offline_memory_agent:
|
|
416
|
+
agent = OfflineMemoryAgent(agent_state=agent_state, interface=interface, user=actor)
|
|
417
|
+
elif agent_state.agent_type == AgentType.chat_only_agent:
|
|
418
|
+
agent = ChatOnlyAgent(agent_state=agent_state, interface=interface, user=actor)
|
|
419
|
+
else:
|
|
420
|
+
raise ValueError(f"Invalid agent type {agent_state.agent_type}")
|
|
409
421
|
|
|
410
422
|
# Rebuild the system prompt - may be linked to new blocks now
|
|
411
423
|
agent.rebuild_system_prompt()
|
|
@@ -508,12 +520,7 @@ class SyncServer(Server):
|
|
|
508
520
|
letta_agent.interface.print_messages_raw(letta_agent.messages)
|
|
509
521
|
|
|
510
522
|
elif command.lower() == "memory":
|
|
511
|
-
ret_str = (
|
|
512
|
-
f"\nDumping memory contents:\n"
|
|
513
|
-
+ f"\n{str(letta_agent.agent_state.memory)}"
|
|
514
|
-
+ f"\n{str(letta_agent.persistence_manager.archival_memory)}"
|
|
515
|
-
+ f"\n{str(letta_agent.persistence_manager.recall_memory)}"
|
|
516
|
-
)
|
|
523
|
+
ret_str = f"\nDumping memory contents:\n" + f"\n{str(letta_agent.agent_state.memory)}" + f"\n{str(letta_agent.archival_memory)}"
|
|
517
524
|
return ret_str
|
|
518
525
|
|
|
519
526
|
elif command.lower() == "pop" or command.lower().startswith("pop "):
|
|
@@ -615,7 +622,6 @@ class SyncServer(Server):
|
|
|
615
622
|
# Convert to a Message object
|
|
616
623
|
if timestamp:
|
|
617
624
|
message = Message(
|
|
618
|
-
user_id=user_id,
|
|
619
625
|
agent_id=agent_id,
|
|
620
626
|
role="user",
|
|
621
627
|
text=packaged_user_message,
|
|
@@ -623,7 +629,6 @@ class SyncServer(Server):
|
|
|
623
629
|
)
|
|
624
630
|
else:
|
|
625
631
|
message = Message(
|
|
626
|
-
user_id=user_id,
|
|
627
632
|
agent_id=agent_id,
|
|
628
633
|
role="user",
|
|
629
634
|
text=packaged_user_message,
|
|
@@ -662,7 +667,6 @@ class SyncServer(Server):
|
|
|
662
667
|
|
|
663
668
|
if timestamp:
|
|
664
669
|
message = Message(
|
|
665
|
-
user_id=user_id,
|
|
666
670
|
agent_id=agent_id,
|
|
667
671
|
role="system",
|
|
668
672
|
text=packaged_system_message,
|
|
@@ -670,7 +674,6 @@ class SyncServer(Server):
|
|
|
670
674
|
)
|
|
671
675
|
else:
|
|
672
676
|
message = Message(
|
|
673
|
-
user_id=user_id,
|
|
674
677
|
agent_id=agent_id,
|
|
675
678
|
role="system",
|
|
676
679
|
text=packaged_system_message,
|
|
@@ -733,7 +736,6 @@ class SyncServer(Server):
|
|
|
733
736
|
# Create the Message object
|
|
734
737
|
message_objects.append(
|
|
735
738
|
Message(
|
|
736
|
-
user_id=user_id,
|
|
737
739
|
agent_id=agent_id,
|
|
738
740
|
role=message.role,
|
|
739
741
|
text=message.text,
|
|
@@ -800,6 +802,10 @@ class SyncServer(Server):
|
|
|
800
802
|
request.system = gpt_system.get_system_text("memgpt_chat")
|
|
801
803
|
elif request.agent_type == AgentType.o1_agent:
|
|
802
804
|
request.system = gpt_system.get_system_text("memgpt_modified_o1")
|
|
805
|
+
elif request.agent_type == AgentType.offline_memory_agent:
|
|
806
|
+
request.system = gpt_system.get_system_text("memgpt_offline_memory")
|
|
807
|
+
elif request.agent_type == AgentType.chat_only_agent:
|
|
808
|
+
request.system = gpt_system.get_system_text("memgpt_convo_only")
|
|
803
809
|
else:
|
|
804
810
|
raise ValueError(f"Invalid agent type: {request.agent_type}")
|
|
805
811
|
|
|
@@ -862,7 +868,7 @@ class SyncServer(Server):
|
|
|
862
868
|
else:
|
|
863
869
|
raise ValueError(f"Invalid message role: {message.role}")
|
|
864
870
|
|
|
865
|
-
init_messages.append(Message(role=message.role, text=packed_message,
|
|
871
|
+
init_messages.append(Message(role=message.role, text=packed_message, agent_id=agent_state.id))
|
|
866
872
|
# init_messages = [Message.dict_to_message(user_id=user_id, agent_id=agent_state.id, openai_message_dict=message.model_dump()) for message in request.initial_message_sequence]
|
|
867
873
|
else:
|
|
868
874
|
init_messages = None
|
|
@@ -1146,11 +1152,11 @@ class SyncServer(Server):
|
|
|
1146
1152
|
|
|
1147
1153
|
def get_archival_memory_summary(self, agent_id: str) -> ArchivalMemorySummary:
|
|
1148
1154
|
agent = self.load_agent(agent_id=agent_id)
|
|
1149
|
-
return ArchivalMemorySummary(size=len(agent.
|
|
1155
|
+
return ArchivalMemorySummary(size=len(agent.archival_memory))
|
|
1150
1156
|
|
|
1151
1157
|
def get_recall_memory_summary(self, agent_id: str) -> RecallMemorySummary:
|
|
1152
1158
|
agent = self.load_agent(agent_id=agent_id)
|
|
1153
|
-
return RecallMemorySummary(size=len(agent.
|
|
1159
|
+
return RecallMemorySummary(size=len(agent.message_manager))
|
|
1154
1160
|
|
|
1155
1161
|
def get_in_context_message_ids(self, agent_id: str) -> List[str]:
|
|
1156
1162
|
"""Get the message ids of the in-context messages in the agent's memory"""
|
|
@@ -1168,7 +1174,7 @@ class SyncServer(Server):
|
|
|
1168
1174
|
"""Get a single message from the agent's memory"""
|
|
1169
1175
|
# Get the agent object (loaded in memory)
|
|
1170
1176
|
agent = self.load_agent(agent_id=agent_id)
|
|
1171
|
-
message = agent.
|
|
1177
|
+
message = agent.message_manager.get_message_by_id(id=message_id, actor=self.default_user)
|
|
1172
1178
|
return message
|
|
1173
1179
|
|
|
1174
1180
|
def get_agent_messages(
|
|
@@ -1199,14 +1205,16 @@ class SyncServer(Server):
|
|
|
1199
1205
|
|
|
1200
1206
|
else:
|
|
1201
1207
|
# need to access persistence manager for additional messages
|
|
1202
|
-
db_iterator = letta_agent.persistence_manager.recall_memory.storage.get_all_paginated(page_size=count, offset=start)
|
|
1203
1208
|
|
|
1204
|
-
# get
|
|
1205
|
-
|
|
1206
|
-
|
|
1209
|
+
# get messages using message manager
|
|
1210
|
+
page = letta_agent.message_manager.list_user_messages_for_agent(
|
|
1211
|
+
agent_id=agent_id,
|
|
1212
|
+
actor=self.default_user,
|
|
1213
|
+
cursor=start,
|
|
1214
|
+
limit=count,
|
|
1215
|
+
)
|
|
1207
1216
|
|
|
1208
|
-
|
|
1209
|
-
messages = sorted(page, key=lambda x: x.created_at, reverse=True)
|
|
1217
|
+
messages = page
|
|
1210
1218
|
assert all(isinstance(m, Message) for m in messages)
|
|
1211
1219
|
|
|
1212
1220
|
## Convert to json
|
|
@@ -1229,7 +1237,7 @@ class SyncServer(Server):
|
|
|
1229
1237
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1230
1238
|
|
|
1231
1239
|
# iterate over records
|
|
1232
|
-
db_iterator = letta_agent.
|
|
1240
|
+
db_iterator = letta_agent.archival_memory.storage.get_all_paginated(page_size=count, offset=start)
|
|
1233
1241
|
|
|
1234
1242
|
# get a single page of messages
|
|
1235
1243
|
page = next(db_iterator, [])
|
|
@@ -1254,7 +1262,7 @@ class SyncServer(Server):
|
|
|
1254
1262
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1255
1263
|
|
|
1256
1264
|
# iterate over recorde
|
|
1257
|
-
cursor, records = letta_agent.
|
|
1265
|
+
cursor, records = letta_agent.archival_memory.storage.get_all_cursor(
|
|
1258
1266
|
after=after, before=before, limit=limit, order_by=order_by, reverse=reverse
|
|
1259
1267
|
)
|
|
1260
1268
|
return records
|
|
@@ -1269,14 +1277,14 @@ class SyncServer(Server):
|
|
|
1269
1277
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1270
1278
|
|
|
1271
1279
|
# Insert into archival memory
|
|
1272
|
-
passage_ids = letta_agent.
|
|
1280
|
+
passage_ids = letta_agent.archival_memory.insert(memory_string=memory_contents, return_ids=True)
|
|
1273
1281
|
|
|
1274
1282
|
# Update the agent
|
|
1275
1283
|
# TODO: should this update the system prompt?
|
|
1276
1284
|
save_agent(letta_agent, self.ms)
|
|
1277
1285
|
|
|
1278
1286
|
# TODO: this is gross, fix
|
|
1279
|
-
return [letta_agent.
|
|
1287
|
+
return [letta_agent.archival_memory.storage.get(id=passage_id) for passage_id in passage_ids]
|
|
1280
1288
|
|
|
1281
1289
|
def delete_archival_memory(self, user_id: str, agent_id: str, memory_id: str):
|
|
1282
1290
|
if self.user_manager.get_user_by_id(user_id=user_id) is None:
|
|
@@ -1291,7 +1299,7 @@ class SyncServer(Server):
|
|
|
1291
1299
|
|
|
1292
1300
|
# Delete by ID
|
|
1293
1301
|
# TODO check if it exists first, and throw error if not
|
|
1294
|
-
letta_agent.
|
|
1302
|
+
letta_agent.archival_memory.storage.delete({"id": memory_id})
|
|
1295
1303
|
|
|
1296
1304
|
# TODO: return archival memory
|
|
1297
1305
|
|
|
@@ -1299,17 +1307,15 @@ class SyncServer(Server):
|
|
|
1299
1307
|
self,
|
|
1300
1308
|
user_id: str,
|
|
1301
1309
|
agent_id: str,
|
|
1302
|
-
|
|
1303
|
-
before: Optional[str] = None,
|
|
1310
|
+
cursor: Optional[str] = None,
|
|
1304
1311
|
limit: Optional[int] = 100,
|
|
1305
|
-
order_by: Optional[str] = "created_at",
|
|
1306
|
-
order: Optional[str] = "asc",
|
|
1307
1312
|
reverse: Optional[bool] = False,
|
|
1308
1313
|
return_message_object: bool = True,
|
|
1309
1314
|
assistant_message_tool_name: str = constants.DEFAULT_MESSAGE_TOOL,
|
|
1310
1315
|
assistant_message_tool_kwarg: str = constants.DEFAULT_MESSAGE_TOOL_KWARG,
|
|
1311
1316
|
) -> Union[List[Message], List[LettaMessage]]:
|
|
1312
|
-
|
|
1317
|
+
actor = self.user_manager.get_user_by_id(user_id=user_id)
|
|
1318
|
+
if actor is None:
|
|
1313
1319
|
raise ValueError(f"User user_id={user_id} does not exist")
|
|
1314
1320
|
if self.ms.get_agent(agent_id=agent_id, user_id=user_id) is None:
|
|
1315
1321
|
raise ValueError(f"Agent agent_id={agent_id} does not exist")
|
|
@@ -1318,8 +1324,12 @@ class SyncServer(Server):
|
|
|
1318
1324
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1319
1325
|
|
|
1320
1326
|
# iterate over records
|
|
1321
|
-
|
|
1322
|
-
|
|
1327
|
+
# TODO: Check "order_by", "order"
|
|
1328
|
+
records = letta_agent.message_manager.list_messages_for_agent(
|
|
1329
|
+
agent_id=agent_id,
|
|
1330
|
+
actor=actor,
|
|
1331
|
+
cursor=cursor,
|
|
1332
|
+
limit=limit,
|
|
1323
1333
|
)
|
|
1324
1334
|
|
|
1325
1335
|
assert all(isinstance(m, Message) for m in records)
|
|
@@ -1411,19 +1421,25 @@ class SyncServer(Server):
|
|
|
1411
1421
|
self.agents_tags_manager.delete_all_tags_from_agent(agent_id=agent_id, actor=actor)
|
|
1412
1422
|
self.blocks_agents_manager.remove_all_agent_blocks(agent_id=agent_id)
|
|
1413
1423
|
|
|
1414
|
-
if self.ms.get_agent(agent_id=agent_id, user_id=user_id) is None:
|
|
1415
|
-
raise ValueError(f"Agent agent_id={agent_id} does not exist")
|
|
1416
|
-
|
|
1417
1424
|
# Verify that the agent exists and belongs to the org of the user
|
|
1418
1425
|
agent_state = self.ms.get_agent(agent_id=agent_id, user_id=user_id)
|
|
1419
|
-
if
|
|
1426
|
+
if agent_state is None:
|
|
1420
1427
|
raise ValueError(f"Could not find agent_id={agent_id} under user_id={user_id}")
|
|
1421
1428
|
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1429
|
+
# TODO: REMOVE THIS ONCE WE MIGRATE AGENTMODEL TO ORM MODEL
|
|
1430
|
+
messages = self.message_manager.list_messages_for_agent(agent_id=agent_state.id)
|
|
1431
|
+
for message in messages:
|
|
1432
|
+
self.message_manager.delete_message_by_id(message.id, actor=actor)
|
|
1433
|
+
|
|
1434
|
+
# TODO: REMOVE THIS ONCE WE MIGRATE AGENTMODEL TO ORM
|
|
1435
|
+
try:
|
|
1436
|
+
agent_state_user = self.user_manager.get_user_by_id(user_id=agent_state.user_id)
|
|
1437
|
+
if agent_state_user.organization_id != actor.organization_id:
|
|
1438
|
+
raise ValueError(
|
|
1439
|
+
f"Could not authorize agent_id={agent_id} with user_id={user_id} because of differing organizations; agent_id was created in {agent_state_user.organization_id} while user belongs to {actor.organization_id}. How did they get the agent id?"
|
|
1440
|
+
)
|
|
1441
|
+
except NoResultFound:
|
|
1442
|
+
logger.error(f"Agent with id {agent_state.id} has nonexistent user {agent_state.user_id}")
|
|
1427
1443
|
|
|
1428
1444
|
# First, if the agent is in the in-memory cache we should remove it
|
|
1429
1445
|
# List of {'user_id': user_id, 'agent_id': agent_id, 'agent': agent_obj} dicts
|
|
@@ -1568,7 +1584,7 @@ class SyncServer(Server):
|
|
|
1568
1584
|
|
|
1569
1585
|
# delete all Passage objects with source_id==source_id from agent's archival memory
|
|
1570
1586
|
agent = self.load_agent(agent_id=agent_id)
|
|
1571
|
-
archival_memory = agent.
|
|
1587
|
+
archival_memory = agent.archival_memory
|
|
1572
1588
|
archival_memory.storage.delete({"source_id": source_id})
|
|
1573
1589
|
|
|
1574
1590
|
# delete agent-source mapping
|
|
@@ -1647,7 +1663,7 @@ class SyncServer(Server):
|
|
|
1647
1663
|
"""Get a single message from the agent's memory"""
|
|
1648
1664
|
# Get the agent object (loaded in memory)
|
|
1649
1665
|
letta_agent = self.load_agent(agent_id=agent_id)
|
|
1650
|
-
message = letta_agent.
|
|
1666
|
+
message = letta_agent.message_manager.get_message_by_id(id=message_id)
|
|
1651
1667
|
save_agent(letta_agent, self.ms)
|
|
1652
1668
|
return message
|
|
1653
1669
|
|
|
@@ -1691,7 +1707,7 @@ class SyncServer(Server):
|
|
|
1691
1707
|
|
|
1692
1708
|
try:
|
|
1693
1709
|
return self.user_manager.get_user_by_id(user_id=user_id)
|
|
1694
|
-
except
|
|
1710
|
+
except NoResultFound:
|
|
1695
1711
|
raise HTTPException(status_code=404, detail=f"User with id {user_id} not found")
|
|
1696
1712
|
|
|
1697
1713
|
def get_organization_or_default(self, org_id: Optional[str]) -> Organization:
|
|
@@ -1701,7 +1717,7 @@ class SyncServer(Server):
|
|
|
1701
1717
|
|
|
1702
1718
|
try:
|
|
1703
1719
|
return self.organization_manager.get_organization_by_id(org_id=org_id)
|
|
1704
|
-
except
|
|
1720
|
+
except NoResultFound:
|
|
1705
1721
|
raise HTTPException(status_code=404, detail=f"Organization with id {org_id} not found")
|
|
1706
1722
|
|
|
1707
1723
|
def list_llm_models(self) -> List[LLMConfig]:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}:root{--background: 210, 10%, 92%;--background-lighter: 0, 0%, 100%;--background-darker: 210, 6%, 86%;--foreground: 224 71.4% 4.1%;--card: 0 0% 100%;--card-foreground: 224 71.4% 4.1%;--popover: 0 0% 100%;--popover-foreground: 224 71.4% 4.1%;--primary: 220.9 39.3% 11%;--primary-foreground: 210 20% 98%;--secondary: 240, 92%, 35%;--secondary-foreground: 0, 0%, 100%;--muted: 220 14.3% 95.9%;--muted-foreground: 220 8.9% 46.1%;--accent: 220 14.3% 95.9%;--accent-foreground: 220.9 39.3% 11%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 20% 98%;--border: 210, 6%, 86%;--input: 210, 6%, 86%;--ring: 224 71.4% 4.1%;--radius: .5rem}.dark{--background: 224 71.4% 4.1%;--background-lighter: 224 71.4% 4.1%;--background-darker: 224 71.4% 4.1%;--foreground: 210 20% 98%;--card: 224 71.4% 4.1%;--card-foreground: 210 20% 98%;--popover: 224 71.4% 4.1%;--popover-foreground: 210 20% 98%;--primary: 210 20% 98%;--primary-foreground: 220.9 39.3% 11%;--secondary: 10, 100%, 60%;--secondary-foreground: 210 20% 98%;--muted: 215 27.9% 16.9%;--muted-foreground: 217.9 10.6% 64.9%;--accent: 215 27.9% 16.9%;--accent-foreground: 210 20% 98%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 210 20% 98%;--border: 215 27.9% 16.9%;--input: 215 27.9% 16.9%;--ring: 216 12.2% 83.9%}*{border-color:hsl(var(--border))}html{height:100%}body{height:100%;width:100%;background-color:hsl(var(--background));color:hsl(var(--foreground));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}input::file-selector-button{color:hsl(var(--foreground))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.fixed{position:fixed}.mt-10{margin-top:2.5rem}.mt-3{margin-top:.75rem}.flex{display:flex}.h-\[100dvh\]{height:100dvh}.h-full{height:100%}.w-\[100dvh\]{width:100dvh}.w-full{width:100%}.max-w-\[600px\]{max-width:600px}.max-w-\[893px\]{max-width:893px}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-5{gap:1.25rem}.border{border-width:1px}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.p-0{padding:0}.p-10{padding:2.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.PopoverContent{width:var(--radix-popover-trigger-width);max-height:var(--radix-popover-content-available-height)}
|