letta-nightly 0.6.1.dev20241206104246__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 (41) 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/cli/cli.py +0 -1
  5. letta/client/client.py +3 -7
  6. letta/constants.py +1 -0
  7. letta/functions/function_sets/base.py +33 -5
  8. letta/main.py +2 -2
  9. letta/memory.py +4 -82
  10. letta/metadata.py +0 -35
  11. letta/o1_agent.py +7 -2
  12. letta/offline_memory_agent.py +6 -0
  13. letta/orm/__init__.py +2 -0
  14. letta/orm/file.py +1 -1
  15. letta/orm/message.py +66 -0
  16. letta/orm/mixins.py +16 -0
  17. letta/orm/organization.py +1 -0
  18. letta/orm/sqlalchemy_base.py +118 -26
  19. letta/schemas/letta_base.py +7 -6
  20. letta/schemas/message.py +1 -7
  21. letta/server/rest_api/routers/v1/agents.py +2 -2
  22. letta/server/rest_api/routers/v1/blocks.py +2 -2
  23. letta/server/server.py +52 -50
  24. letta/server/static_files/assets/index-43ab4d62.css +1 -0
  25. letta/server/static_files/assets/index-4848e3d7.js +40 -0
  26. letta/server/static_files/index.html +2 -2
  27. letta/services/block_manager.py +1 -1
  28. letta/services/message_manager.py +182 -0
  29. letta/services/organization_manager.py +6 -9
  30. letta/services/source_manager.py +1 -1
  31. letta/services/tool_manager.py +1 -1
  32. letta/services/user_manager.py +1 -1
  33. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/METADATA +1 -1
  34. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/RECORD +37 -37
  35. letta/agent_store/lancedb.py +0 -177
  36. letta/persistence_manager.py +0 -149
  37. letta/server/static_files/assets/index-1b5d1a41.js +0 -271
  38. letta/server/static_files/assets/index-56a3f8c6.css +0 -1
  39. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/LICENSE +0 -0
  40. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/WHEEL +0 -0
  41. {letta_nightly-0.6.1.dev20241206104246.dist-info → letta_nightly-0.6.1.dev20241207104149.dist-info}/entry_points.txt +0 -0
letta/server/server.py CHANGED
@@ -77,14 +77,15 @@ from letta.schemas.user import User
77
77
  from letta.services.agents_tags_manager import AgentsTagsManager
78
78
  from letta.services.block_manager import BlockManager
79
79
  from letta.services.blocks_agents_manager import BlocksAgentsManager
80
- from letta.services.tools_agents_manager import ToolsAgentsManager
81
80
  from letta.services.job_manager import JobManager
81
+ from letta.services.message_manager import MessageManager
82
82
  from letta.services.organization_manager import OrganizationManager
83
83
  from letta.services.per_agent_lock_manager import PerAgentLockManager
84
84
  from letta.services.sandbox_config_manager import SandboxConfigManager
85
85
  from letta.services.source_manager import SourceManager
86
86
  from letta.services.tool_execution_sandbox import ToolExecutionSandbox
87
87
  from letta.services.tool_manager import ToolManager
88
+ from letta.services.tools_agents_manager import ToolsAgentsManager
88
89
  from letta.services.user_manager import UserManager
89
90
  from letta.utils import create_random_username, get_utc_time, json_dumps, json_loads
90
91
 
@@ -260,6 +261,7 @@ class SyncServer(Server):
260
261
  self.agents_tags_manager = AgentsTagsManager()
261
262
  self.sandbox_config_manager = SandboxConfigManager(tool_settings)
262
263
  self.blocks_agents_manager = BlocksAgentsManager()
264
+ self.message_manager = MessageManager()
263
265
  self.tools_agents_manager = ToolsAgentsManager()
264
266
  self.job_manager = JobManager()
265
267
 
@@ -414,7 +416,7 @@ class SyncServer(Server):
414
416
  agent = OfflineMemoryAgent(agent_state=agent_state, interface=interface, user=actor)
