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.

Files changed (52) hide show
  1. letta/agent.py +54 -37
  2. letta/agent_store/db.py +1 -77
  3. letta/agent_store/storage.py +0 -5
  4. letta/chat_only_agent.py +103 -0
  5. letta/cli/cli.py +0 -1
  6. letta/client/client.py +3 -7
  7. letta/constants.py +1 -0
  8. letta/functions/function_sets/base.py +37 -9
  9. letta/main.py +2 -2
  10. letta/memory.py +4 -82
  11. letta/metadata.py +0 -35
  12. letta/o1_agent.py +7 -2
  13. letta/offline_memory_agent.py +180 -0
  14. letta/orm/__init__.py +3 -0
  15. letta/orm/file.py +1 -1
  16. letta/orm/message.py +66 -0
  17. letta/orm/mixins.py +16 -0
  18. letta/orm/organization.py +1 -0
  19. letta/orm/sqlalchemy_base.py +118 -26
  20. letta/orm/tool.py +22 -1
  21. letta/orm/tools_agents.py +32 -0
  22. letta/personas/examples/offline_memory_persona.txt +4 -0
  23. letta/prompts/system/memgpt_convo_only.txt +14 -0
  24. letta/prompts/system/memgpt_offline_memory.txt +23 -0
  25. letta/prompts/system/memgpt_offline_memory_chat.txt +35 -0
  26. letta/schemas/agent.py +3 -2
  27. letta/schemas/letta_base.py +7 -6
  28. letta/schemas/message.py +1 -7
  29. letta/schemas/tools_agents.py +32 -0
  30. letta/server/rest_api/app.py +11 -0
  31. letta/server/rest_api/routers/v1/agents.py +2 -2
  32. letta/server/rest_api/routers/v1/blocks.py +2 -2
  33. letta/server/server.py +63 -47
  34. letta/server/static_files/assets/index-43ab4d62.css +1 -0
  35. letta/server/static_files/assets/index-4848e3d7.js +40 -0
  36. letta/server/static_files/index.html +2 -2
  37. letta/services/block_manager.py +1 -1
  38. letta/services/message_manager.py +182 -0
  39. letta/services/organization_manager.py +6 -9
  40. letta/services/source_manager.py +1 -1
  41. letta/services/tool_manager.py +2 -2
  42. letta/services/tools_agents_manager.py +94 -0
  43. letta/services/user_manager.py +1 -1
  44. {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/METADATA +2 -1
  45. {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/RECORD +48 -39
  46. letta/agent_store/lancedb.py +0 -177
  47. letta/persistence_manager.py +0 -149
  48. letta/server/static_files/assets/index-3ab03d5b.css +0 -1
  49. letta/server/static_files/assets/index-9fa459a2.js +0 -271
  50. {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/LICENSE +0 -0
  51. {letta_nightly-0.6.1.dev20241205211219.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/WHEEL +0 -0
  52. {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
- else:
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, user_id=user_id, agent_id=agent_state.id))
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.persistence_manager.archival_memory))
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.persistence_manager.recall_memory))
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.persistence_manager.recall_memory.storage.get(id=message_id)
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 a single page of messages
1205
- # TODO: handle stop iteration
1206
- page = next(db_iterator, [])
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
- # return messages in reverse chronological order
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.persistence_manager.archival_memory.storage.get_all_paginated(page_size=count, offset=start)
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.persistence_manager.archival_memory.storage.get_all_cursor(
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.persistence_manager.archival_memory.insert(memory_string=memory_contents, return_ids=True)
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.persistence_manager.archival_memory.storage.get(id=passage_id) for passage_id in passage_ids]
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.persistence_manager.archival_memory.storage.delete({"id": memory_id})
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
- after: Optional[str] = None,
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
- if self.user_manager.get_user_by_id(user_id=user_id) is None:
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
- cursor, records = letta_agent.persistence_manager.recall_memory.storage.get_all_cursor(
1322
- after=after, before=before, limit=limit, order_by=order_by, reverse=reverse
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 not agent_state:
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
- agent_state_user = self.user_manager.get_user_by_id(user_id=agent_state.user_id)
1423
- if agent_state_user.organization_id != actor.organization_id:
1424
- raise ValueError(
1425
- 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?"
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.persistence_manager.archival_memory
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.persistence_manager.recall_memory.storage.get(id=message_id)
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 ValueError:
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 ValueError:
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)}