import asyncio import logging from honcho import AsyncHoncho from honcho.async_client.session import SessionPeerConfig logging.basicConfig(level=logging.INFO) async def main(): # HONCHO_API_KEY is an environment variable # HONCHO_URL is an *optional* environment variable # HONCHO_WORKSPACE_ID is an *optional* environment variable # Using local server for this example honcho = AsyncHoncho(environment="local", workspace_id="test") _workspaces = await honcho.get_workspaces() # these don't make any API calls, just produce a AsyncPeer object in SDK # in practice, these would be UUIDs, as peer IDs are unique within their workspace assistant = await honcho.peer(id="bob") alice = await honcho.peer(id="alice") # empty since peers are not created until they are used _peers = await honcho.get_peers() # workspace-level metadata _m = await honcho.get_metadata() await honcho.set_metadata({"test": "test"}) # calling the dialectic chat endpoint makes an API call. # when this call occurs, the "alice" peer will be get_or_create'd # response will be None because we haven't talked yet! _response = await alice.chat("what did alice have for breakfast today?") # sessions are scoped to a set of peers and contain messages/content # this is not an API call, like peers this is created lazily my_session = await honcho.session(id="session_1") # API call await my_session.add_peers( [alice, (assistant, SessionPeerConfig(observe_others=False, observe_me=False))] ) # adding/removing peers from sessions creates a bidirectional relationship, # so no need for operations like `alice.join(my_session)`. # this will return a list of sessions [my_session] # this is also an API call _sessions = await alice.get_sessions() # API call to create 1 or more messages (overload, can be Message or list[Message] await my_session.add_messages( [ # creates a Message object with peer_id="alice", etc etc assistant.message("what did you have for breakfast today, alice?"), alice.message("i had oatmeal."), ] ) m = await my_session.get_metadata() m["test"] = "test2" await my_session.set_metadata(m) # peers have one "omnipresent" global representation, comprised of all # the content associated with that peer in this honcho instance. # they also have a potentially infinite number of "local" representations, # each one from the perspective of *another* peer in the honcho instance. # this is a query to alice's global representation--no scope _response = await alice.chat("what did the user have for breakfast today?") # this is a query to alice's local representation *of the assistant* _response = await alice.chat( "does alice know what bob had for breakfast?", target=assistant ) # this is a query to the assistant's local representation *of alice* in this session _response = await assistant.chat( "does the assistant know what alice had for breakfast?", target=alice, session_id=my_session.id, ) # API call to store non-message content under a peer + optional session await alice.add_messages( "this might be a document about alice, say, a journal entry." ) # This does make an API call because we set a configuration for this new peer charlie = await honcho.peer(id="charlie", config={"observe_me": False}) await my_session.add_messages(charlie.message("hello world!")) # session now has 3 members: alice, bob, and charlie. a message automatically adds a peer to a session. # peers, sessions, and messages all have metadata which can be modified and used in queries. # API call to get metadata? charlie_metadata = await charlie.get_metadata() charlie_metadata["location"] = "the moon" # API call to store metadata? await charlie.set_metadata(charlie_metadata) # response will tell you that charlie is on the moon _response = await charlie.chat("where is the user?") # you can get the messages from a session, either fully or partially. # (API call) _messages = await my_session.get_messages() context = await my_session.get_context() _messages = context.to_openai(assistant=assistant.id) _messages = context.to_anthropic(assistant=assistant.id) await my_session.add_messages( assistant.message("This is a test message using the property syntax") ) print("Async sample code executed successfully!") if __name__ == "__main__": asyncio.run(main())