415
417
  elif agent_state.agent_type == AgentType.chat_only_agent:
416
418
  agent = ChatOnlyAgent(agent_state=agent_state, interface=interface, user=actor)
417
- else:
419
+ else:
418
420
  raise ValueError(f"Invalid agent type {agent_state.agent_type}")
419
421
 
420
422
  # Rebuild the system prompt - may be linked to new blocks now
@@ -422,7 +424,7 @@ class SyncServer(Server):
422
424
 
423
425
  # Persist to agent
424
426
  save_agent(agent, self.ms)
425
- return agent
427
+ return agent
426
428
 
427
429
  def _step(
428
430
  self,
@@ -518,12 +520,7 @@ class SyncServer(Server):
518
520
  letta_agent.interface.print_messages_raw(letta_agent.messages)
519
521
 
520
522
  elif command.lower() == "memory":
521
- ret_str = (
522
- f"\nDumping memory contents:\n"
523
- + f"\n{str(letta_agent.agent_state.memory)}"
524
- + f"\n{str(letta_agent.persistence_manager.archival_memory)}"
525
- + f"\n{str(letta_agent.persistence_manager.recall_memory)}"
526
- )
523
+ ret_str = f"\nDumping memory contents:\n" + f"\n{str(letta_agent.agent_state.memory)}" + f"\n{str(letta_agent.archival_memory)}"
527
524
  return ret_str
528
525
 
529
526
  elif command.lower() == "pop" or command.lower().startswith("pop "):
@@ -625,7 +622,6 @@ class SyncServer(Server):
625
622
  # Convert to a Message object
626
623
  if timestamp:
627
624
  message = Message(
628
- user_id=user_id,
629
625
  agent_id=agent_id,
630
626
  role="user",
631
627
  text=packaged_user_message,
@@ -633,7 +629,6 @@ class SyncServer(Server):
633
629
  )
634
630
  else:
635
631
  message = Message(
636
- user_id=user_id,
637
632
  agent_id=agent_id,
638
633
  role="user",
639
634
  text=packaged_user_message,
@@ -672,7 +667,6 @@ class SyncServer(Server):
672
667
 
673
668
  if timestamp:
674
669
  message = Message(
675
- user_id=user_id,
676
670
  agent_id=agent_id,
677
671
  role="system",
678
672
  text=packaged_system_message,
@@ -680,7 +674,6 @@ class SyncServer(Server):
680
674
  )
681
675
  else:
682
676
  message = Message(
683
- user_id=user_id,
684
677
  agent_id=agent_id,
685
678
  role="system",
686
679
  text=packaged_system_message,
@@ -743,7 +736,6 @@ class SyncServer(Server):
743
736
  # Create the Message object
744
737
  message_objects.append(
745
738
  Message(
746
- user_id=user_id,
747
739
  agent_id=agent_id,
748
740
  role=message.role,
749
741
  text=message.text,
@@ -876,7 +868,7 @@ class SyncServer(Server):
876
868
  else:
877
869
  raise ValueError(f"Invalid message role: {message.role}")
878
870
 
879
- 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))
880
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]
881
873
  else:
882
874
  init_messages = None
@@ -1160,11 +1152,11 @@ class SyncServer(Server):
1160
1152
 
1161
1153
  def get_archival_memory_summary(self, agent_id: str) -> ArchivalMemorySummary:
1162
1154
  agent = self.load_agent(agent_id=agent_id)
1163
- return ArchivalMemorySummary(size=len(agent.persistence_manager.archival_memory))
1155
+ return ArchivalMemorySummary(size=len(agent.archival_memory))
1164
1156
 
1165
1157
  def get_recall_memory_summary(self, agent_id: str) -> RecallMemorySummary:
1166
1158
  agent = self.load_agent(agent_id=agent_id)
1167
- return RecallMemorySummary(size=len(agent.persistence_manager.recall_memory))
1159
+ return RecallMemorySummary(size=len(agent.message_manager))
1168
1160
 
1169
1161
  def get_in_context_message_ids(self, agent_id: str) -> List[str]:
1170
1162
  """Get the message ids of the in-context messages in the agent's memory"""
@@ -1182,7 +1174,7 @@ class SyncServer(Server):
1182
1174
  """Get a single message from the agent's memory"""
1183
1175
  # Get the agent object (loaded in memory)
1184
1176
  agent = self.load_agent(agent_id=agent_id)
1185
- 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)
1186
1178
  return message
1187
1179
 
1188
1180
  def get_agent_messages(
@@ -1213,14 +1205,16 @@ class SyncServer(Server):
1213
1205
 
1214
1206
  else:
1215
1207
  # need to access persistence manager for additional messages
1216
- db_iterator = letta_agent.persistence_manager.recall_memory.storage.get_all_paginated(page_size=count, offset=start)
1217
1208
 
1218
- # get a single page of messages
1219
- # TODO: handle stop iteration
1220
- 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
+ )
1221
1216
 
1222
- # return messages in reverse chronological order
1223
- messages = sorted(page, key=lambda x: x.created_at, reverse=True)
1217
+ messages = page
1224
1218
  assert all(isinstance(m, Message) for m in messages)
1225
1219
 
1226
1220
  ## Convert to json
@@ -1243,7 +1237,7 @@ class SyncServer(Server):
1243
1237
  letta_agent = self.load_agent(agent_id=agent_id)
1244
1238
 
1245
1239
  # iterate over records
1246
- 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)
1247
1241
 
