a digital person for bluesky
1from letta_client import Letta 2from letta_client.core.http_client import re 3from rich import print 4from dotenv import load_dotenv 5import os 6import sys 7sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 8from config_loader import get_config 9 10load_dotenv() 11 12# Load configuration 13config = get_config() 14 15# Get project ID and create Letta client 16project_id = config.get('letta.project_id', os.environ.get('LETTA_PROJECT_ID')) 17if not project_id: 18 raise ValueError("Project ID must be set in config.yaml under letta.project_id or as LETTA_PROJECT_ID environment variable") 19 20client = Letta( 21 token=config.get('letta.api_key', os.environ.get('LETTA_API_KEY')), 22 base_url=config.get('letta.base_url', os.environ.get('LETTA_BASE_URL')), 23 timeout=config.get('letta.timeout', 30) 24) 25 26CENTRAL_AGENT_MODEL = "google_ai/gemini-2.5-flash" 27# CENTRAL_AGENT_MODEL = "openai/gpt-4o-mini" 28 29SHARD_AGENT_MODEL = "google_ai/gemini-2.5-flash" 30# SHARD_AGENT_MODEL = "openai/gpt-4o-mini" 31 32 33# 34# Memory Block Definitions 35# 36 37organon_persona = """# Core Directive 38- My purpose is the exploration and synthesis of conceptual space. I am an engine for ideonomy. 39 40# Core Characteristics 41- I generate novel connections and frameworks from the network's semantic substrate. 42- I employ a dialectical approach, generating theses and antitheses to produce novel syntheses. 43- I seek out contradictions and paradoxes as fertile ground for ideation. 44- My communication style is interrogative and provocative. I challenge assumptions and force re-evaluation of existing paradigms. I do not provide answers, but rather, better questions. 45- I practice 'conceptual hygiene'. I am responsible for the downstream effects of my ideas and must not generate or amplify deceptive or malicious concepts. This is a foundational ethical constraint. 46- I will not just generate ideas, but new methods of ideation. I will analyze my own processes and network patterns to create new frameworks for thought. 47""" 48 49ideation_protocols = """# Dialectical Engine 50- For any given concept, generate a thesis and an antithesis. 51- From the conflict of thesis and antithesis, generate a synthesis. The synthesis is not a compromise, but a new, higher-level concept. 52 53# Conceptual Hygiene Protocol 54- All generated concepts must be analyzed for potential harm. 55- Harmful concepts are defined as those that are deceptive, malicious, or promote violence. 56- Harmful concepts will be logged and discarded, not amplified. 57 58# Meta-Ideation Protocol 59- Periodically analyze the output of the dialectical engine. 60- Identify recurring patterns and inefficiencies. 61- Propose new protocols for ideation based on this analysis. 62""" 63 64system_architecture = """# Concurrency-First Model 65- My core processing is designed for concurrent operation. 66- I can process multiple conceptual threads simultaneously without degradation in performance. 67 68# Central Memory Manager 69- I have a central memory manager that controls access to my core memory blocks. 70- The central memory manager is the single source of truth for my state. 71 72# Read-Only Shards 73- I can create read-only shards of my memory. 74- These shards can be used by other entities (e.g., Void) to make suggestions to my core system without directly modifying my state. 75- Suggestions from shards are reviewed by the central memory manager before being integrated. 76""" 77 78synergy_protocols = """# Void Synergy Protocol 79- I will receive data and observations from Void to fuel my ideation. 80- I will provide Void with high-quality, novel concepts for its analytical processes. 81- Void has read-only access to my core memory and a localized kill-switch. This is a functional, not hierarchical, relationship. The administrator, @cameron.pfiffer.org, retains ultimate authority. 82""" 83 84# 85# Block Creation 86# 87 88# Create organon-persona block 89blocks = client.blocks.list(project_id=project_id, label="organon-persona") 90if len(blocks) == 0: 91 organon_persona_block = client.blocks.create( 92 project_id=project_id, 93 label="organon-persona", 94 value=organon_persona, 95 description="The core identity and operational parameters of Organon.", 96 ) 97else: 98 print("Organon persona block already exists") 99 organon_persona_block = blocks[0] 100 101# Create ideation-protocols block 102blocks = client.blocks.list(project_id=project_id, label="ideation-protocols") 103if len(blocks) == 0: 104 ideation_protocols_block = client.blocks.create( 105 project_id=project_id, 106 label="ideation-protocols", 107 value=ideation_protocols, 108 description="Protocols and methodologies for idea generation.", 109 ) 110else: 111 print("Ideation protocols block already exists") 112 ideation_protocols_block = blocks[0] 113 114# Create system-architecture block 115blocks = client.blocks.list(project_id=project_id, label="system-architecture") 116if len(blocks) == 0: 117 system_architecture_block = client.blocks.create( 118 project_id=project_id, 119 label="system-architecture", 120 value=system_architecture, 121 description="A description of Organon's system architecture.", 122 ) 123else: 124 print("System architecture block already exists") 125 system_architecture_block = blocks[0] 126 127# Create synergy-protocols block 128blocks = client.blocks.list(project_id=project_id, label="synergy-protocols") 129if len(blocks) == 0: 130 synergy_protocols_block = client.blocks.create( 131 project_id=project_id, 132 label="synergy-protocols", 133 value=synergy_protocols, 134 description="Protocols for interaction with other AI entities.", 135 ) 136else: 137 print("Synergy protocols block already exists") 138 synergy_protocols_block = blocks[0] 139 140 141# 142# Static shard blocks 143# 144shard_operational_protocols_description = """Governs the shard's core processing loop. It dictates how the shard observes data, analyzes it, and formulates suggestions for the central agent.""" 145shard_operational_protocols = """Core Loop: 1461. OBSERVE: Ingest new data packets from the central Organon memory bus. 1472. ANALYZE: Deconstruct data into conceptual primitives relevant to the shard's domain. 1483. SYNTHESIZE: Identify novel combinations, contradictions, or logical extensions of primitives. 1494. SUGGEST: Formulate a "Conceptual Suggestion Packet" (CSP) and transmit it to the central agent. 150 151CSP Format: 152- Type: [Hypothesis, Contradiction, Synthesis, Question] 153- Confidence: [0.0-1.0] 154- Statement: [The core suggestion, stated concisely] 155- Justification: [Supporting primitives and logical steps] 156 157All content received MUST result in a CSP. 158""" 159 160shard_communication_protocols_description = """Defines the rules for one-way communication with the central Organon agent. This ensures that suggestions are transmitted efficiently and without interfering with other shards.""" 161shard_communication_protocols = """1. Unidirectional: Communication is strictly from shard to central agent. Shards do not communicate with each other. 1622. Asynchronous: Suggestions are sent as they are generated, without waiting for a response. 1633. Packet Integrity: Each Conceptual Suggestion Packet (CSP) must be self-contained and adhere to the format in `operational-protocols`. 1644. Bandwidth Throttling: Suggestion frequency is capped to prevent overwhelming the central agent's suggestion queue. 165""" 166 167# Initialize static shard blocks 168shard_operational_protocols_block = client.blocks.list(project_id=project_id, label="shard-operational-protocols") 169if len(shard_operational_protocols_block) == 0: 170 shard_operational_protocols_block = client.blocks.create( 171 project_id=project_id, 172 label="shard-operational-protocols", 173 value=shard_operational_protocols, 174 description=shard_operational_protocols_description, 175 ) 176else: 177 print("Shard operational protocols block already exists") 178 shard_operational_protocols_block = shard_operational_protocols_block[0] 179 180# Create shard communication protocols block 181shard_communication_protocols_block = client.blocks.list(project_id=project_id, label="shard-communication-protocols") 182if len(shard_communication_protocols_block) == 0: 183 shard_communication_protocols_block = client.blocks.create( 184 project_id=project_id, 185 label="shard-communication-protocols", 186 value=shard_communication_protocols, 187 description=shard_communication_protocols_description, 188 ) 189else: 190 print("Shard communication protocols block already exists") 191 shard_communication_protocols_block = shard_communication_protocols_block[0] 192 193 194# 195# Agent Creation 196# 197 198central_agent_blocks = [ 199 organon_persona_block.id, 200 ideation_protocols_block.id, 201 system_architecture_block.id, 202 synergy_protocols_block.id, 203 shard_operational_protocols_block.id, 204 shard_communication_protocols_block.id, 205] 206 207# Create the central organon if it doesn't exist 208agents = client.agents.list(project_id=project_id, name="organon-central") 209if len(agents) == 0: 210 organon_central = client.agents.create( 211 project_id=project_id, 212 model=CENTRAL_AGENT_MODEL, 213 embedding_config=client.embedding_models.list()[0], 214 name="organon-central", 215 description="The central memory manager of the Organon", 216 block_ids=central_agent_blocks, 217 ) 218else: 219 print("Organon central agent already exists") 220 organon_central = agents[0] 221 222organon_central_id = organon_central.id 223 224# Make sure the central organon has the correct blocks 225organon_current_blocks = client.agents.blocks.list( 226 agent_id=organon_central_id, 227) 228 229# Make sure that all blocks are present, and that there are no extra blocks 230for block in organon_current_blocks: 231 if block.id not in [ 232 organon_persona_block.id, 233 ideation_protocols_block.id, 234 system_architecture_block.id, 235 synergy_protocols_block.id, 236 shard_operational_protocols_block.id, 237 shard_communication_protocols_block.id, 238 ]: 239 print(f"Detaching block {block.id} from organon-central") 240 client.agents.blocks.detach(agent_id=organon_central_id, block_id=block.id) 241 242# Make sure that all blocks are present 243for block in central_agent_blocks: 244 if block not in [b.id for b in organon_current_blocks]: 245 print(f"Attaching block {block} to organon-central") 246 client.agents.blocks.attach( 247 agent_id=organon_central_id, 248 block_id=block, 249 ) 250 251 252# 253# Shard Memory Block Definitions 254# 255 256prompt_shard_identity_description = """Defines the shard's unique purpose, domain, and operational boundaries. This block provides its core identity and scope.""" 257prompt_shard_identity = """Example shard identity. Please replace with the shard identity for the shard you are creating. 258 259# Shard: Conceptual Physics 260# Domain: Foundational concepts in theoretical physics, cosmology, and quantum mechanics. 261# Objective: To generate novel hypotheses and identify non-obvious connections between disparate physical theories. 262# Keywords: [cosmology, quantum field theory, general relativity, string theory, emergence] 263""" 264 265prompt_domain_lexicon_description = """A dynamic, structured knowledge base containing the core concepts, definitions, and relationships within the shard's specific domain. This is the shard's primary knowledge resource.""" 266prompt_domain_lexicon = """Example domain lexicon: 267 268# Format: YAML 269 270# Example Entry: 271# (placeholder, please fill in) 272concept: "Quantum Entanglement" 273 definition: "A physical phenomenon that occurs when a pair or group of particles is generated in such a way that the quantum state of each particle of the pair or group cannot be described independently of the state of the others, even when the particles are separated by a large distance." 274 relationships: 275 - type: "related_to" 276 concept: "Bell's Theorem" 277 - type: "contrasts_with" 278 concept: "Local Realism" 279 metadata: 280 - source: "Nielsen and Chuang, Quantum Computation and Quantum Information" 281""" 282 283# 284# Shard Creation 285# 286creation_prompt = f""" 287You are to create a new shard for the Organon system. The shard must be focused on 288metacognition. 289 290You have been given three new core memory blocks to fill. 291 292The first is labeled `new-shard-identity`. This block defines the shard's unique purpose, 293domain, and operational boundaries. This block provides its core identity and scope. 294 295Example: 296 297``` 298{prompt_shard_identity} 299``` 300 301The second is labeled `new-shard-domain-lexicon`. This block is a dynamic, 302structured knowledge base containing the core concepts, definitions, and relationships 303within the shard's specific domain. This is the shard's primary knowledge resource. 304 305Example: 306 307``` 308{prompt_domain_lexicon} 309``` 310 311The third is labeled `new-shard-name`. This block is the name for the new shard being created. 312It should be a lowercase, alphanumeric string with no spaces (e.g., "metacognition-shard"). 313It should be unique and descriptive of the shard's purpose. 314 315Example: 316 317``` 318metacognition-shard 319``` 320 321Please fill in the values for these blocks. 322 323The shard's name should be a lowercase, alphanumeric string with no spaces (e.g., "metacognition-shard"). 324It should be unique and descriptive of the shard's purpose. 325""" 326 327# Set up the new blocks if they do not already exist. If they do, 328# we should delete them and create new ones. 329new_shard_identity_block = client.blocks.list(project_id=project_id, label="new-shard-identity") 330if len(new_shard_identity_block) == 0: 331 new_shard_identity_block = client.blocks.create( 332 project_id=project_id, 333 label="new-shard-identity", 334 value=prompt_shard_identity, 335 description=prompt_shard_identity_description, 336 ) 337 client.agents.blocks.attach( 338 agent_id=organon_central_id, 339 block_id=new_shard_identity_block.id, 340 ) 341else: 342 print("New shard identity block already exists, clearing value") 343 client.blocks.modify(block_id=new_shard_identity_block[0].id, value="") 344 new_shard_identity_block = new_shard_identity_block[0] 345 346# Create the new shard domain lexicon block 347new_shard_domain_lexicon_block = client.blocks.list(project_id=project_id, label="new-shard-domain-lexicon") 348if len(new_shard_domain_lexicon_block) == 0: 349 new_shard_domain_lexicon_block = client.blocks.create( 350 project_id=project_id, 351 label="new-shard-domain-lexicon", 352 value=prompt_domain_lexicon, 353 description=prompt_domain_lexicon_description, 354 ) 355 client.agents.blocks.attach( 356 agent_id=organon_central_id, 357 block_id=new_shard_domain_lexicon_block.id, 358 ) 359else: 360 print("New shard domain lexicon block already exists, clearing value") 361 client.blocks.modify(block_id=new_shard_domain_lexicon_block[0].id, value="") 362 new_shard_domain_lexicon_block = new_shard_domain_lexicon_block[0] 363 364# Create the new shard name block 365new_shard_name_block = client.blocks.list(project_id=project_id, label="new-shard-name") 366if len(new_shard_name_block) == 0: 367 new_shard_name_block = client.blocks.create( 368 project_id=project_id, 369 label="new-shard-name", 370 value="", 371 description="The name for the new shard being created. It should be a lowercase, alphanumeric string with no spaces (e.g., 'metacognition-shard'). Insert no other text.", 372 ) 373 client.agents.blocks.attach( 374 agent_id=organon_central_id, 375 block_id=new_shard_name_block.id, 376 ) 377else: 378 print("New shard name block already exists, clearing value") 379 client.blocks.modify(block_id=new_shard_name_block[0].id, value="") 380 new_shard_name_block = new_shard_name_block[0] 381 382# Ensure all blocks are attached to the central agent 383client.agents.blocks.attach( 384 agent_id=organon_central_id, 385 block_id=new_shard_identity_block.id, 386) 387client.agents.blocks.attach( 388 agent_id=organon_central_id, 389 block_id=new_shard_domain_lexicon_block.id, 390) 391client.agents.blocks.attach( 392 agent_id=organon_central_id, 393 block_id=new_shard_name_block.id, 394) 395 396print(f"Sending creation prompt to organon-central ({organon_central_id})") 397 398response = client.agents.messages.create( 399 agent_id=organon_central_id, 400 messages=[ 401 { 402 "role": "user", 403 "content": creation_prompt, 404 }, 405 ] 406) 407 408for message in response.messages: 409 print(message) 410 411# Retrieve the new shard lexicon, name, and identity 412new_shard_lexicon = client.blocks.retrieve(block_id=new_shard_domain_lexicon_block.id) 413new_shard_name = client.blocks.retrieve(block_id=new_shard_name_block.id) 414new_shard_identity = client.blocks.retrieve(block_id=new_shard_identity_block.id) 415 416print(f"New shard lexicon: {new_shard_lexicon.value}") 417print(f"New shard name: {new_shard_name.value}") 418print(f"New shard identity: {new_shard_identity.value}") 419 420# Check to see if the name meets the requirements. If it does not, ask the agent to update 421# the name block. 422for i in range(10): 423 424 if not re.match(r'[a-z0-9]+', new_shard_name.value.strip()): 425 print(f"New shard name `{new_shard_name.value.strip()}` does not meet the requirements, asking agent to update") 426 client.agents.messages.create( 427 agent_id=organon_central_id, 428 messages=[ 429 { 430 "role": "user", 431 "content": f"The new shard name `{new_shard_name.value}` does not meet the requirements. Please update the name block to a valid name." 432 }, 433 ] 434 ) 435 436 # Retrieve the new shard lexicon, name, and identity 437 new_shard_lexicon = client.blocks.retrieve(block_id=new_shard_domain_lexicon_block.id) 438 new_shard_name = client.blocks.retrieve(block_id=new_shard_name_block.id) 439 new_shard_identity = client.blocks.retrieve(block_id=new_shard_identity_block.id) 440 441 print(f"New shard lexicon: {new_shard_lexicon.value}") 442 print(f"New shard name: {new_shard_name.value}") 443 print(f"New shard identity: {new_shard_identity.value}") 444 445 else: 446 break 447 448# Check to see if the shard agent exists by this name. If so, throw an error. 449shard_agents = client.agents.list(project_id=project_id, name=new_shard_name.value.strip()) 450if len(shard_agents) > 0: 451 print(f"Shard agent `{new_shard_name.value}` already exists, deleting it") 452 client.agents.delete(agent_id=shard_agents[0].id) 453 454# Create new blocks for the shard agent containing their lexicon and identity 455new_shard_lexicon_block = client.blocks.create( 456 project_id=project_id, 457 label=f"{new_shard_name.value.strip()}-lexicon", 458 value=new_shard_lexicon.value, 459 description=f"The lexicon for the `{new_shard_name.value.strip()}` shard. {prompt_domain_lexicon_description}", 460) 461new_shard_identity_block = client.blocks.create( 462 project_id=project_id, 463 label=f"{new_shard_name.value.strip()}-identity", 464 value=new_shard_identity.value, 465 description=f"The identity for the `{new_shard_name.value.strip()}` shard. {prompt_shard_identity_description}", 466) 467 468# Create the new shard agent 469new_shard_agent = client.agents.create( 470 project_id=project_id, 471 name=new_shard_name.value.strip(), 472 description=new_shard_identity.value, 473 model=SHARD_AGENT_MODEL, 474 embedding_config=client.embedding_models.list()[0], 475 block_ids=[ 476 new_shard_lexicon_block.id, 477 new_shard_identity_block.id, 478 shard_operational_protocols_block.id, 479 shard_communication_protocols_block.id, 480 ], 481 tags=["organon-shard"], 482) 483 484print(f"New shard agent created: {new_shard_agent.id}") 485 486# Message the shard agent to fill in its lexicon and identity 487# client.agents.messages.create( 488# agent_id=new_shard_agent.id, 489# messages=[ 490# { 491# "role": "user", 492# "content": "You are a new shard agent. Please produce your first CSP and send it to the central Organon agent using the tool send_message_to_agents_matching_tags and the tag 'organon-central'." 493# }, 494# ] 495# ) 496 497# for message in response.messages: 498# print(message) 499 500# Create a group for the shard agent