1248
1242
  # get a single page of messages
1249
1243
  page = next(db_iterator, [])
@@ -1268,7 +1262,7 @@ class SyncServer(Server):
1268
1262
  letta_agent = self.load_agent(agent_id=agent_id)
1269
1263
 
1270
1264
  # iterate over recorde
1271
- cursor, records = letta_agent.persistence_manager.archival_memory.storage.get_all_cursor(
1265
+ cursor, records = letta_agent.archival_memory.storage.get_all_cursor(
1272
1266
  after=after, before=before, limit=limit, order_by=order_by, reverse=reverse
1273
1267
  )
1274
1268
  return records
@@ -1283,14 +1277,14 @@ class SyncServer(Server):
1283
1277
  letta_agent = self.load_agent(agent_id=agent_id)
1284
1278
 
1285
1279
  # Insert into archival memory
1286
- 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)
1287
1281
 
1288
1282
  # Update the agent
1289
1283
  # TODO: should this update the system prompt?
1290
1284
  save_agent(letta_agent, self.ms)
1291
1285
 
1292
1286
  # TODO: this is gross, fix
1293
- 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]
1294
1288
 
1295
1289
  def delete_archival_memory(self, user_id: str, agent_id: str, memory_id: str):
1296
1290
  if self.user_manager.get_user_by_id(user_id=user_id) is None:
@@ -1305,7 +1299,7 @@ class SyncServer(Server):
1305
1299
 
1306
1300
  # Delete by ID
1307
1301
  # TODO check if it exists first, and throw error if not
1308
- letta_agent.persistence_manager.archival_memory.storage.delete({"id": memory_id})
1302
+ letta_agent.archival_memory.storage.delete({"id": memory_id})
1309
1303
 
1310
1304
  # TODO: return archival memory
1311
1305
 
@@ -1313,17 +1307,15 @@ class SyncServer(Server):
1313
1307
  self,
1314
1308
  user_id: str,
1315
1309
  agent_id: str,
1316
- after: Optional[str] = None,
1317
- before: Optional[str] = None,
1310
+ cursor: Optional[str] = None,
1318
1311
  limit: Optional[int] = 100,
1319
- order_by: Optional[str] = "created_at",
1320
- order: Optional[str] = "asc",
1321
1312
  reverse: Optional[bool] = False,
1322
1313
  return_message_object: bool = True,
1323
1314
  assistant_message_tool_name: str = constants.DEFAULT_MESSAGE_TOOL,
1324
1315
  assistant_message_tool_kwarg: str = constants.DEFAULT_MESSAGE_TOOL_KWARG,
1325
1316
  ) -> Union[List[Message], List[LettaMessage]]:
1326
- 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:
1327
1319
  raise ValueError(f"User user_id={user_id} does not exist")
1328
1320
  if self.ms.get_agent(agent_id=agent_id, user_id=user_id) is None:
1329
1321
  raise ValueError(f"Agent agent_id={agent_id} does not exist")
@@ -1332,8 +1324,12 @@ class SyncServer(Server):
1332
1324
  letta_agent = self.load_agent(agent_id=agent_id)
1333
1325
 
1334
1326
  # iterate over records
1335
- cursor, records = letta_agent.persistence_manager.recall_memory.storage.get_all_cursor(
1336
- 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,
1337
1333
  )
1338
1334
 
1339
1335
  assert all(isinstance(m, Message) for m in records)
@@ -1353,7 +1349,7 @@ class SyncServer(Server):
1353
1349
  records = records[::-1]
1354
1350
 
1355
1351
  return records
1356
-
1352
+
1357
1353
  def get_server_config(self, include_defaults: bool = False) -> dict:
1358
1354
  """Return the base config"""
1359
1355
 
@@ -1425,19 +1421,25 @@ class SyncServer(Server):
1425
1421
  self.agents_tags_manager.delete_all_tags_from_agent(agent_id=agent_id, actor=actor)
1426
1422
  self.blocks_agents_manager.remove_all_agent_blocks(agent_id=agent_id)
1427
1423
 
1428
- if self.ms.get_agent(agent_id=agent_id, user_id=user_id) is None:
1429
- raise ValueError(f"Agent agent_id={agent_id} does not exist")
1430
-
1431
1424
  # Verify that the agent exists and belongs to the org of the user
1432
1425
  agent_state = self.ms.get_agent(agent_id=agent_id, user_id=user_id)
1433
- if not agent_state:
1426
+ if agent_state is None:
1434
1427
  raise ValueError(f"Could not find agent_id={agent_id} under user_id={user_id}")
1435
1428
 
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
- )
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}")
1441
1443
 
1442
1444
  # First, if the agent is in the in-memory cache we should remove it
1443
1445
  # List of {'user_id': user_id, 'agent_id': agent_id, 'agent': agent_obj} dicts
@@ -1582,7 +1584,7 @@ class SyncServer(Server):
1582
1584
 
1583
1585
  # delete all Passage objects with source_id==source_id from agent's archival memory
1584
1586
  agent = self.load_agent(agent_id=agent_id)
1585
- archival_memory = agent.persistence_manager.archival_memory
1587
+ archival_memory = agent.archival_memory
1586
1588
  archival_memory.storage.delete({"source_id": source_id})
1587
1589
 
1588
1590
  # delete agent-source mapping
@@ -1661,7 +1663,7 @@ class SyncServer(Server):
1661
1663
  """Get a single message from the agent's memory"""
1662
1664
  # Get the agent object (loaded in memory)
1663
1665
  letta_agent = self.load_agent(agent_id=agent_id)
1664
- 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)
1665
1667
  save_agent(letta_agent, self.ms)
1666
1668
  return message
1667
1669
 
@@ -1705,7 +1707,7 @@ class SyncServer(Server):
1705
1707
 
1706
1708
  try:
1707
1709
  return self.user_manager.get_user_by_id(user_id=user_id)
1708
- except ValueError:
1710
+ except NoResultFound:
1709
1711
  raise HTTPException(status_code=404, detail=f"User with id {user_id} not found")
1710
1712
 
1711
1713
  def get_organization_or_default(self, org_id: Optional[str]) -> Organization:
@@ -1715,7 +1717,7 @@ class SyncServer(Server):
1715
1717
 
1716
1718
  try:
1717
1719
  return self.organization_manager.get_organization_by_id(org_id=org_id)
1718
- except ValueError:
1720
+ except NoResultFound:
1719
1721
  raise HTTPException(status_code=404, detail=f"Organization with id {org_id} not found")
1720
1722
 
1721
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)}