From c2dc498b1cd166bd1426f7d3aa3cee47a4eb406b Mon Sep 17 00:00:00 2001 From: Vadym Barda Date: Fri, 4 Oct 2024 16:58:22 -0400 Subject: [PATCH] docs: clean up memory docs (#2000) --- ...3-a466-46ad-aafe-2b870831057e.msgpack.zlib | 1 + ...b-d730-48bd-9652-983812fd7811.msgpack.zlib | 1 + ...0-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib | 1 + ...6-11d5-40e1-8567-361e5bef8917.msgpack.zlib | 2 +- .../persistence_0d49697f.msgpack.zlib | 1 - ...8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib | 2 +- ...3-7101-43ab-a811-592e222b9580.msgpack.zlib | 1 + ...d-6489-4e03-8c23-fd0530278455.msgpack.zlib | 1 - ...0-a5a6-4697-8115-322242f197b5.msgpack.zlib | 2 +- ...9-3a73-4033-bfb4-5093ac1f5d7f.msgpack.zlib | 1 - ...f-d68d-456c-b0b7-5eb94fb89ca6.msgpack.zlib | 1 - ...3-a466-46ad-aafe-2b870831057e.msgpack.zlib | 1 + ...b-d730-48bd-9652-983812fd7811.msgpack.zlib | 1 + ...0-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib | 1 + ...5-ff8b-4d17-beb7-2420c0575dd9.msgpack.zlib | 1 - .../shared-state_f9bf2c15.msgpack.zlib | 1 - .../how-tos/cross-thread-persistence.ipynb | 358 ++++++++++++++ docs/docs/how-tos/index.md | 17 +- docs/docs/how-tos/memory/shared-state.ipynb | 465 ------------------ docs/docs/how-tos/persistence.ipynb | 453 ++++------------- docs/mkdocs.yml | 11 +- 21 files changed, 493 insertions(+), 830 deletions(-) create mode 100644 docs/cassettes/cross-thread-persistence_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib create mode 100644 docs/cassettes/cross-thread-persistence_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib create mode 100644 docs/cassettes/cross-thread-persistence_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib delete mode 100644 docs/cassettes/persistence_0d49697f.msgpack.zlib create mode 100644 docs/cassettes/persistence_6fa9a5e3-7101-43ab-a811-592e222b9580.msgpack.zlib delete mode 100644 docs/cassettes/persistence_8578a66d-6489-4e03-8c23-fd0530278455.msgpack.zlib delete mode 100644 docs/cassettes/shared-state_18bd8679-3a73-4033-bfb4-5093ac1f5d7f.msgpack.zlib delete mode 100644 docs/cassettes/shared-state_5f36c16f-d68d-456c-b0b7-5eb94fb89ca6.msgpack.zlib create mode 100644 docs/cassettes/shared-state_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib create mode 100644 docs/cassettes/shared-state_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib create mode 100644 docs/cassettes/shared-state_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib delete mode 100644 docs/cassettes/shared-state_e240f025-ff8b-4d17-beb7-2420c0575dd9.msgpack.zlib delete mode 100644 docs/cassettes/shared-state_f9bf2c15.msgpack.zlib create mode 100644 docs/docs/how-tos/cross-thread-persistence.ipynb delete mode 100644 docs/docs/how-tos/memory/shared-state.ipynb diff --git a/docs/cassettes/cross-thread-persistence_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib b/docs/cassettes/cross-thread-persistence_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib new file mode 100644 index 000000000..923a74528 --- /dev/null +++ b/docs/cassettes/cross-thread-persistence_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib @@ -0,0 +1 @@ +eNqFVG1sU1UYLkIIGkA0GkkY7Fid8Qenve1tR9uQYO0Ax6gbW0GKEXJ27rnttfeLe07HPiTKwKAjkVxJGCrG6LqWlA26AGrAKYmQGPWHhhgsBELUGP/4C6KJBua5XcsgW2Z/NPee9+t5n+c5t7/QRSyqGPqcEUVnxEKY8Rdq9xcssjNLKNuX1whLG1KurbUjMZS1lHJDmjGTRrxeZCoepLO0ZZgK9mBD83b5vBqhFKUIzXUaUk/5hz63hrp3MCNDdOqOAJ/gD6wE7loSP3m5z20ZKuFP7iwllptHscGR6Mw5ekF5ErQTjWidxIoArQfoSCNAoeB5o9O9+xWnlSER1UnFKspKBIowCKmh64RBPx8mNPoFpyftoYxoTl7SyAJkEYBAmqimnFUBolShjG8CGFIzip4CzAAsTYADyAM283+g6LLBi3cX0gRJnLGDubRBmT02jYOTCGNiMkh0bEi8lz2a6lXMlUAisooYKWIHW4Vku5ghxIRIVbpIfrLKLiHTVBWMnLj3Vb7HSJUMyHpMMj1cdCBCTqXO7M+iNRzeth4umQ4Ejxjw+EvdkG+n6ConHaqIQ8qblfi5ewMmwhneB1btYOcni0/cm2NQeziOcGvHfS2RhdP2MLK0xsCpe8+trM4UjdiFWNv0cdXg1DjR4/N5wmP3NaY9OraHZaRSMnaX5LslRa6vCIVGKPhO1FhSiZ5iaXvIL4SOWYSa3Mpkb563ZFnan+OKkO+/KVTd90lrS03N665Hc01cHXt8naWsBEIAtGIGHP8AXyjiD0cEP1gfT4zEqmMSM4oxlrCQTmUuyNqa+AWczuoZIhVjM8pedk+tZfH5qqIpDFZvHhfLebVzAUEQys/MmmkRjbPmTMyJ4XD4f/pyZgizTzv7QZ8AhUBicstgYFsZzFQ5eX+rePIOHo7o6Vkyp/DUssGs2TPjEfzbilXQUJHsL/jzDsHXviqeifokRuM0bMbFYCiTNMPBM90Qq0ZWgox/wwisGKKb2WXQKRA50BiSRTEoiqIkBcOyLAeCZJUoyVK4kQx1Kcgu+jw+kDKMlEpOxtbBGMJpAjsqtrELTckXo/Hm2MhW2G50Gpy/BOI864ZO8h3E4na0i5XR/IJbJM/L26NJ+3QIS6tE7MeBkBwMiGEM177UXqoZ6K5Bcs7XofKt3MNtavGji3OW1B9Y4Kr85iYORlu+fm7JmxPfhga3N767Dp59IvrYlQMLBgbc6NDCIBM7dsmjw7e+aimuWL3otZvXfx1f/tfy3jqWHLx0NXmz+9LqNQmvcqb52q2bvXSC7V+snctvWltEzX8IzXXRtj9/emBZpC439NaKq0ut9Rebd245Jhx6fHPyw8Onik37R0uPLPvn8rUdx368nF5Td5AObLqx4f2ntv7ctOffw+fnzXfvHf0Nb93Yua9p7qJFDaW/zRsPhhbOG3/nOj7y3fwr50tvfDQwNG/j2dL4hdsfxILJy2/3PzS0/pcTnx5d+nr9hvr3Pm+4dRSzIw8fv724b3vqeHzLhYEvI7ueLd/5+MDtO8tcromJua7fPfHBjjku1385MZ/f \ No newline at end of file diff --git a/docs/cassettes/cross-thread-persistence_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib b/docs/cassettes/cross-thread-persistence_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib new file mode 100644 index 000000000..795ff5279 --- /dev/null +++ b/docs/cassettes/cross-thread-persistence_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib @@ -0,0 +1 @@ +eNqFVHlsFFUcXiyIgTYg3gFkWO7j7c7sbrtsRcyy3KVsabdCMUJe37zdme7szHTe2x5UgpRLhEgmHiTGEAPbXdm00NoiIaAGFAE1QkgIbEgANQT/kIQQDFY5fLPd5QgNzh+Tmd/5/b7f915rqgEbRNbUAe2ySrEBEWU/xGxNGbg+jgndkIxhKmlioiJYFdodN+TMBIlSnZQ6nVCXHVClkqHpMnIgLeZsEJwxTAiMYJKo1cTmzPct9hhsWkW1KFaJvZQTeJdnOmfPBzHLWy12Q1Mw+7LHCTbszIs0hkSllqlRgpSTCRdr5lQYw2/Y17xtpWsiViw3UmBcxMANigHRVBVT4GIN+BIXb9UhzYTimBVXo8U5aGAOchJW9HBc4SAhMqEMPUehEpXVCEc1jkqYs0A4uGr25mQ1rLHkNSkJQ5GxtD0haYSaXY/NvQ8ihHUKsIo0kdUyOyKrZX06J+KwAilOIwtbllgzHcVYB1CRG3CyL8vshLquyAhafmcdm6M9RwCgzTp+3J22IAJGn0rNA/48DmdFM1uTyvEOt8fh6mwCbDpZVRjRQIEMUlLP+g897NAhirI6ICcBM9mXvPfhGI2YbeUQBaseKQkNJJlt0IiVeLofthtxlcoxbKYCFY+3yzkftHM7BMHh63qkMGlWkdkWhgrBXfdJvp+SZvt1A74E8MLePEsKViNUMncLvpIvDEx0Jl+8PslK0jhpTbCN4J9PpHKK2xUsy2/zom1EYg7bjvn1PEOezvEeLogoZ+mHE2aUunylzDK/PNQeyLUJ9buMrpABVRJmC5mbX34KSXE1isV0oN+1Z+wPxjJYf0WOyRTkThtblvVrJjw8z2cmPjHSwDHGmtUx4fb5fP9TlzGDqdljzQcEHvCeUN+UxZ4VGa6/zL4zm8OTtPAwROOfEPkATz6ae2J0/3h4z4p0DjSQRfMw+17FCxXRCEKLPdF6b039kmhZXXFj06Jo/f4mgBQtLgLK7i0MsoJoomaG87p8XkEQisPe8AyvKIphEYsC9kIXqnXBWgR3N8jQTAsOgYtoWkTB+wLzQAAiCYOqrGzM1JyaJf7yhYH25aBSq9UYfyHIeFY1FSersMHkaKazrdkBN3CSpVf6a8yeGUj0upHb40VY9Lh9CMxdVtmZF9B9gSSs2yF7P65jMjWY6diAyJitz9iyT4Fi+qMj/YUb771/+tiOev2r+OQWtw8c3DBqSGxKeOa4C4Fw28kFvzeg25d++jQJJkzakkoFh9Efnu86vnTYhbPXrg5effuj386du44O9M6+9c1rsz4uKu3Zc/pPe/Vaji6fcKp1WXndzqLRH4yYgraP/fdFuRceXJnmPwSHqm/Vx891nIbDS2q/u3uht6juJln57SevDr4+98tRZ6b5zhevH7Dr+tHLfwQH7py04PCO0tVlRy83nimcKL9wfjstGDnoVOcrl4OuW2PGDqwc9NzkUPX5q43vlu+Z6vmluzgz2z90Y0/wyNWZ/j3GItM+flMvHT5r6dlpvz696c4o6dmxqYhBhh1xv3ylcNydoqE7xxVu/QzO12+2LSbp5MCTF08IspR2v+S8NDq9MPPmjanbXh9xvGP/j3+3fH7zzHsF8BSIbL72T/vdbVvKujtOurtqL3WMXtS9tu3QX1duDLXZ7t0rsCWnrXtnyFM223+sv8iH \ No newline at end of file diff --git a/docs/cassettes/cross-thread-persistence_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib b/docs/cassettes/cross-thread-persistence_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib new file mode 100644 index 000000000..7a4f441ea --- /dev/null +++ b/docs/cassettes/cross-thread-persistence_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib @@ -0,0 +1 @@ +eNqFVG1oHEUYvlDQ+sMPqggGwfFoU5HM3e7d5i4XBY2XxLQ1HyZX8iGlndudvd3e7uy6O5fetUZqEm1sSdulCIKlBXO5K9eYJm3qB7Ui2B+KFhTqj6MqVBAs8YcW/KxtnL3cJSkJcVmW2Xm/nvd5n5mh/AC2bNUgVZMqodhCImU/tjOUt/DLKWzTkZyOqWJI2c6O7th4ylKLmxRKTbvB70em6kOEKpZhqqJPNHT/AO/XsW2jBLazcUPKFK/s8+oovZMaSUxsbwPguYBQC7wVJ7bz0j6vZWiYrbwpG1teZhUNhoRQd2uPgihQbaBnAEE6fsY7uMMNNySsuWZRQykJwyCsg7ZBCKYwwApwoQDn5rEzNsW669dnpACyMEBAwZoppzSAbFu1KUMPKNKSKkkAagCqYOCC8IHt7AtUIhsNC0u3uIvjOSPuHcwrGEmMtSNZxbCpM7OChzNIFLFJISaiIbHcznuJvapZCyQsa4jiguhiLRHtFJIYmxBp6gDOLUQ508g0NVVErt2/m/U1WSYE0oyJV5oLLmTI6CTU+aCxgsPfmWFjI4DzBQVfYDoNWbcq0RjxUEMMUs4s2S8sN5hITLI8sCwJJ7cQPLXcx7CdiTYkdnTfkRJZouJMIEsPCeeW71spQlUdO/lo58pyZeNSuaCP532RmTsS2xkiOhMy0mw8s0jyYkiBzTsIuRDk+KkKSxomCao44wE+cMrCtsnkjIdzLCVN2UNZNhH81ef5sgLf7dhWmeYPng3ZJjYd52KLpdYCTgAdIgWungBf3xCINHAB8HxbbDJaLhNbdRgzMQsRW2YDaa4MPy8qKZLEUiG66tiL3qW2LFZfU3WVwvLpY8Nyf52swHFcsWZNTwvrjDW3YjYYiUT+Jy9jBlNn1u0P8hzkhNhCl3VCfxGsFrlwhst4ci4ehmjjGp5LeCreYE3v1fFwgf5CGTRUJedjtt7J8W1Iifa0b+sVd0vp7e2tAdqeDCvy+TQUNSMlQcruMQxLgkhTpwjiclyuY28wGBLCKBQOcjyW5XBIkgUUiGBhfEBFToH38SBhGAkNn4m2wCgSFQy7S7Jx8k197Y1tW6KTvbDLiBuMvxhiPBOD4Fw3tpgcnUKpNDvgFs6x8K7GPme2XpTCQTHIx+vrOSEYEWFzT9d0RUCLAsm6t0PpvnyNydRiW5euPnZovaf0rHvh8FPJz559YGT+4Nv/PCQVM39t7al5/7TAPz56iOgjEzuaLyQ2jNzed3QL+PbT8P1y04PXvrn+0ZMPX50jF38+4c/fuvGr9f0vP8798Vt6//Dgn0K+te74PfcNzwbXF8b6dw1HNzv96St6q3MDv3ryNHfsJ/zi1MEDZ/dHoXbprvnQ7bHqwcu/v5N+dNO9jxw4fLbl3Ngr36G9ezqPfVL9xCnu6VERq7v+rd568s0Pa9Lt+txRsvnW6Bs3pbe+eL332pfnhzfePHIid/1uj2d+fp3n76+rL1dVeTz/AbjckGA= \ No newline at end of file diff --git a/docs/cassettes/persistence_08ae8246-11d5-40e1-8567-361e5bef8917.msgpack.zlib b/docs/cassettes/persistence_08ae8246-11d5-40e1-8567-361e5bef8917.msgpack.zlib index b783b954d..615498036 100644 --- a/docs/cassettes/persistence_08ae8246-11d5-40e1-8567-361e5bef8917.msgpack.zlib +++ b/docs/cassettes/persistence_08ae8246-11d5-40e1-8567-361e5bef8917.msgpack.zlib @@ -1 +1 @@ -eNrlV8tu20YUbTddeNVFP4AhChQoRIoPUS8jCGQ5ieWXHMt2bAeBMBoOpbFIDs0ZypIDL5r2B/gJjR0pNVwnQYI2TZuuu+gPuIt+RPdFeynJtVwH6LowF5Jm7p1zX+fOpR4POiTklPkfnlBfkBBhAQsePx6EZDciXHzV94hoMftopVpbO4xCevZ5S4iAF9NpFFCVBcRHVMXMS3f0NG4hkYbfgUuGMEcNZvfO/nwke4Rz1CRcLkoPHsmYgSlfwEJu0RtS5TNParCGnJLkkLkk2Y44CeWDlHRJd464LpNmWOOGNMf2JIx8qSIhzikXUo9FkmA26t2ahBkJERz/N9YeeCpRLnk9yUceuXXV+EPY8ZhN3GSrGQjFVC1FRGGDJbo+7OrwzUVIkAcLEUYE1oJ4AWQR9BIoTdUOBi2CbMjx7x98fNRiXMSnl/P2HGFMAJ74mNnUb8bfNvdpkJJs4rhIkGNw2ifDqsTHbUICBbm0Q/qjU/ELFAQuxSiRp3c480/GQSqiF5Cr4uMkOAVK4Yv4dRWcKFXSKz0osC/paiavai+6CmSM+i5UTHER+NMPhvIfJwUBwm0AUcbkifujw6eTOozHT5cQrtYuQaIQt+KnKPSymVeT+2HkC+qReFBeuWpuLLwwZ6q6rhZeXgLmPR/HTx3kcvL9pcNEhD0FM8CIv9b6mLE2JfHZH/U6duoN76ajNfLbrri3u9HN3i9V5srBSnaxuoNrrLPXDo1MG4eLRnP9zraFFT1n5EwrVzB0RVc1VVd1ZUFdd93KYtVv5wLaKpUEbdfn1+YWraXS9rZe392rbzJ9vbda2Vlf4gszzXZo2TtoZmY/LIv9jOmyjWWm75ur9zZrgelaNeL19tTStATeRR1q37ScznLO791xN+vdap43VrW7Ys26a7D12kJjgzTnxd490qvMMpSfcM+yTEUbe5jVMnkteU7PueESvyla8aFhmc9CwgNoVfJlH1ImIv74CHhIfv1lMO7ZJ9WFCwp/cjQLnIzfrbWilGRkpRoJJEMzMpJuFs18MWNId5fWTspjM2sJBc8kQboiTTrJzqhdpiW4KEJOxM1IOEr+5VqIfO4AL2+f98AAtyK/Tezj8nvZ/y5hP5Q2iQe6ViHdgHGijN2MTzaV1dHtpVRmX41aTWFhE/l0f9gK8TcJs8EJ6r8ei4OQJZBgXPF4fKgb+ulYck66YwhUU3RN0fQfIA6KoccSxwMWQmAEw90oevFZykPdpMFumrplZiHr0xL1sRvZpBY1ZpkHNvm0FITEZch+21XgsiAu9ShUZfg5vnehefSkZm+uagjWJnBFP7O00fPzpEpIEgtJGP8AHRXg+en9SudYmUSnkDXfXlaDGl3gHGY9/uaqfAzxROMn3XNlhdrx2aewqBsFbJk523LMRoYYumZi07IJLHJ2w8Bm/nn5jlJGuEWU2pB+8WB2a7m0VCl/t6lM8kipBqPJNPAZ96nj9GskhNLEx9hlkQ13ZUj6gLVa2opf53HBRDli2I6p64VCXrl9f3U4i77oJ5Xzm7999JeNBCrCUKC2XJSTwYVhbCmlGbq/TfJOJ1zZys230IazaXfF/XnPyewuySmZNXaAjuMT6sWoU4eEBQUMBBcEMC96MXU+Ry6PEeCRYcEJ3uMwNeoOuEXCALwDeD9yXcBqMYqToQkzk/o26cpFLSUDlEBy8dF4Xk0MudTFhJNhERIn4sgdoR2kZJc1geUNfg4PFilv1cFhGAxjrYcHU1P//8xcpGGLRcmLxLWMffhmc22Dp/zahg6vyNc1dvVaBf7fscIfFBbIE9E+mK0u3344NfU3SnL4Fg== \ No newline at end of file +eNqFVF1sFFUUbukLiUSxYHzTy4ISsXd3Zn9adok2sFRoa3/srvIXbO7euduZ7sy9w8ydtluCxEWURE0zPhAh8YVud2Wt0KYoEktCtIk/ISH481Ax1mBC0Gqij5KYeme7S0EanKeZe75zzne+78zNFQeIZWuM1o5rlBMLYS4+bDdXtMgBh9j8tYJBuMqUfHdXIjnqWNrsEyrnph0LBJCp+RHlqsVMDfsxMwIDcsAgto36iJ1PMSX7Q+2ugz4DDfVyliHU9sWALAXDDcBXRYmTfQd9FtOJePM5NrF8IoqZoEK5d6Rq60DrRgOkWMp3qAEsYZFtazYX7f+TsJPoOgPbWErk8Y02oBomgDNgEMJBljl+sJMNAowoaAWLNbxTgVBQthm02oCrxCIA0SxXNdoHbJNgLa1hD7VRAbqWKZfDKuIApZjDAbM8NCir5WlXrqeiAdJ8N+NlphsUVQRHIwsoMjz8fk8bphDdi2IdOQqBIRiBNqOUcBgU6kmNQcl3qKgSpAjnRvIqs7k7eY8XZxHGxOSQUMwUMYj7Yd+wZjYAhaR1xEkJexXLZrulDCEmRLo2QAqLWe4EMk1dw8iLB/pF9/EKa8izJrk3XPKGg8JRyt3zW6s8At1CREaB5A+F/cGJISgM06guvIc6EpQKZjn+6Z0BE+GMqAMra+kWFpPP3IlhtjvWgXBX4q6SyMKqO4YsozE8dee55VCuGcQtxrvvbVcJLrUL+WXZH528q7CdpdgdSyPdJpO3Rb6dUhKuhKDUCCX5TFUlndA+rrqjoXDofYvYplgLcqQgSnLHzuWFI+Tyl8XKT3Cqq73q5k819fntwh33YlJ1GoAUAl2YA891IEdjITkmXnZ0JMfjlTbJZc2YTFqI2mlhSEvV/CJWHZohSim+rO2zvqWxLNFf1wyNw8oNIMzyPt18WJKk2Sfvi7SIIVTzOuZD0Wj0f+oKZQh3z3nzQVmCUii5OGUkvHcWLJe5eI1U+BQ8PoLRhvsgl/hU0eC+6OX5BMN7SxXSUFPcafHeK8md0eQLmWRkIMl3tynb2ox+pTPe0v/REMQ6cxTIxV1KYHkhhrg7C4JNJBVRpFRjWsLiSQUlWUqhSDooNwXDBKdHBzTklmS/DPoY69PJ2fhzMI6wSmCivDZucfuezq0drfHx3bCHpZjQL4mEzpRRUkgQS6yjWyq3Fj+4RQoivWfrHvfcZozTERRMESUSltLRKGzZ1TNRXaDbC5L3bofynf2qWFNLHM38+fibK2vKT93zI+3tM9Laowttm+eTMeexd97LTZnrph5e69Zfm1/dwWIXmn7uvjU3diT3Qd1c9tKJ1cObV1n6/Pd/fPvrhS2/06GmZ7+mhz956O255kvbrqyHT9X/tSPX0nmg9uUNx4Zf2r3qdHHlG/5b3ySc/cam1sv5FxNN88PXvpu4Wf/05GcXOw+Pts21/+N7MHBa+fwVsGbmx7HBzPS79qYbU8dOXjqZ6I399ujxo9e/eORG0wNXwx+fmN7wet2Buf6v3uqN30we25L7pX605cK0uWbFSMu+jt6ZFedn9+ZPLVztf+ZKsxhtYaGuJnz9+N/ra2tq/gUe9MBC \ No newline at end of file diff --git a/docs/cassettes/persistence_0d49697f.msgpack.zlib b/docs/cassettes/persistence_0d49697f.msgpack.zlib deleted file mode 100644 index fc8a38082..000000000 --- a/docs/cassettes/persistence_0d49697f.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_273d56a8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib b/docs/cassettes/persistence_273d56a8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib index 1c9a4bb4e..0d1358369 100644 --- a/docs/cassettes/persistence_273d56a8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib +++ b/docs/cassettes/persistence_273d56a8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib @@ -1 +1 @@ -eNrlV8tu20YUbbdZFQW6J4gCBQqRIkXqaRiFLOeh+CHH8isOAmFEDkVa5Aw9M5QlG140bT+An9DEkVLDdRIkaNP0se6iH1B30Y/oF/RSkmMbDtB1QS5szdw7Z+6Ze+5c8tGohxn3KPnwxCMCM2QJGPD40Yjh3Qhz8fUwwMKl9tFKo7n2JGLe2eeuECGvZLMo9FQaYoI81aJBtqdnLReJLPwOfTyGOWpTe3D2zYEcYM5RB3O5Ij04kC0KWxEBA3kPVkgel4KBRFCAv5AzksyojxNbxDGTDx/CTEBt7CdTnVAohppXRMTaNPElMKvDfy4YRgEMBIswjAUOQmADfgmUpmqHIxcjG7j+/cFHRy7lIj69Gv9zZFkY4DGxqO2RTvx9Z98LM5KNHR8JfAxBEzw+nfi4i3GoIN/r4eFkVfwChaHvWSixZ3c4JSdTkooYhPi6+Tghp8CREBG/bkAQ1Xp2ZQAHTSRdNUuq9qKvcIE84sPJKT6CeIbh2P7zZUOIrC6AKNMkxsPJ4tPLPpTHT5eQ1WhegUTMcuOniAUF89XleRYR4QU4HtVWrm83NV5sZ6i6rpZfXgHmA2LFTx3kc/zjlcVYsIFiUcCIv9WGFqVdD8dn/7RaltNqB7OO1i5t++Le7ka/sFmt36mFK4XFxo7VpL29LsuZXYst5jrrt7bzlqIXc0UjXyzndEVXNVVXdWVBXff9+mKDdIuh51arwuu27q7dWcwvVbe39dbuXmuL6uuD1frO+hJfmOt0Wd7eQXNz+6wm9k3DpxvLVN83Vu9tNUPDzzdxMNhTqzMSRBf1PHs27/SWi2Rwy99q9Rsl3l7Vbou1/O0cXW8utDdw567Yu4cH9XmKSpfCy+cNRZtGWNDMkpY8p+fa8DHpCDd+ohvGM4Z5CCWDvxrCkYmIPzoCHeI/fh9Na+dxY+FCwp8czYMm41/X3Cgj5QpSE4dSTsuZkm5UjFLFzEm3l9ZOatNt1hIJnkkC90UW95KZSbnMSFCwjGMxGwlHKb1cY4hwB3R587wGRpYbkS62j2vvVf+vifohtQkfqFoF90PKsTINMz7ZUlYnt4hSn381KTWFsg4i3v64FOLvEmVDEB55PTWHjCaQsLkS8PhxKXc6NZxr7hh4aoquKZr+E9DwLCixJO6QMuCFLbiixCA+ywSon9TXrKHnjQIc+ozkEcuPbNyM2vM0gC35jBQy7FNkv+0rcFdg3ws8SMr47/T6g9rRk5S9ue4haBfDTfksr02e3y67MJzskLB4B3RUhueX9zudY5mJT7lYfnvVDVJ0gfOkEPA31+1TiMcaP+mfOyueHZ99CoOWaZUcR89ZxaLjFNtIwxhhHeVLhbZp5kp64XntllJDlouV5lh98Wj+/nJ1qV77YUu5LCOlEU4axIhQTjzHGTYxg9TEx5ZPIxuuSoaHgLVavR+/LlllAxVxvlzGJb1cLik3N1dHyIc09az4lWvMyhXTNOQZKUCzpYKpaeN+8eUwSSvp/PXxnzYSqCIdyJ4tV+SkuVjQWpTqHMin27WNjf5c5JrhHN7cijbJ4t3dxaopZ2Ta3gGpTleoF+1IHYsZHCwQv8CA+a5Oc5nzHnO1xYDIcnlYwQccOkrLgbAwCyE6gCeR7wOWSz0raWzQ1zxi475c0TIyQAkkVw6mvUxGoGgoa1iWueh+MgwYdiKO/AnaYUb2aQcqoM3P4WFHj7stCBiaxtTr4eGNG///k7k4hrqcUuKfBWllLnHK2CCt7DOpTXtqS12yaWqpEypSy91FPZxa8pOvg9TSF+kt+RA+1iiB99q0HoBHHMqC8Uduet/xIstN792X3ntvQCOW3pcdFKS24aupIv7fXGUuaChfYvtgvrF88+GNG/8CG87Pqg== \ No newline at end of file +eNqFVH1sE2UcLrBMFCKCDqdGOI4pCLv2rtd1vRFdujIRWNnoytcQxrvr2/bY9e64u3bdGEw2iEQwcBEMLirOdS3UCvsA0eDix1SMkQASDGXLkCVgjDMBxUlExLddy0dY8P567/f5/J7n976NkQCUFU4URsU4QYUyYFX0o2iNERmu80NF3Rz2QdUrukJlpeXOVr/MxZ/xqqqkFBgMQOL0QFC9sihxrJ4VfYYAZfBBRQEeqISqRFdtvH497gPBSlWshoKCF2AUaTTlYng6CFlWrsdlkYfohPsVKOPIy4oIiaAmTDVeoM5QME7BfLWYAHywEN+wKlFAdEE+EcDywO+CBE3kEYooCFAljKgFaTaS+IaIFwIXmm5HyCsqqtZxD96DgGWhpBJQYEUXJ3i0Dz11nJSLuaCbByqMsomKSUK0aDWEEgF4LgDDw1laO5AknmNBwm9Yi7rHUsAJtVaC97qjifkINLagakesaRyGslpEr4CRetqkN7YHCUUFnMAjgggeIEhhKek/eqdDAmw1qkOkpNPCw8kH7owRFa3NDtjS8rtKApn1am1A9plNXXfaZb+gcj6oRWxl97ZLOW+3o/UUpWc67iqs1Aqs1uYGvAI7bpF8KyWKVKEJ0kyQ1IE0SzwUPKpXa6WMpn0yVCS0drApjEqqfqUxhBSB338bSW3K+6UL02r26yaF5iJ1tG6n15+LkTRWyqpYQnWMYgpoqsBoxubZnTFbqo1zRDE6nDIQFDcSpDgtfoT1+oVq6IraRpQ9jt8eS0b9ec7HqUTqliCxEr9ayESSZPzZ+0bK0IdYS3QM0QzD/E9dxAxUtUOJ+QiKJEjaOTxlnqkijo2UOXzXUnjCCTwIUc59Im/jSUdj940eGY/RXBFNgSY4l/YpOleSFEU7A3Vw4TpOXLTA5mAsRUyANZsPBwmWF/0uQkXvDSSSCxFUtThGUab8qiqKNrnNbqMpn2bcbjqftsAqi4lmjKyrNcABLUrpKcwjih4eHrS9SNgA64VEeXJttMjcFYus9vm22HLCIVaJiD8nQDwLogDD5VBG66hFk63RBZdhGKU7rCu0QxaWdecBI7RYXBTpZhiieJmjPb1AtxYklHgdku/aJrSmMjJ9Papz6raxuuQ3pt5hF3vJ8TdmZxi6Z1qbheILK8dd3dkr9BrHb8JPfVT2llo8a//jVz+bEChYc3Rw7ta6qfUZhj242eKtOdu38VREPBYZ+jXnutDQ37DjL1D3zskW+/TjMx1/Pt3Sg9cKwTOhS/GTFzDNaM7uPKgtrfngxOwsd+eZQNeNQ5+cF06CR8xVPZeOXdyx71RvSeWCpjmXW12//GCQpVjmnK1f5md2F0689shLWSWf/5ExPStr6IlJRxyZ4vzsfxZHv8g5Yx3YWV3Sd/zE6MEHKnpaGz3BPutQ35LzE3Objja8Hptx+diuN+xdK1/76s1zD4ZeaX7s7701A3sWPbd0b8usrFU9XROez7jwaFY3XrPsqbzKkhYi1N2kdG6cvKeL2FbXFZfes36X4dNGfVMUyVkyrWPxFTD5dN7gOWbAvvnt1WMzmz0HFvxknffQfjuYP+Hnd7Prt29xFg4NTHZPs5Q/LLc9eXH8uL7e3cElU8cddv547d/TLc3bXy1avaXDOhBsr8gufGHX6tnrMP7jS4Pt+prTL5NXlv+25vei2Nm+fmbX2oYjU6b0n28Yo9PdvDlGV00XXN89Wqf7D0/81FI= \ No newline at end of file diff --git a/docs/cassettes/persistence_6fa9a5e3-7101-43ab-a811-592e222b9580.msgpack.zlib b/docs/cassettes/persistence_6fa9a5e3-7101-43ab-a811-592e222b9580.msgpack.zlib new file mode 100644 index 000000000..678bb17e5 --- /dev/null +++ b/docs/cassettes/persistence_6fa9a5e3-7101-43ab-a811-592e222b9580.msgpack.zlib @@ -0,0 +1 @@ +eNrtVWtQFFcWxqBG1GUtrcRESeyMiy+mZ7qnZ0aGaHQc8AGCIGMcSSy83XNnpqWne+juQR6CSkQ2KgttFNeNSQwOM2QkAqJl1KBB3XXN+qAwUdGs5ZrdNaR8QNZstlIm5A4PNSXr1laS2qqt9K/b95x7znfOd+79igM5UJRYgR9Qy/IyFAEjox9pU3FAhNleKMlr/W4ouwS7L3VBunWnV2Tbol2y7JHitFrgYTWAl12i4GEZDSO4tTmk1g0lCTih5KMFe16bt0DlBrmZspAFeUkVh5GETq/GVH1OaOelApUocBCtVF4JiipkZQSEhJdDWy72OWzeRDdGC7SqcGnopGCHXMjCcMBrhziFG3BJ4Hko4zoUmzDqCFVhwAWBHZVV7nMJkqw0PAS0DjAM9Mg45BnBzvJO5V1nPutRY3bo4IAMg0woYncnlGAWhB4ccGwO9PecUuqBx8OxDAjZtctR9tpexLic54EPm4OhwnBULy8r+819OLSpeaivPEZoKL1GV5+LSzJgeQ51BucAguT3dNsPPWjwACYLxcF7OVP8PYd3P+gjSEp1MmAWpH8vJBAZl1INRLdR3/jgvujlZdYNlYAl9eF0vcb76SgNSWpMDd8LLOXxjFLtAJwEG+41+d6RIGKFwgkjTpC7+7rEQd4pu5SdJDm1RoSSB80bfMWPQspeqdiHGIGn/hjoHZGqBUl9bF4JG+mLR+woTVaXV40RFLaAkbEQ6xhpiqPIOB2JzUm21lp601j7JaPBKgJeciBCEvrIDzAuL58F7UFLv7S3qe6XJaL8HOtmZbz3eiCyQr+KT08QRNuER3qK0I26Fsroo0wm03+IizoDZWVvqD6cJHCCsvZUadBntGH9ney5ZL14/CE8CNGvHuF5H0+fN/ZI7/7x6MiMYC9onLUr76N1JkFaEvU0fBF49V6bxaMjs+YYcxPSrPtycYYTvHZcRg8NxLsHIldW2jBoAAaSoY2AAjRlMtj1dCzpmEoyZCxh11EEtTOHBUqQ1JCYUxCcHKyzzMYtgHFBPL17bJRA/JIUc/I8S60NXyjQAuqfFaA+8wIP/elQROOoBLtTowsuQj86vtC8RNkbyzAOAyABYSdowmEy4QmLF9b3DdC9AfGFXofuB20NGlMRbf1+ADluw5Cw7i98fkVy0rGZI9Z1fRg7Wvuq752Mk9U7htw0a/NT44/mUMmVvKP1Rq2h8tsV86wd+lP/KIq6Mv7g0GGcZamjcevNqqL6XSeuf3OhIzszff/S969MB8Vxsv7gpIHpoyZc3DBuTUTzIEPtb5fFPJGnbskfFZN4vX3RmLXb9Kcb7+oOnaHmtwyNaaA7c+7GLPo66tNzkz0JV4Z98uHfh5/Pf3b1G9GpayrngorcATGm1e3syh0jTxhqrA7b0bjVxo9GPfXs3qdLDLZjLRW3J3zVzIa3HjNX1U249md++f6yNGLsq0PNGV/Pe37dmTufc3f8mdfapzfvaN0yfRu2cdDIxdV/eLNz8ZC95ccr669+VlicPWZXbNWnmuXv7BkfaTv1xcDoz1fpj5jeODwgLKyrKzysfFbWrfVo/SNJSt4PlJQVLiBPlDB3HsYDN5zxs6z838mKjvxxZYX6WVb+B7JC9ScrxhSXM9tECytkZrHJmTA3fklGvIv+t7JiYvSkwcEYocMxFQCH3aijiVi7zmHS0zojRcKfWFZgrMmk++9kZft9WXl5kzlrrHl4Sdf6luitDdnbD25uih6xvmCor7R14cZp429Hbvu4ds6YwG86V2kPpWy4/NrV9qZfTm+JYD4YXOCeuuGyIBR+1dHx3qUZW87uan33n5mHi1YVzSrNicqVG6bs2xiZlLJzZjCt7HgLeCt8ItcyMbjGuaLx4/mNQy5zB2xFtpUva1rePkur150uPzeuprOOfKFs8IWZlpQDZcKNZS/94vyIPZ88JcvLsNtLnlAfIy88Fj769KyIqhti+0n6ycfTVgafSywgI76cVlowaOR7mRYVG7Nv+LmmWzMOR5nx0ZEX5u5w7x6cNmva8dTJ5kWauNI5XzzzL/XjmvzsYBpZshTcjKpYe+Tu0dlp3zbfSrwFJq389YEp8aTmryfKzoCmsXVHIiquDbOcZa4Hhw+Mqy8/9FmA7rjUEFaSavuyac/rm0r+suW1s1trshOJtpO7myvBn65Ojo6UpnXJNZWlyaBVfRFLumjDi28P+1sh7NxY9tHmqPPt4343avbTQbf6SP0k4/6k0gOX9t1h817oGtyjYFMo5kn3Y2Fh3wHILFEg \ No newline at end of file diff --git a/docs/cassettes/persistence_8578a66d-6489-4e03-8c23-fd0530278455.msgpack.zlib b/docs/cassettes/persistence_8578a66d-6489-4e03-8c23-fd0530278455.msgpack.zlib deleted file mode 100644 index 2e13100a6..000000000 --- a/docs/cassettes/persistence_8578a66d-6489-4e03-8c23-fd0530278455.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_cfd140f0-a5a6-4697-8115-322242f197b5.msgpack.zlib b/docs/cassettes/persistence_cfd140f0-a5a6-4697-8115-322242f197b5.msgpack.zlib index a30efa685..18e97c77b 100644 --- a/docs/cassettes/persistence_cfd140f0-a5a6-4697-8115-322242f197b5.msgpack.zlib +++ b/docs/cassettes/persistence_cfd140f0-a5a6-4697-8115-322242f197b5.msgpack.zlib @@ -1 +1 @@ -eNrlVs1u20YQbtCbe+6dIQoUKLQUKYmSLEMoZDmOFf/IlmzHcRAIq+VKpEVyGe7SlmQYaNPeCxZ9gSaOlBpufpCgTdOm5x76Au6hT9CH6FCiahsOUKC3QjpY2t3Zb+eb+WbGD4b71OcWc6+dWq6gPiYCFjx8MPTp/YBy8eXAocJkxvF6tb75KPCts09MITxeSCaxZynMoy62FMKc5L6WJCYWSfjt2XQEc9xkRu/ss0PZoZzjNuVyQbp7KBMGT7kCFrJpXZcqHztSkzXlhCT7zKbRdsCpLx/dgx2HGdSOttqeQGlFRyLwmyyydWFXg28ufIodWAg/oLAW1PGACNhFUKqiHg1Nig2g+dWxybgIn152/BkmhAI4dQkzLLcdft/uW15CMmjLxoKegLcuHYUlPOlQ6iFsW/t0ML4VPseeZ1sER+fJPc7c05gdEj2PXj0+iaghiIUrwldVcKJUSa73IMKupCmZvKI+7yIusOXaEDJkY/Bn4I3Of7544GHSARAUZy8cjC8/vWjDePh4FZNq/RIk9okZPsa+k828vLjvB66wHBoOy+tXn4sPz59LK5qmzL64BMx7Lgkft7DN6Y+XLlPh9xBhgBF+qz6dxMembluY4SMtlX/iU+6BXugXA7gmAv7gGHJBf/9tGAvnYXV5ksQ/3/vweAHyEr7dNIOElMpKdepJKTWVkbR0IZ0vZDTp5urmaTl+ZjNKw5kkaFck6X60MxbMnARq9TkVxUC0UP7Fpo9d3oLc3JjoYEjMwO1Q46T8TgW8jRQA9CI+oFtEux7jFMVuhqc7qDYuIVRZeDmWG2J+G7tWfySH8Lsou+CE5b6Kjz2fRZDwOHJ4+HA28zQ+mMT9BHiqSFORqv0ENCwCMov89pgPvCiB+hS98Czh4G6ksWJa09NZVVXnJMsldmDQetBcYA48yeckz6c2w8abLoJqobblWJCU0d+49kE/GlxWX1+1EKxDoU080dXx59eLJj6NXohY/AN0PAufX95tNMHKRDazefXNZTNI0TnOo6zDX189jyEeqvy0OzFGlhGefQSLBsnrJJeazeVz2SbJkDzJ4ZbazGBd1VNGnuaflRdRGROTovpIfeFw4c5aabVSPqkDdpmxjkW//uPa+40GaTWaThEu53dtsXF/u5u9Xaoslb317Ep1j9TZ/kHHT2U6xF9JtbcWd3WCtFwql9ZzsykNaYqqaIqGlpUt266sVN1OzrPMUklYncatzaUVfbW0u6s17h80dpi21atV9rZW+fJ8u+Prxh6en+/7ZdHPpG22vca0frq2sVP30rZep07vQClBPrEwi8k5CYRoQViKcX0gqA8UVUemoE6qY04yRiooKpd74Zy0BM296tq9OSgrkBOFb+zQuiVocY259OwbiEGwbxlFvbW/lnN7i/ZOo1vN82ZNvSk29ZsptlVfbm7T9i1xsEF7lQWG8xeCoOtppMZxyKqZ/Eg8567/R69+2EEXyx1VvfEUG7qMu1arNahTH0ooPCE2Cwxo6z4dQM5rpTvhqzyZTeOc0coRjWggP3Tjdm00tz4fRBXmtv/44C8DC1yQDmXLkAtyNOQIjDhUmrf6u45bE2v9hdr87f72zkZ7delg1dzaxYtyQmbNPega8Q3lfCwqo74CBgT6kKCAeR6fxGTgXZ53UO8pHW7wHofx1miBW9T3wDuAdwPbBiyTWSQasDBfLdegXbmgJmSAElguHMaDVcbQXKDDwrXE+RSWYeHTVsCxPUY7Ssg2a0MzavIJPLxocbMBDsMMi63uHc3M/P8jcx6GJWrbTJ5S8tI8/Ac2pdyvT23Sl9jB1HIn2J1a7pWpZT6egFNLv8eCqeUumIF708r+06ki/u9cZS6YJ19ge3ehunbj3szM35z4rZ4= \ No newline at end of file +eNqFVH9MG1UcL8Ml2xKTiWYxS8hujQymvPauV6AlGFcLG6QyKjSboBt7vXttT653591rBSZ/DIhmLnNelihm6nQt7WzKoNKxBUeGQaPRRROXLDYxaKbL/GPJVGZiWCK+lhZYIHh/vfv+/Hw/n+97/fEwUjVBloqSgoSRCjlMfjS9P66iV0JIw4OxIMIBmY+6W9o8kZAqZMoCGCtardkMFcEEJRxQZUXgTJwcNIcZcxBpGvQjLeqV+Z5M6KgxCLs7sdyFJM1YSzG0xVpJGQtBxPLiUaMqi4icjCENqUbi5WSCRMJZU0DYSTWVBymv7DX2HcpmyjwSsx5OhCEeARZUAU2WJISBhdSmqy20sS8eQJAnY52KBmQN66lVQEchxyEFAyRxMi9Ifn3E3ysolRSPfCLEKMFlK+aY0BNdCCkAikIYxRaz9DGoKKLAwazf/DLpnswjBrhHQavdiexggMwrYf2So4DD7O4hvEoUbWKtJstYN9AwFCSRMANESCDFlJz/s5UOBXJdpA7Ia6bHFpMvrIyRNX24GXItbQ+UhCoX0IehGqy2jq+0qyEJC0Gkx53u1e3yzuV2rIlhTPbUA4W1HonTh31Q1FBqieSllARRhQV0NaCZCwWWRCT5cUCPMEzNeRVpCtk3NBAjJXFI648SRdC1r+P5FTnX4iqoOWsoidYTdfQpTyBUSdEs1cJhKqs6xdhrWaaWHPY1e5LOfBvPmmKkPCqUNB8RpKEgfpwLhKQuxCeca8qeMS6PpZL+ohAUMMhfDyJW9lePWmmazuxaN1JFQcJatmOUtdvt/1OXMIOwns7OBxga0Kxnccoqa0eGWitz8ZLl8cSyeAiiJ9aJXMZTiKbWjV4bj8XakciDBgKvXyHnTprZC19t7e3oZS0+t2LrsDe7WVe4K3SxG3CiHOIBJg8NArmF6MZ6hvLyVi9kLTS0evkqK0LIx9RAZKuppq12xmKzRcIC1BOMiaH8suwX0ahzL3BCLoBAW25t9Hh9+35Hc5Mz+QJolb0y4c8DCc+SLKFYG1LJOuqJXGtywVUUI+mtjnY9beM4XxW02Bg7D2mf3Q4aDraOFRZoaUGi2dch96AdI2uqEtOXRU/uOLHJkPuKn3u72TWzZ+vrC9/Y3j1c0tT2jLa7orH39LNPV5RMnEm1T77XND5+wz3/c9nzn1+fZr+/Unx386GTGyfgQTR3cfbvW66ehXuXZ9O+uZ/udp66VLbrvHNfpGHnUCnsn/rnkaGtL7ln3tw80Xr6qw0jNakY1g/HHUNN1+u+Hf30TN3MQyNjJU9tk+NX3cOjf762feM7v01ND4jmI8PjhjuVx7ak67cMfOGquLXpBp385fb9Rsdw9UzJgaL0xx9O//HRyV9LB99K3lfCaV9V96WzN0XusWsHzvXfizz8RqPjA2Xor+1zTa66q+WPeyYT5Y8OpvbcnPzhR/Zf04ZSY6qs0tZ79sj787v3/375RMcnd44Xb5urcxyf3wGk727LhJSFhWJDJF5S2VdkMPwHIYKQ/g== \ No newline at end of file diff --git a/docs/cassettes/shared-state_18bd8679-3a73-4033-bfb4-5093ac1f5d7f.msgpack.zlib b/docs/cassettes/shared-state_18bd8679-3a73-4033-bfb4-5093ac1f5d7f.msgpack.zlib deleted file mode 100644 index b21475734..000000000 --- a/docs/cassettes/shared-state_18bd8679-3a73-4033-bfb4-5093ac1f5d7f.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/shared-state_5f36c16f-d68d-456c-b0b7-5eb94fb89ca6.msgpack.zlib b/docs/cassettes/shared-state_5f36c16f-d68d-456c-b0b7-5eb94fb89ca6.msgpack.zlib deleted file mode 100644 index 6ea5bfc76..000000000 --- a/docs/cassettes/shared-state_5f36c16f-d68d-456c-b0b7-5eb94fb89ca6.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/shared-state_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib b/docs/cassettes/shared-state_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib new file mode 100644 index 000000000..746f1956f --- /dev/null +++ b/docs/cassettes/shared-state_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib @@ -0,0 +1 @@ +eNqFVHtsFEUcLi2QWolGQAEhuJxFMXbvbvce7Z0xUA+EAqW1PVJbxDLsTm+X7u0uO7Ol11qTlkciNYGFiIomEHvclaOUK48QBGJFixoBK9jIGamgFCPYPwTFB9I62155hAb3j8nO/F7f7/t9Mw3RKqghUZFHtIgyhhrgMNkgoyGqwZU6RHhNJAixoPDhwoJif5OuiYnpAsYq8tpsQBWtQMaCpqgiZ+WUoK2KsQUhQiAAUXi5wocSn9ZagqC6HCuVUEYWL8XYWWcWZRlyIidLai2aIkHyZ9ER1CzEyikEiYzNo1UCwJSIqGCIkkEQzrTULTXDFR5KppmTgM5D2kG7aKTIMsQ0SwrY3azdzINCCMOg6Veq6BTQIAUoAUpqhS5RACERYYKewkCqFOUAhRUKC5AyQVipxWSlRLlCIcF1UQECnrC0ISwoCBtt9/S9B3AcVDENZU7hSS5jd6BGVLMoHlZIAMMYZ2IbINaIVUKo0kASq2BkMMqIA1WVRA6YdtsK0kdLkgAah1R4rzlmQqQJfTI2DuYO4bAVhsiYZMpudTitbLyaJt2JskSIpiVAIEXUAfvhOw0q4CpJHjopASMyGNx6p4+CjB35gCsovisl0DjB2AG0oNu5785zTZexGIRG1Fd4b7mk8XY5h5VhrJ62uxKjkMwZOyqAhGDbLZJvhcTIfB203U3bmdYhliQoB7BgNDEed7MGkUrkC1dHSEqso4YwmQg88Xk0qbgPChYMTbM7ZWx4NpmOcdQv6FmU3UEVcJgy9UMWr8vhdXqoufn+Fl+yjH/YYbT5NSCjCjKQOUPDj3KCLldCPuYbduwJy+22NFJfEoMippO3jQzL3Bphp91uTzx1X08NBglrZsWww+Px/E9ewgzExn6zP5qx03aHf7BLl7MsQQ0XOXhnk3giJh6CKPM+nrfxDHlT9/UeHo/TUxZLgqZF3jhC/svtTAmnqKzuy0H64nw0b25hkYt1hFwHqmlOUnSexuTdgvSAIKqxkaAYwPJ2JwNZxuF2uLPZHDbb6XKwHg8DuWwXzzZVicCIMVaGCihKQIJ7fC/SPsAJkC4ekI0RnV26KDc/z9fyMl2kLFcIf35AeJYVGUaKoUbkaMQGSpMLrsEICS/KLTX253BcBc9CJoeHIIfzuOk5JUXxIQHdEkjYfB0G3sd6IlONHHWM2P5EY3rKwJcmbcpVxuWOWdu/vmeB9b0ZIzO6umvSi9b4X2pNn3PqzX2TvJU2rmD+2J6Pms6lrnjk6QXXa7dtm4s+Ht/W0f1h79WTdczRm/921mWVn/rh2ys39iU+iT40+fcz7U3rTzZzUlyYOpnfciJvyuRfXdrxx3yRx0N9Va87sh8F2/Zs2bXqyz93TXdP9L/f0Xaz5u80vc/zXfT0j6OFzpalXpR2+HK8vplFOZ1G/cWRedfLaq6GU/efuayeLpvV/POo7ydtbD83ms0r2cm9s9zVv+yFZQ51bX3jzsK+h115Cz8b/yxsPt6xff7UpV8ERvu+5tZPmfbAX/XTmqccOnuxvH3rsRGbciZkjFt57Uh2Yl5P/fS91WmZvynxY4vyXu05O6EXzHhtYVlvV8aS9oqZ3c83bjzzpO+rn1xdE9Ol8xuvP7OwILWWboq/+83aC2+gzsAhdKrp2i+z+sZeynhu3SwPeuX8H0tWX/JKD27euawxa+WVA+l9Uyf2N2fVt721Fa3W/8nsHbV5TNfB1g1Z63ovR3J39+3Vb1youTkqJaW/Py0ls7Tk7YbUlJT/AFgF6ww= \ No newline at end of file diff --git a/docs/cassettes/shared-state_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib b/docs/cassettes/shared-state_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib new file mode 100644 index 000000000..83045dace --- /dev/null +++ b/docs/cassettes/shared-state_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib @@ -0,0 +1 @@ +eNqFVG1oHEUYTo0JDYq10j8WpcPRFsTM3e59hFwQJb3EKjVNTK42qbRhMvve7Ta7O5vduSTXWiSxFD8wZfOjFVGR5nIn17RJMLZCLFKtUGiLSqv1IPhDEQwitFb7wx/W2ctdk5IY98cyM+/X8z7vMzOc6wfb0Zi5ZkIzOdiEcrFx3OGcDX0pcPjhrAFcZUqmrbUjPpaytcIWlXPLaQgEiKX5iclVm1ka9VNmBPrlgAGOQ5LgZHqYki58f9BnkMFuznrBdHwNSJaC4VrkKzuJk5cP+mymg1j5Ug7YPmGlTCAxuXc0oBKONAcZaWQSA57xHdrrhTMFdM9MdZJSAIdwBDvMNIHjoCgg1QUlL4+TdjgYnl8XSyFiAyJIBd1KpHREHEdzuECPONF7NTOJOENcBeSB8KNd4o80M8EaFpZecQ9Ho65R8B3KqUAUwdvRjMoc7k4vY2KSUAoWx2BSpojs7qnkAc2qRQokdMIhTz20RardfC+AhYmu9UN2IcqdIpYlChHPHtgvOpsoUYJ52oLl5rwHGgtCTe6ebSzjCLSlxeBMJPlDYX9wahCLfjVTF9RjnQhIWaton11qsAjtFXlwSRRudiH49FIf5rjjLYS2dtyTkthUdceJbdSFP156bqdMrhng5mJty8uVjIvlQn5Z9ken70nspE3qjieI7sD0XZLvhuTFxENYqsOSfLrMkg5mkqvuWFAOf2SDYwlBw2tZkZKnnOGMmAhcvpgrafBE647yNH+seCTTJKbjnourqVokhVAr5chTlPg1REINEQltb4lPxEpl4isOYzpuE9NJiIE0l4efo2rK7AUlH1tx7AXfYlu2qK9rhsZx6f6JYXlbNxOWJKmwdVVPGwzBmlcxE4pGo/+TVzAD3J3x+sOyhKVQvNRleE8BrRS5cItLeLIeHoFo8yqei3jK3mhV7//AI+3Jl0BjTXE/E+tuSe6EoHWgOVq/bXd4G0vY27e92NXSEv5kEFOdpRTMxUsGuCiIQe4WEESVUDQSkaOJqBwJBykoSg/QHhqReuqjdYo81q8RNy/7ZZRkLKnDZOxZHCNUBdxRlI2ba+ra2djyfGyiE7ezHib4ixPBs8lMyHaALeTo5oulxQW3ISvC2xu73Jl6ShNKEIAqEbmeRutw8+72qbKA7gok470OxRdzSMjUFkcX5ja9tbai+FW+MHJl/5fSw4e7v7rc5R+5eqzp7OanN/wUax1qf3P97dHXLz55fXb4/p8HAg/hP8M3rqwLnR+Y+vWXuQ0n//40Pdnafurkdzffvn08ttf4q7ry3LqZzHMX3q+ppg8+YPn2XZv+4sOjj1d1zpwfH/kj9c/oDmXrlUsnXvHvu3RftaFseemHr+dZfP7MtU09N9dffWf6tydujf4+zOZrbh0fUh97132v6UhV33V146OfH/lmwGfWHOtYWz3fd3Xnjac2G+F9b1Sdmdt4IXPn28QHr4o27typrFgfmK2oXFNR8S83QI1c \ No newline at end of file diff --git a/docs/cassettes/shared-state_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib b/docs/cassettes/shared-state_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib new file mode 100644 index 000000000..ac64b017b --- /dev/null +++ b/docs/cassettes/shared-state_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib @@ -0,0 +1 @@ +eNqFVH9oG1Ucb90fDmR1DgTR4R5Bq2hfcpdLmqRs1Jqm1dW2oY2rrWh9uXvJXXP37nb30iXO/mE3HKJ03mAqxTFZ02SEbmtd58AfYGVDpYL7Y1IiTMU/RHAynMgQOuq7NGk7Wuv9cbz3vr8+38/3895oYRiblqKT2imFUGwikbKNZY8WTLw/jS16OK9hKutSLtrdG5tIm0rpUZlSw2ryeJChuBGhsqkbiugWdc0zzHs0bFkoia1cXJeypasHXRrKDFI9hYnlagI85/U1AFfViZ28eNBl6ipmK1fawqaLWUWdISHUOTogIwoUC2hZQJCGm10jLznhuoRVxyyqKC1hKEA/tHRCMIVeVoBr9HJOHitrUaw5fv16GiATAwRkrBqJtAqQZSkWZegBRWpKIUlAdUBlDBwQbvA8+wOFJPSm5aVT3MHxtB53jRRkjCTG2tGcrFvUnlnHwzkkitigEBNRl1hu+0zyVcVoABJOqIjiouhgLRNtF1MYGxCpyjDOL0fZ08gwVEVEjt0zxPqaqhACadbA681FBzJkdBJqX2yp4vBEs2xsBHBuwef2Tmcg61YhKiMeqohByhtl+6drDQYSUywPrEjCzi8Hn13ro1v2ZCcSu3vvSIlMUbYnkak1+s6vPTfThCoatgvh6PpyFeNqOcHN8+7QzB2JrSwR7ckEUi08s0LySkiRzVuAXCPk+LNVllRMklS2J7y897SJLYPJGR/Ks5Q0bY3m2ETwt18XKgo81d1RneaPNTtyrWw69ucxOd0AOAF0ixQ4emK/Jr/Q5OdAe2dsKlwpE9twGDMxExErwQYSqQ6/IMppksJSMbzh2Euu1bZMVl9VNIXCyu1jw3K2ds7HcVypflNPE2uMNadiTgiFQv+TlzGDqT3r9Ad5DnJCrNKlb6AENopcvsMVPHkHD0P0yCaeq3iq3mBT7//Aww0UK6ChItmfsfUgx++LdkXkwHBHsN3Xt5eIfDJMwpF9FzJQVPW0BCl7xzAsCyJD7RLgeMQn4qGgXwj4/VJc8kteMS7FuaAQ53FA8k4MK8gu8m4eJHU9qeJz4TYYRqKMYW9ZNnahtb+rpfPZ8NQLsEeP64y/GGI8E53gfC82mRztYrk0u+AmzrPwnpZ+ezYoignJi+PBkBAIiqFGGOnrma4KaEUgOed1KL+XrzOZmuzo0g+73tpaU/62PDfW0XHpqe2Hl/ae/qs1/tp32p6Ge0bbTz7zfuf4Ax/Qr+hRads/N45F5nrn+u4dalv4YmLh4ye6bjx8a7D7p2to6MDsNS1/5NYft+fv33mduzLu+v7Kjp1tbz65tXhi4JVDYc+2SOYqn3vj5vlFVx+qn58/tdvjnr+r7sL0fQ8t/r4YGPKd+Xsis7vjQaFuDz6RuPhR89zNXz+sD/t7oiizPXB80v4z9fhI/S/jP4cu//bO2GO33x47Ih3/5u6ZL98L1B273vzJy+/uYk0sLW2p6bu8sL+2tqbmX44/ioo= \ No newline at end of file diff --git a/docs/cassettes/shared-state_e240f025-ff8b-4d17-beb7-2420c0575dd9.msgpack.zlib b/docs/cassettes/shared-state_e240f025-ff8b-4d17-beb7-2420c0575dd9.msgpack.zlib deleted file mode 100644 index 43b3e2617..000000000 --- a/docs/cassettes/shared-state_e240f025-ff8b-4d17-beb7-2420c0575dd9.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/shared-state_f9bf2c15.msgpack.zlib b/docs/cassettes/shared-state_f9bf2c15.msgpack.zlib deleted file mode 100644 index 06a96fec6..000000000 --- a/docs/cassettes/shared-state_f9bf2c15.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/docs/how-tos/cross-thread-persistence.ipynb b/docs/docs/how-tos/cross-thread-persistence.ipynb new file mode 100644 index 000000000..def85825a --- /dev/null +++ b/docs/docs/how-tos/cross-thread-persistence.ipynb @@ -0,0 +1,358 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "d2eecb96-cf0e-47ed-8116-88a7eaa4236d", + "metadata": {}, + "source": [ + "# How to add cross-thread persistence to your graph\n", + "\n", + "
\n", + "

Prerequisites

\n", + "

\n", + " This guide assumes familiarity with the following:\n", + "

\n", + "

\n", + "
\n", + "\n", + "In the [previous guide](https://langchain-ai.github.io/langgraph/how-tos/persistence/) you learned how to persist graph state across multiple interactions on a single [thread](). LangGraph also allows you to persist data across **multiple threads**. For instance, you can store information about users (their names or preferences) in a shared memory and reuse them in the new conversational threads.\n", + "\n", + "In this guide, we will show how to construct and use a graph that has a shared memory implemented using the [Store](https://langchain-ai.github.io/langgraph/reference/store/#langgraph.store.base.BaseStore) interface.\n", + "\n", + "
\n", + "

Note

\n", + "

\n", + " Support for the Store API that is used in this guide was added in LangGraph v0.2.32.\n", + "

\n", + "
\n", + "\n", + "## Setup\n", + "\n", + "First, let's install the required packages and set our API keys" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "3457aadf", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install -U langchain_openai langgraph" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "aa2c64a7", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "ANTHROPIC_API_KEY: ········\n" + ] + } + ], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "\n", + "def _set_env(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}: \")\n", + "\n", + "\n", + "_set_env(\"ANTHROPIC_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "id": "51b6817d", + "metadata": {}, + "source": [ + "
\n", + "

Set up LangSmith for LangGraph development

\n", + "

\n", + " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", + "

\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "c4c550b5-1954-496b-8b9d-800361af17dc", + "metadata": {}, + "source": [ + "## Define store\n", + "\n", + "In this example we will create a graph that will be able to retrieve information about a user's preferences. We will do so by defining an `InMemoryStore` - an object that can store data in memory and query that data. We will then pass the store object when compiling the graph. This allows each node in the graph to access the store: when you define node functions, you can define `store` keyword argument, and LangGraph will automatically pass the store object you compiled the graph with.\n", + "\n", + "When storing objects using the `Store` interface you define two things:\n", + "\n", + "* the namespace for the object, a tuple (similar to directories)\n", + "* the object key (similar to filenames)\n", + "\n", + "In our example, we'll be using `(\"memories\", )` as namespace and random UUID as key for each new memory.\n", + "\n", + "Importantly, to determine the user, we will be passing `user_id` via the config keyword argument of the node function.\n", + "\n", + "Let's first define an `InMemoryStore` which is already populated with some memories about the users." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "a7f303d6-612e-4e34-bf36-29d4ed25d802", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.store.memory import InMemoryStore\n", + "\n", + "in_memory_store = InMemoryStore()" + ] + }, + { + "cell_type": "markdown", + "id": "3389c9f4-226d-40c7-8bfc-ee8aac24f79d", + "metadata": {}, + "source": [ + "## Create graph" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2a30a362-528c-45ee-9df6-630d2d843588", + "metadata": {}, + "outputs": [], + "source": [ + "import uuid\n", + "from typing import Annotated\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langchain_anthropic import ChatAnthropic\n", + "from langchain_core.runnables import RunnableConfig\n", + "from langgraph.graph import StateGraph, MessagesState, START\n", + "from langgraph.checkpoint.memory import MemorySaver\n", + "from langgraph.store.base import BaseStore\n", + "\n", + "\n", + "model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", + "\n", + "\n", + "# NOTE: we're passing the Store param to the node --\n", + "# this is the Store we compile the graph with\n", + "def call_model(state: MessagesState, config: RunnableConfig, *, store: BaseStore):\n", + " user_id = config[\"configurable\"][\"user_id\"]\n", + " namespace = (\"memories\", user_id)\n", + " memories = store.search(namespace)\n", + " info = \"\\n\".join([d.value[\"data\"] for d in memories])\n", + " system_msg = f\"You are a helpful assistant talking to the user. User info: {info}\"\n", + "\n", + " # Store new memories if the user asks the model to remember\n", + " last_message = state[\"messages\"][-1]\n", + " if \"remember\" in last_message.content.lower():\n", + " memory = \"User name is Bob\"\n", + " store.put(namespace, str(uuid.uuid4()), {\"data\": memory})\n", + "\n", + " response = model.invoke(\n", + " [{\"type\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", + " )\n", + " return {\"messages\": response}\n", + "\n", + "\n", + "builder = StateGraph(MessagesState)\n", + "builder.add_node(\"call_model\", call_model)\n", + "builder.add_edge(START, \"call_model\")\n", + "\n", + "# NOTE: we're passing the store object here when compiling the graph\n", + "graph = builder.compile(checkpointer=MemorySaver(), store=in_memory_store)\n", + "# If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass the store or checkpointer when compiling the graph, since it's done automatically." + ] + }, + { + "cell_type": "markdown", + "id": "f22a4a18-67e4-4f0b-b655-a29bbe202e1c", + "metadata": {}, + "source": [ + "
\n", + "

Note

\n", + "

\n", + " If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass store when compiling the graph, since it's done automatically.\n", + "

\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "552d4e33-556d-4fa5-8094-2a076bc21529", + "metadata": {}, + "source": [ + "## Run the graph!" + ] + }, + { + "cell_type": "markdown", + "id": "1842c626-6cd9-4f58-b549-58978e478098", + "metadata": {}, + "source": [ + "Now let's specify a user ID in the config and tell the model our name:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c871a073-a466-46ad-aafe-2b870831057e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Hi! Remember: my name is Bob\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Hello Bob! It's nice to meet you. I'll remember that your name is Bob. How can I assist you today?\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"1\", \"user_id\": \"1\"}}\n", + "input_message = {\"type\": \"user\", \"content\": \"Hi! Remember: my name is Bob\"}\n", + "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", + " chunk[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d862be40-1f8a-4057-81c4-b7bf073dc4c1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "what is my name?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Your name is Bob.\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"2\", \"user_id\": \"1\"}}\n", + "input_message = {\"type\": \"user\", \"content\": \"what is my name?\"}\n", + "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", + " chunk[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "80fd01ec-f135-4811-8743-daff8daea422", + "metadata": {}, + "source": [ + "We can now inspect our in-memory store and verify that we have in fact saved the memories for the user:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "76cde493-89cf-4709-a339-207d2b7e9ea7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'data': 'User name is Bob'}\n" + ] + } + ], + "source": [ + "for memory in in_memory_store.search((\"memories\", \"1\")):\n", + " print(memory.value)" + ] + }, + { + "cell_type": "markdown", + "id": "23f5d7eb-af23-4131-b8fd-2a69e74e6e55", + "metadata": {}, + "source": [ + "Let's now run the graph for another user to verify that the memories about the first user are self contained:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "d362350b-d730-48bd-9652-983812fd7811", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "what is my name?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "I apologize, but I don't have any information about your name. As an AI assistant, I don't have access to personal information about users unless it has been specifically shared in our conversation. If you'd like, you can tell me your name and I'll be happy to use it in our discussion.\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"3\", \"user_id\": \"2\"}}\n", + "input_message = {\"type\": \"user\", \"content\": \"what is my name?\"}\n", + "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", + " chunk[\"messages\"][-1].pretty_print()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/how-tos/index.md b/docs/docs/how-tos/index.md index 57266115a..7ee97325e 100644 --- a/docs/docs/how-tos/index.md +++ b/docs/docs/how-tos/index.md @@ -18,17 +18,22 @@ These how-to guides show how to achieve that controllability. ## Persistence -LangGraph makes it easy to persist state across graph runs. The guide below shows how to add persistence to your graph. +LangGraph makes it easy to persist state across graph runs (thread-level persistence) and across threads (cross-thread persistence). These how-to guides show how to add persistence to your graph. -- [How to add persistence ("memory") to your graph](persistence.ipynb) -- [How to manage conversation history](memory/manage-conversation-history.ipynb) -- [How to delete messages](memory/delete-messages.ipynb) -- [How to add summary conversation memory](memory/add-summary-conversation-history.ipynb) -- [How to share state between threads](memory/shared-state.ipynb) +- [How to add thread-level persistence to your graph](persistence.ipynb) +- [How to add cross-thread persistence to your graph](cross-thread-persistence.ipynb) - [How to use Postgres checkpointer for persistence](persistence_postgres.ipynb) - [How to create a custom checkpointer using MongoDB](persistence_mongodb.ipynb) - [How to create a custom checkpointer using Redis](persistence_redis.ipynb) +## Memory + +LangGraph makes it easy to manage conversation [memory](../concepts/memory.md) in your graph. These how-to guides show how to implement different strategies for that. + +- [How to manage conversation history](memory/manage-conversation-history.ipynb) +- [How to delete messages](memory/delete-messages.ipynb) +- [How to add summary conversation memory](memory/add-summary-conversation-history.ipynb) + ## Human in the Loop One of LangGraph's main benefits is that it makes human-in-the-loop workflows easy. diff --git a/docs/docs/how-tos/memory/shared-state.ipynb b/docs/docs/how-tos/memory/shared-state.ipynb deleted file mode 100644 index cd1228e7c..000000000 --- a/docs/docs/how-tos/memory/shared-state.ipynb +++ /dev/null @@ -1,465 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "id": "d2eecb96-cf0e-47ed-8116-88a7eaa4236d", - "metadata": {}, - "source": [ - "# How to share state between threads\n", - "\n", - "By default, LangGraph state is scoped to a single thread. LangGraph also allows you to store information that can be **shared** across threads.\n", - "\n", - "For instance, you can persist each user’s preferences to a shared memory and reuse them in new conversational threads.\n", - "\n", - "In this guide, we will show how to construct and use a graph that has a shared memory implemented using the `Store` interface.\n", - "\n", - "
\n", - "

Note

\n", - "

\n", - " Support for the Store API that is used in this notebook was added in LangGraph v0.2.32.\n", - "

\n", - "
\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "3457aadf", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langchain_openai langgraph" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "aa2c64a7", - "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "OPENAI_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "51b6817d", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "c4c550b5-1954-496b-8b9d-800361af17dc", - "metadata": {}, - "source": [ - "## Create graph\n", - "\n", - "In this example we will create a graph that will let us store information about a user's preferences. We will do so by defining an `InMemoryStore` - an object that can store data in memory and query that data. We can then pass the store object when compiling the graph. This allows each node in the graph to access the store: when you define node functions, you can define `store` keyword argument, and LangGraph will automatically pass the store object you compiled the graph with.\n", - "\n", - "When storing objects using the `Store` interface you define two things:\n", - "\n", - "* the namespace for the object, a tuple (similar to directories)\n", - "* the object key (similar to filenames)\n", - "\n", - "In our example, we'll be using `(\"memories\", )` as namespace and random UUID as key for each new memory.\n", - "\n", - "Importantly, to determine the user, we will be passing `user_id` via the config keyword argument of each node function." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "a7f303d6-612e-4e34-bf36-29d4ed25d802", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal, TypedDict, Annotated\n", - "import uuid\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langgraph.graph import StateGraph, MessagesState, START, END\n", - "from langgraph.store.base import BaseStore\n", - "from langgraph.store.memory import InMemoryStore\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "\n", - "# We will give this as a tool to the agent\n", - "# This will let the agent call this tool to save a fact\n", - "class Info(TypedDict):\n", - " \"\"\"This tool should be called when you want to save a new fact about the user.\n", - "\n", - " Attributes:\n", - " fact (str): A fact about the user.\n", - " topic (str): The topic related the fact is about, i.e. Food, Location, Movies, etc.\n", - " \"\"\"\n", - "\n", - " fact: str\n", - " topic: str\n", - "\n", - "\n", - "# This is the prompt we give the agent\n", - "# We will pass known info into the prompt\n", - "# We will tell it to use the Info tool to save more\n", - "prompt = \"\"\"You are a helpful assistant that learns about users to provide better assistance.\n", - "\n", - "Current user information:\n", - "\n", - "{info}\n", - "\n", - "\n", - "Instructions:\n", - "1. Use the `Info` tool to save new information the user shares.\n", - "2. Save facts, opinions, preferences, and experiences.\n", - "3. Your goal: Improve assistance by building a user profile over time.\n", - "\n", - "Remember: Every piece of information helps you serve the user better in future interactions.\n", - "\"\"\"\n", - "\n", - "\n", - "# We give the model access to the Info tool\n", - "model = ChatOpenAI(model=\"gpt-4o-mini\").bind_tools([Info])\n", - "\n", - "\n", - "def call_model(state: MessagesState, config: RunnableConfig, *, store: BaseStore):\n", - " \"\"\"Call the model.\"\"\"\n", - " user_id = config[\"configurable\"][\"user_id\"]\n", - " memories = store.search((\"memories\", user_id))\n", - " info = \"\\n\".join([d.value[\"fact\"] for d in memories])\n", - " # Format system prompt\n", - " system_msg = prompt.format(info=info)\n", - " # Call model\n", - " response = model.invoke(\n", - " [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", - " )\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# Routing function to decide what to do next\n", - "# If no tool calls, then we end\n", - "# If tool calls, then we update memory\n", - "def route(state):\n", - " if len(state[\"messages\"][-1].tool_calls) == 0:\n", - " return END\n", - " else:\n", - " return \"update_memory\"\n", - "\n", - "\n", - "def update_memory(state: MessagesState, config: RunnableConfig, *, store: BaseStore):\n", - " \"\"\"Update the memory.\"\"\"\n", - " user_id = config[\"configurable\"][\"user_id\"]\n", - " memory_id = str(uuid.uuid4())\n", - " tool_calls = []\n", - " memories = {}\n", - " # Each tool call is a new memory to save\n", - " for tc in state[\"messages\"][-1].tool_calls:\n", - " # We append ToolMessages (to pass back to the LLM)\n", - " # This is needed because OpenAI requires each tool call be followed by a ToolMessage\n", - " tool_calls.append(\n", - " {\"role\": \"tool\", \"content\": \"Saved!\", \"tool_call_id\": tc[\"id\"]}\n", - " )\n", - " # We create a new memory from this tool call\n", - " store.put(\n", - " (\"memories\", user_id),\n", - " memory_id,\n", - " {\n", - " \"fact\": tc[\"args\"][\"fact\"],\n", - " \"topic\": tc[\"args\"][\"topic\"],\n", - " },\n", - " )\n", - " # Return the messages and memories to update the state with\n", - " return {\"messages\": tool_calls}\n", - "\n", - "\n", - "# This is the in memory checkpointer we will use\n", - "# We need this because we want to enable threads (conversations)\n", - "checkpointer = MemorySaver()\n", - "\n", - "# This is the in memory store needed to save the memories (i.e. user preferences)\n", - "in_memory_store = InMemoryStore()\n", - "\n", - "# Construct this relatively simple graph\n", - "graph = StateGraph(MessagesState)\n", - "graph.add_node(call_model)\n", - "graph.add_node(update_memory)\n", - "graph.add_edge(\"update_memory\", END)\n", - "graph.add_edge(START, \"call_model\")\n", - "graph.add_conditional_edges(\"call_model\", route, path_map=[END, \"update_memory\"])\n", - "graph = graph.compile(checkpointer=checkpointer, store=in_memory_store)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "5f36c16f-d68d-456c-b0b7-5eb94fb89ca6", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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iAiLQz1cmR1c1DRShlvp5ZKW5SOjnjkfuLoynkaWAEF4Jla53KY3M1z7dGH1qKysudwfR0DpaJlHUQmqqpqb0JmFpe6KEuI2f4MOfotAe4A84PJnWq1UljttNb6GBtNR07BHFE3ua0faepP2nqe8r6UNDTWuip6Ojp4qSjp42ww08DAyOJjRprWtHQAAAADoAF90BERAREQEREGDc7NR3jxU1cDZZKScVNNL3PglALedju9p5XOadd7XuadtcQcayVtWzktty7Se408DHS1sdK6OnqN7Bew7IaSQSYy7bd+sacdusC72WlvcMDKmPmdTzsqYHte5jo5WHbXBzSCPWCAdOa5zTtriCGei0+PXp9e2ahrpaIX2iazx6mo5XPbGXgljhzNa7lcASOmthzdktJW4QEREBERAREQEREBERAREQaO/zT108VmpWyaqmOFZVU9W2GajhLXBr2jRcXOcOVugNaeeYFoB3FPA2mgjhYXlkbQwGR5e4gDXVziST9pJJWhxCLxqS63aVlpkqaurkhFXa3F/aQQvcyJsjz3vb6XM0dGuLgPWTRICIiAiIgIiICIiAiIgn8sqJbNHBe2T1DKagJfW01LRiokqYC0jWgOccjiJPQJOmuHK7Y1vwQRsdQv1T+El8Fl8nPbdXOtkrqAVN506epbHoNm5x/CBzSDznqevN6W0FAiIgIi0l4zfHsfqvFrne7fQVOubsaipYx+vp5Sd6+1Z00VVzamLycW7RS3nTw72ntXvbPvTzp4d7T2r3tn3rbs2NyT0lbTkqUUt508O9p7V72z7086eHe09q97Z96bNjck9JLTkqUUt508O9p7V72z7086eHe09q97Z96bNjck9JLTkqVqMmy6xYXQMrshvVusVE+QQtqbnVR08bnkEhoc8gEkNcdd/Q/Qtb508O9p7V72z71zrwgqbAuOPCW/4lVZNZxNVQl9HM+qj/calnpRP3vp6XQ/YSmzY3JPSS05KvhLxBxbI7cLTasjxC43WN1TUyUGK18U0bIjUOIk5GuLgTzsL3a1zvP0hdDXg3/w6uHli4QY7fcpyu6UFsya6yGhhpamoa2SCljd1JBP+0eN93cxp9a9k+dPDvae1e9s+9NmxuSeklpyVKKW86eHe09q97Z96edPDvae1e9s+9NmxuSeklpyVKKW86eHe09q97Z96edPDvae1e9s+9NmxuSeklpyVKKW86eHe09q97Z96edPDvae1e9s+9NmxuSeklpyVKKZh4m4jUSBkeTWpziQAPHIx3nQ9f0kD+tUy114deH+eJjxLTAiItaCnbZD4nm17Y2G5llXT01UaiZ/NR8454zHEO9rwI2OcO48zSOvMqJTlbD2fEC0ziluMhlt1VC6oik/ecWpIHBsjf+Y70uR30NkHrQUaIiDCvVY63WeuqmAF8EEkrQfpa0kf+ikcSpI6fH6KQDmnqYWTzzO6vmkc0Fz3E9SST/27gqfKvmxeP0Ob/IVPYz83LV+iRf5AujgbsKfFl3NkiIsmIiIgIiICIiAiIgIiICIiAiIg/l7GyMLHtDmuGi1w2CFjcOpOxpr1bWEiltlwNNTs9UcZhilDB/JaZSAO4AADQACy1g8Pf4/mH9MD/R0qVb8KuPD6x6rHCViiIuYgp2+QOdlmNTtpa+bkfURulppeWCEOiJ3M38YEtAb9DiqJTmSU3a5HicviVbUmKtmPbU0vLFT7pZhzzN/GYfwAPU97D6kFGiIg1eVfNi8foc3+Qqexn5uWr9Ei/wAgVDlXzYvH6HN/kKnsZ+blq/RIv8gXRwf0Z8f4ZdzYk6BP0LkVp8IDypwy4cZd5B7L5Y3Kjt3ifjm/FO3c4c/P2f7py8vdpu994XXiNjS83WbgPxBtuO8PcRfW427G8Ov1NcIqxstR43WU0Mjy1rmdnyRvDX9QHODiO9vrk37mLbO8Jm8UliumVV2CiHCbVeKi1V10hvDZKiFsVSac1ApzEOaPYBI5+YddBwGz8uMvGvIKjH+JlswnGp7jTY7bKmC45Gy6NozRVJpjJqnHKXSPia5jzpzNHQBJUJg2AZvxV4d5RiUVTYbdgtyyy7Nr6wumdcjC25SOkijj5ez28tLecu6B34JI2rrK+DOf0Q4mWjD6zG5cazhtRUSMvL546igqpqYQSlnZsc17HcjXDfKWkno7143qmB+ZV4Qlz4S4NjFwr7JRXW2usNNW1FfX5JBSVdS7sgZWwQSAunkAHNrmbzFwAJKzrxxQzKr4+Ypasbt9Fc8WueMyXTsqm4eLF7TPTgznUDzzMa/TY96dzkkt0Nz928HTLzJfYaGfGaqPIMao7DUXC6NmkqLWIqYwyCmaG6ex5cX9XR6cdkO1pUj+Fmc2S5cPchsUuPzX2x487H7nR3CedtLKx3YOMkMjIy7YfAOjmjYd3jSe0NHmPhm2PGL3f4qektNbabDVSUldJNkdLTXCR8Z1N4tRP9OUNOwNuYXlpDQehPoairIbjRwVdO/tIJ42yxvH4zXDYP8AYVxWwcLM74e5DfKTGpMVuOKXa8S3cPvTJxW0JneHzxMaxpbK3m5iwlzSObrvStK/jXjNqrqmimgyLtqaR0L+wxa5yx8zSQeV7KctcNjo5pII6gkLKJnvE1mvHK+2HK8vstiwpl/+TFtp7rWVM12bSNdFI2V3KwGJxMn7i7Q/BOjtzegPyxfwh57jc8c+UGMHG7HktqnvFouLrg2oc6GKJkzxPG1g7J3ZPDxpzx0I2D0X3pMBrsmv3EnJqOeFtuzHH6O329lVFPTzxyRR1TXGaKSNroxudmuhd0OwOm8F3Ae43Cg4S2+4VFE+ixiw1Vnu4ilfzTdtQMpiYNs6jbXHbuU61030U9oaLE/DKs2TZFj1M6itUNpyCsjoqCSmyOlqrix8vSE1FEz0og46B05xYXAOA66+7fCfyCWzWi+Q8OTPZLpe5MeppmXuMTPqxPJBGezMYAidJHouLg5vX0CACaDhJgfEPAobDjl1kxO44xZofFY7pDHO25VMEbC2AOjLRHG8aZzO5375T0BOxq7bwIv9Hw0w7Hn1ltNbZsyGRVEjZZOzdT+UZqnlYeTZk5JGjRAHMD6WuqntDNn8I+SyW3Jae+4tLSZZZ7lRWmOyUFa2pbXT1gaaURTuYwadzHZc0cvK7oViZF4Stxwex5kcnwzyXkmPWyG8stkF0FRBXUskvZc8c4iBBa8EOaY+nTWwdpmfAK9ZLlObX2kuVBR1tZcrLeLFJKHyNiqaBmiKhmh6DyS30XE6dvvGjp814CZxxPt2cXTIa2wUmTXiyQ2C20dvlndRU0DagTvfJK6MPc57/oYAA0Drvae0L2l4s3635Ri1syfEYsfo8kqKilo6pt0FQ+KVkImijmYImtY+RomGmvcA6LQLuYEUXDfPxxFo73XQ0BpKCiu9VbKSo7XtBWsgcI3zD0RygyiVoHX8De+uhB+FlVwjhi2ipJ5Y8xlraepxmOmhdLPJcYZWvj5GgHp3hxd6Ia52+i6JwzwqHhzw/wAfxqB/ai20ccD5vXLIBuSQ/a55c4/a4rKL3sKZYPD3+P5h/TA/0dKs5YPD3+P5h/TA/wBHSrZP6VfhH1hY71iiIuWgpzJoBLkGIvNJcKgxXGVwlo38sMG6OoHPUD8aM75QP+N8Z9So1OZNF2mQYk7xe5S9ncJXdpQv1BF+86gc1SPXGd8oH/MdEfUgo0REGryr5sXj9Dm/yFT2M/Ny1fokX+QKpvNG642iupGEB88EkQJ9Rc0j/uo/EqyOexUcG+SppYWQVFO7o+GRrQHNcD1B3/aNEdCF0MDfhTHvZdzcoiLNiIiICIiAiIgIiICIiAiIgIiICweHv8fzD+mB/o6VZksrII3SSPbGxo2XOOgP61j8O4jLTXm5Na4U1zuBqqdzv9pGIYog8dO53ZEg+sEEdCEq3YVcz7vrCxwlWoiLmIKcyWPtMhxI9hc5eSvld2lE/UEX70nG6keuM70B/wAwxn1KjU7kERlyfFj2V0eI6md/aUT+WmZ+95G/vketp5vRH/Hyn1IKJERAWmvGF4/kNQJ7rYrbcpwOUS1dJHK4D6NuBK3KLKmuqib0zaTglvNXhfsjY/1dD+ynmrwv2Rsf6uh/ZVSi3bRjc89ZZa05pbzV4X7I2P8AV0P7KeavC/ZGx/q6H9lVKJtGNzz1k1pzS3mrwv2Rsf6uh/ZTzV4X7I2P9XQ/sqpRNoxueesmtOaW81eF+yNj/V0P7KeavC/ZGx/q6H9lVKJtGNzz1k1pzcd4KcO8WufD2mqK3HLTW1BrrgwzT0UUjyG1s7Wt2QejWgNA9QAHTWlc+avC/ZGx/q6H9lajgeTFhdbSPcDJR36805HXo0XKpLO/+QWH6OvTougJtGNzz1k1pzS3mrwv2Rsf6uh/ZTzV4X7I2P8AV0P7KqUTaMbnnrJrTmlvNXhfsjY/1dD+ynmrwv2Rsf6uh/ZVSibRjc89ZNac0t5q8L9kbH+rof2U81eF+yNj/V0P7KqUTaMbnnrJrTmm6fhriNJKJIMWs0Mg7nst8QI677+X7FSIi114leJ+eZnxSZmeIiItaCnLvEJs2x3cV1Jihq5RLTHVE3pG3ln+lx59sH8l59So1OuaKjiFG4wXRrqS1uAn5iKB/bSt23X40zewB3+K1/8ALQUSIiAiIgIiICIiAiIgIiIOe4GDYeImeWB7OzZUVMF/pD10+KeIRSAeokTU0riB3CVmx6QJ6Eo/PcbrauptWR2SIS5DZHSGGAvEYraaQAT0hcejQ/kjeCegkhiJOgVvccyKiyqzU9yoHPMEoILJWGOWJ4JD45GHqx7XAtc09WkEHuQbNERAREQEREBERAREQFPY5E6pvN/uUlPcaV0lQ2kYytl3G+OFuhJFH+I1znv697tA92ll368y0HYUtBHT1l3qSHQ0c1U2EuiD2Nll6gktjEgJ009S0dOYFZFjstJjlmorXQMfHR0cTYYhLK6V/K0a257yXPce8ucSSSSSSSUGciIgIiICIiAiIgIiICIiAo3IsRr6K7z5Hij4Ke9ShvjtBUuLKS6BoDW9qWgmOUNAa2ZoJADWua9rWhtkiDQYrmdDljauKJk1Dc6FwjrrXWtDKmlcd8vO0Egtdo8r2lzHgEtcQt+p3K8JpMmkpq2OaW13yj2aO7UehNDvvYd9JInaHNG8Fp0DoOa1w8r8Y/Dvm4QcV8awK7W6Hylb7nEMnuFES6kfRyQ7jMLHAyNeRMyYtJ9AxhgfKHFyD2Ui/iGaOoiZLE9ssT2hzHsO2uB6gg+sL+0BERARFPcQs4tvDXCL3lF3kEdvtVK+pl66LtD0WD7XO00faQgoVqLjkDIap1FQRsudzjfB29HFOxr6eKVzgJpATtrNMkI6bdyEDZXnbwS/C2qPCfsldbKqKgsOU0bah1YKGbT2QHlFPPBDK1/N1eWu2Xta6IFw1Mxq9K222QWqnEUDSXEN7SaQ80szmsawPkeer3crGjmPXoEGPZ7Obf2k9VP5QuMpd2la+FjH8he5zIhyjoxnNytB2dDZLnFzjs0RAREQEREBERAREQEREBERARFOcQcndiOJV1xiDXVYDYaZruoMz3BjNj1gFwJ+wFbMOirFriinjO44tRnnFKmxOoNuoqfynd+UOdFz8kUAPcZHaOiR1DQCSO/QIK8m8Q+AeG8U8jrr9fbDb6e51z3S1EloidSCV56l7tOO3E9S7vcSSe9dEiYWBxe900r3GSSV526R5O3OcfWSdlf0vv8ARvs3R9HpiJpiqe+Zi/lJfJ9ccvOR4nYLdZbXlNwgttvgZTU0UkNNKWRsAa1vO+IuOgAOpPctj8ucy9ra33Sj+AtSi9uzaP8A4qflj0TWltvlzmXtbW+6UfwE+XOZe1tb7pR/AWpRNm0f/FT8sehrS23y5zL2trfdKP4CluJNqruLuLy47ld/uNys0sjJZKVghpw9zTtvM6KNriN9dE62B06BfCx5bR3+836208c7J7NUMpqh0rQGuc6JkoLNEkjleB1A67/Ot0sY0fRqovGHT8sehrSkeEfC/GuB1/ZesZx20zXFjXMbUXCJz6hjXDThHLzHsyRsFwaehI11K9XYTntDmtNIIWPpK+ANM9FMQXM33OBHRzT104fR1APRef1/VPcqux1sF1t/8eo3dpG3ehKPxo3fyXDofo6EdQF4NL+y8HSKJ7OmKau626P9xwWJvxepEWJabnBerVR3Gldz0tXCyoicfWxzQ5p/sIWWvgZiYm0giIoCIiAiIgIiICIiAiIgLmfHsO+TVnI32YusfaaPq7KUDf8A8xaumLR5tjLcvxevtReIpZmB0MpGxHK0h8bj9IDmtJHrGwvZoeLTg6RRiVcIlYedUR0c9PNNTVcDqWsgeYp4H98bx3j7R3EEdCCCOhClrliV7ra+eenze8W+GR3MylgpaJzIx9AL6dziPzklfpM1Wi9MX8LMFSuAcTLfLlvGaey3auslLbae0RVNupsggllp5XF7xNIwMniHaN0wEnmIGta6k9OdhOQOOxxBvjegGhR2/wDt/iy2LsJt91tNNRZJHDlroHue2ovFHTyO2T38rY2sGhobDR3dV5sWicenVmm3jwn3bpHHLZg1JV5fw7sd7uUGX2/yLc5GztLjBURGaB0TSC93aMa1zQOZzvwGnvAK0lFJTzUmL4tfKt8OFDKLzbpmzTuZG9sD5DSU0km/wN700nryNC9Ix2S3Q1FLPHQUrJ6SJ0FPK2FodDGdbYw621p5W7A6dB9Cx6jE7JV26ot89mt81BUyunmpZKVjopZHO5nPc0jRcT1JI2T1WmdE5f7Hs7p927zHOeBtutNpyXiRR2NsLLXDd4Wwsp5OeNv70i5g07PQO2NerWumtLramKnBIKamEOOVZw8OeHzGzUVK3t9NDW8wkicOgAA0AdDXcsT5EZBr/wBoV89zt/8A/MvRhxVg06mrfjwtbfN8xZIp+wY3dbTWumrcrud7hLC0U1ZT0jGA7HpbihY7Y0R36693cqe22Kqyq5RWeh2JqjQllA/i8O9PkP5hvlHrdofTrdNcU0zXXuiMyIu7jwkD/Nrjpfv0qRjm7/4D1b/+JCrl8KGihttFT0lNGIqeCNsUbB3Na0aA/sC+6/MMavtMSquO+ZlnO+RERakEREBERAREQEREBERAREQSebcOLbmnJUPfJQXSNnJHX04HPy9SGPBGnt2SdHqNnlLdkrmtXwbyulkcIJbTcIgTqQzSU7z9HocjwP8A713ZF09H+0tI0anUom8ZSt83APNRmX1K2e/u+EnmozL6lbPf3fCXf0Xs++tJyjpPqbsnAPNRmX1K2e/u+EnmozL6lbPf3fCXf0T760nKOk+puycA81GZfUrZ7+74SeafMvqVs9/d8Jd/RPvrSco6T6m7Jw+28FckrJQLjW262Qes0rn1MhH2czWBp+30vzFdUxTDrbhtC6noI3GSTRmqZiHTTkdxe7Q+3QAAGzoBbxF4dJ0/SNKjVxJ3ZQCIi5yCIiD/2Q==", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "id": "552d4e33-556d-4fa5-8094-2a076bc21529", - "metadata": {}, - "source": [ - "## Run graph on one thread\n", - "\n", - "We can now run the graph on one thread and give it some information" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "18bd8679-3a73-4033-bfb4-5093ac1f5d7f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'call_model': {'messages': [AIMessage(content='Hello! How can I assist you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 178, 'total_tokens': 188, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_74ba47b4ac', 'finish_reason': 'stop', 'logprobs': None}, id='run-8e7b57b7-8231-4811-945d-a2cf2e1adba3-0', usage_metadata={'input_tokens': 178, 'output_tokens': 10, 'total_tokens': 188})]}}\n", - "{'call_model': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_mpPvip6DbMYkZueShwDDws3y', 'function': {'arguments': '{\"fact\":\"User likes pepperoni pizza\",\"topic\":\"Food\"}', 'name': 'Info'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 21, 'prompt_tokens': 200, 'total_tokens': 221, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_74ba47b4ac', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-5cd7b512-071b-49ac-9932-de0130774a1e-0', tool_calls=[{'name': 'Info', 'args': {'fact': 'User likes pepperoni pizza', 'topic': 'Food'}, 'id': 'call_mpPvip6DbMYkZueShwDDws3y', 'type': 'tool_call'}], usage_metadata={'input_tokens': 200, 'output_tokens': 21, 'total_tokens': 221})]}}\n", - "{'update_memory': {'messages': [{'role': 'tool', 'content': 'Saved!', 'tool_call_id': 'call_mpPvip6DbMYkZueShwDDws3y'}]}}\n", - "{'call_model': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Jqn1cbXFQcVl4hGrbB660kw1', 'function': {'arguments': '{\"fact\":\"User just moved to San Francisco\",\"topic\":\"Location\"}', 'name': 'Info'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 246, 'total_tokens': 268, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_74ba47b4ac', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-9490584d-1678-47db-bb0a-d0797a7af7c3-0', tool_calls=[{'name': 'Info', 'args': {'fact': 'User just moved to San Francisco', 'topic': 'Location'}, 'id': 'call_Jqn1cbXFQcVl4hGrbB660kw1', 'type': 'tool_call'}], usage_metadata={'input_tokens': 246, 'output_tokens': 22, 'total_tokens': 268})]}}\n", - "{'update_memory': {'messages': [{'role': 'tool', 'content': 'Saved!', 'tool_call_id': 'call_Jqn1cbXFQcVl4hGrbB660kw1'}]}}\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"1\", \"user_id\": \"1\"}}\n", - "\n", - "# First let's just say hi to the AI\n", - "for update in graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": \"hi\"}]}, config, stream_mode=\"updates\"\n", - "):\n", - " print(update)\n", - "\n", - "# Let's continue the conversation (by passing the same config) and tell the AI we like pepperoni pizza\n", - "for update in graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": \"i like pepperoni pizza\"}]},\n", - " config,\n", - " stream_mode=\"updates\",\n", - "):\n", - " print(update)\n", - "\n", - "# Let's continue the conversation even further (by passing the same config) and tell the AI we live in SF\n", - "for update in graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": \"i also just moved to SF\"}]},\n", - " config,\n", - " stream_mode=\"updates\",\n", - "):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "id": "16f19db5-ff4a-4666-9be5-ef791c39be0a", - "metadata": {}, - "source": [ - "We can now inspect our in-memory store and verify that we have in fact saved the memories for the user:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "57335ef9-c6fc-40d8-8dd7-dce8a600d05b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'fact': 'User likes pepperoni pizza', 'topic': 'Food'}\n", - "{'fact': 'User just moved to San Francisco', 'topic': 'Location'}\n" - ] - } - ], - "source": [ - "for memory in in_memory_store.search((\"memories\", \"1\")):\n", - " print(memory.value)" - ] - }, - { - "cell_type": "markdown", - "id": "b8c416fa-086a-491d-a7d3-57091f6413e3", - "metadata": {}, - "source": [ - "## Run graph on a different thread\n", - "\n", - "We can now run the graph on a different thread and see that it remembers facts about the user (specifically that the user likes pepperoni pizza and lives in SF):" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "e240f025-ff8b-4d17-beb7-2420c0575dd9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'call_model': {'messages': [AIMessage(content=\"Since you like pepperoni pizza, I can recommend a few places in San Francisco where you can enjoy some delicious pizza. Here are some options:\\n\\n1. **Tony's Pizza Napoletana** - Located in North Beach, this restaurant is famous for its award-winning pizzas. You can find a variety of styles, including classic pepperoni.\\n\\n2. **Pizza Orgasmica** - Known for its fun atmosphere and a wide range of pizza options, including pepperoni, this spot is a local favorite.\\n\\n3. **Little Star Pizza** - This place offers deep-dish and thin-crust options. Their pepperoni pizza is highly recommended.\\n\\n4. **Pizzeria Delfina** - A popular spot known for its artisanal pizzas, including a delicious pepperoni option.\\n\\n5. **The Pizza Place on Noriega** - A casual eatery offering classic pizza options in the Sunset District.\\n\\nWould you like more options, or are you interested in a specific neighborhood for dinner?\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 198, 'prompt_tokens': 205, 'total_tokens': 403, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_74ba47b4ac', 'finish_reason': 'stop', 'logprobs': None}, id='run-e5d7ff2e-1665-49c4-83dd-ec9b3e693b3c-0', usage_metadata={'input_tokens': 205, 'output_tokens': 198, 'total_tokens': 403})]}}\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"2\", \"user_id\": \"1\"}}\n", - "\n", - "for update in graph.stream(\n", - " {\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"where and what should i eat for dinner? Can you list some restaurants?\",\n", - " }\n", - " ]\n", - " },\n", - " config,\n", - " stream_mode=\"updates\",\n", - "):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "id": "091995d3", - "metadata": {}, - "source": [ - "Perfect! The AI recommended restaurants in SF, and included a pizza restaurant at the top of it's list.\n", - "\n", - "Notice that the `messages` in this new thread do NOT contain the messages from the previous thread since we didn't store them as shared values across the `user_id`. However, the `info` we saved in the previous thread was saved since we passed in the same `user_id` in this new thread.\n", - "\n", - "Let's now run the graph for another user to verify that the preferences of the first user are self contained:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "f9bf2c15", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'call_model': {'messages': [AIMessage(content=\"To help you better, could you please share your location or the area you're interested in? Additionally, do you have any preferences for cuisine or dietary restrictions?\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 32, 'prompt_tokens': 192, 'total_tokens': 224, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_74ba47b4ac', 'finish_reason': 'stop', 'logprobs': None}, id='run-fba82c81-703a-4f5e-bd1a-1edf5876425e-0', usage_metadata={'input_tokens': 192, 'output_tokens': 32, 'total_tokens': 224})]}}\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"3\", \"user_id\": \"2\"}}\n", - "\n", - "for update in graph.stream(\n", - " {\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"where and what should i eat for dinner? Can you list some restaurants?\",\n", - " }\n", - " ]\n", - " },\n", - " config,\n", - " stream_mode=\"updates\",\n", - "):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "id": "b7086cea", - "metadata": {}, - "source": [ - "Perfect! The graph has forgotten all of the previous preferences and has to ask the user for it's location and dietary preferences.\n", - "\n", - "We can also verify that there are no memories stored for user \"2\":" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "dea8be21-c4a0-434c-87ab-706c138beb23", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "in_memory_store.search((\"memories\", \"2\"))" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/persistence.ipynb b/docs/docs/how-tos/persistence.ipynb index 8c71bcb8e..caae5b363 100644 --- a/docs/docs/how-tos/persistence.ipynb +++ b/docs/docs/how-tos/persistence.ipynb @@ -5,7 +5,7 @@ "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", "metadata": {}, "source": [ - "# How to add persistence (\"memory\") to your graph\n", + "# How to add thread-level persistence to your graph\n", "\n", "
\n", "

Prerequisites

\n", @@ -27,59 +27,29 @@ " Chat Models\n", " \n", " \n", - "
  • \n", - " \n", - " Tool calling agent\n", - " \n", - "
  • \n", " \n", "

    \n", "
    \n", "\n", + "Many AI applications need memory to share context across multiple interactions. In LangGraph, this kind of memory can be added to any [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph) using [thread-level persistence](https://langchain-ai.github.io/langgraph/concepts/persistence) .\n", "\n", - "Many AI applications need memory to share context across multiple interactions. In LangGraph, memory is provided for any [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph) through [Checkpointers](https://github.com/langchain-ai/langgraph/tree/e4ca7ab69c599fd77dd4f0d47280849d715392cc/libs/checkpoint).\n", - "\n", - "When creating any LangGraph workflow, you can set them up to persist their state by doing using the following:\n", - "\n", - "1. A [Checkpointer](https://langchain-ai.github.io/langgraph/reference/checkpoints/#basecheckpointsaver).\n", - "2. Call `compile(checkpointer=my_checkpointer)` when compiling the graph.\n", - "\n", - "There are several options for checkpointers to use.\n", - "\n", - "1. [MemorySaver](https://langchain-ai.github.io/langgraph/reference/checkpoints/#memorysaver) is an in-memory key-value store for Graph state.\n", - "2. [SqliteSaver](https://langchain-ai.github.io/langgraph/reference/checkpoints/#sqlitesaver) allows you to save to a Sqlite db locally or in memory.\n", - "3. There are various external databases that can be used for persistence, such as [Postgres](https://langchain-ai.github.io/langgraph/how-tos/persistence_postgres/), [MongoDB](https://langchain-ai.github.io/langgraph/how-tos/persistence_mongodb/), and [Redis](https://langchain-ai.github.io/langgraph/how-tos/persistence_redis/).\n", - " \n", - "Here is an example using the built-in [MemorySaver](https://langchain-ai.github.io/langgraph/reference/checkpoints/#memorysaver) checkpointer:\n", + "When creating any LangGraph graph, you can set it up to persist its state by adding a [checkpointer](https://langchain-ai.github.io/langgraph/reference/checkpoints/#basecheckpointsaver) when compiling the graph:\n", "\n", "```python\n", - "from langgraph.graph import StateGraph\n", "from langgraph.checkpoint.memory import MemorySaver\n", "\n", - "builder = StateGraph(....)\n", - "# ... define the graph\n", - "memory = MemorySaver()\n", - "graph = builder.compile(checkpointer=memory)\n", - "...\n", + "checkpointer = MemorySaver()\n", + "graph.compile(checkpointer=checkpointer)\n", "```\n", "\n", - "This works for [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph) and all its subclasses, such as [MessageGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#messagegraph).\n", - "\n", - "This guide shows how you can add memory to your graph.\n", + "This guide shows how you can add thread-level persistence to your graph.\n", "\n", "
    \n", "

    Note

    \n", "

    \n", - " In this how-to, we add memory that is scoped to a single conversation (session). If you need memory that is shared across multiple conversations or users, check out this how-to guide).\n", + " If you need memory that is shared across multiple conversations or users (cross-thread persistence), check out this how-to guide).\n", "

    \n", - "
    \n", - "\n", - "
    \n", - "

    Note

    \n", - "

    \n", - " In this how-to, we will create our agent from scratch to be transparent (but verbose). You can accomplish similar functionality using the create_react_agent(model, tools=tool, checkpointer=checkpointer) (API doc) constructor. This may be more appropriate if you are used to LangChain’s AgentExecutor class.\n", - "

    \n", - "
    " + "" ] }, { @@ -94,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", "metadata": {}, "outputs": [], @@ -113,10 +83,18 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 2, "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "ANTHROPIC_API_KEY: ········\n" + ] + } + ], "source": [ "import getpass\n", "import os\n", @@ -148,242 +126,98 @@ "id": "4cf509bc", "metadata": {}, "source": [ - "## Define graph state\n", + "## Define graph\n", "\n", - "The state is the interface for all the nodes." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "14619607", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", + "We will be using a single-node graph that calls a [chat model](https://python.langchain.com/docs/concepts/#chat-models).\n", "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph.message import add_messages\n", - "\n", - "# Add messages essentially does this with more\n", - "# robust handling\n", - "# def add_messages(left: list, right: list):\n", - "# return left + right\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]" - ] - }, - { - "cell_type": "markdown", - "id": "21ac643b-cb06-4724-a80c-2862ba4773f1", - "metadata": {}, - "source": [ - "## Define tools\n", - "\n", - "We will first define the tools we want to use.\n", - "For this simple example, we will use create a placeholder search engine.\n", - "However, it is really easy to create your own tools - see documentation [here](https://python.langchain.com/docs/how_to/custom_tools) on how to do that.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "d7ef57dd-5d6e-4ad3-9377-a92201c1310e", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.tools import tool\n", - "\n", - "\n", - "@tool\n", - "def search(query: str):\n", - " \"\"\"Call to surf the web.\"\"\"\n", - " # This is a placeholder for the actual implementation\n", - " return [\"The answer to your question lies within.\"]\n", - "\n", - "\n", - "tools = [search]" - ] - }, - { - "cell_type": "markdown", - "id": "01885785-b71a-44d1-b1d6-7b5b14d53b58", - "metadata": {}, - "source": [ - "Now we can create our [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/?h=tool+node#toolnode). This \n", - "object actually **runs** the tools (aka functions) that the LLM has asked to use." + "Let's first define the model we'll be using:" ] }, { "cell_type": "code", "execution_count": 3, - "id": "5cf3331e-ccb3-41c8-aeb9-a840a94d41e7", + "id": "892b54b9-75f0-4804-9ed0-88b5e5532989", "metadata": {}, "outputs": [], "source": [ - "from langgraph.prebuilt import ToolNode\n", + "from langchain_anthropic import ChatAnthropic\n", "\n", - "tool_node = ToolNode(tools)" + "model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")" ] }, { "cell_type": "markdown", - "id": "5497ed70-fce3-47f1-9cad-46f912bad6a5", + "id": "7b7a2792-982b-4e47-83eb-0c594725d1c1", "metadata": {}, "source": [ - "## Define the model\n", - "\n", - "Now we need to load the [chat model](https://python.langchain.com/docs/concepts/#chat-models) to power our agent.\n", - "For the design below, it must satisfy two criteria:\n", - "\n", - "1. It should work with **messages** (since our state contains a list of chat messages)\n", - "2. It should work with [**tool calling**](https://python.langchain.com/docs/concepts/#functiontool-calling).\n", - "\n", - "
    \n", - "

    Note

    \n", - "

    \n", - " These model requirements are not general requirements for using LangGraph - they are just requirements for this one example.\n", - "

    \n", - "
    \n", - " " + "Now we can define our `StateGraph` and add our model-calling node:" ] }, { "cell_type": "code", "execution_count": 4, - "id": "892b54b9-75f0-4804-9ed0-88b5e5532989", + "id": "87326ea6-34c5-46da-a41f-dda26ef9bd74", "metadata": {}, "outputs": [], "source": [ - "from langchain_openai import ChatOpenAI\n", + "from typing import Annotated\n", + "from typing_extensions import TypedDict\n", "\n", - "# We will set streaming=True so that we can stream tokens\n", - "# See the streaming section for more information on this.\n", - "model = ChatOpenAI(temperature=0, streaming=True)" + "from langgraph.graph import StateGraph, MessagesState, START\n", + "\n", + "\n", + "def call_model(state: MessagesState):\n", + " response = model.invoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + "\n", + "\n", + "builder = StateGraph(MessagesState)\n", + "builder.add_node(\"call_model\", call_model)\n", + "builder.add_edge(START, \"call_model\")\n", + "graph = builder.compile()" ] }, { "cell_type": "markdown", - "id": "a77995c0-bae2-4cee-a036-8688a90f05b9", + "id": "250d8fd9-2e7a-4892-9adc-19762a1e3cce", "metadata": {}, "source": [ - "\n", - "After we've done this, we should make sure the model knows that it has these tools available to call.\n", - "We can do this by converting the LangChain tools into the format for OpenAI function calling, and then bind them to the model class.\n" + "If we try to use this graph, the context of the conversation will not be persisted across interactions:" ] }, { "cell_type": "code", "execution_count": 5, - "id": "cd3cbae5-d92c-4559-a4aa-44721b80d107", + "id": "6fa9a5e3-7101-43ab-a811-592e222b9580", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "hi! I'm bob\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Hello Bob! It's nice to meet you. How are you doing today? Is there anything I can help you with or would you like to chat about something in particular?\n", + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "what's my name?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "I apologize, but I don't have access to your personal information, including your name. I'm an AI language model designed to provide general information and answer questions to the best of my ability based on my training data. I don't have any information about individual users or their personal details. If you'd like to share your name, you're welcome to do so, but I won't be able to recall it in future conversations.\n" + ] + } + ], "source": [ - "bound_model = model.bind_tools(tools)" - ] - }, - { - "cell_type": "markdown", - "id": "e03c5094-9297-4d19-a04e-3eedc75cefb4", - "metadata": {}, - "source": [ - "## Define nodes and edges \n", + "input_message = {\"type\": \"user\", \"content\": \"hi! I'm bob\"}\n", + "for chunk in graph.stream({\"messages\": [input_message]}, stream_mode=\"values\"):\n", + " chunk[\"messages\"][-1].pretty_print()\n", "\n", - "We now need to define a few different nodes in our graph.\n", - "In `langgraph`, a node can be either a function or a [runnable](https://python.langchain.com/docs/concepts/#langchain-expression-language-lcel).\n", - "There are two main nodes we need for this:\n", - "\n", - "1. The agent: responsible for deciding what (if any) actions to take.\n", - "2. A function to invoke tools: if the agent decides to take an action, this node will then execute that action.\n", - "\n", - "We will also need to define some edges.\n", - "Some of these edges may be conditional.\n", - "The reason they are conditional is that based on the output of a node, one of several paths may be taken.\n", - "The path that is taken is not known until that node is run (the LLM decides).\n", - "\n", - "1. Conditional Edge: after the agent is called, we should either:\n", - " a. If the agent said to take an action, then the function to invoke tools should be called\n", - " b. If the agent said that it was finished, then it should finish\n", - "2. Normal Edge: after the tools are invoked, it should always go back to the agent to decide what to do next\n", - "\n", - "Let's define the nodes, as well as a function to decide how what conditional edge to take." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "3b541bb9-900c-40d0-964d-7b5dfee30667", - "metadata": {}, - "outputs": [], - "source": [ - "# Define the function that determines whether to continue or not\n", - "from typing import Literal\n", - "from langgraph.graph import END\n", - "\n", - "\n", - "def should_continue(state: State):\n", - " \"\"\"Return the next node to execute.\"\"\"\n", - " last_message = state[\"messages\"][-1]\n", - " # If there is no function call, then we finish\n", - " if not last_message.tool_calls:\n", - " return END\n", - " # Otherwise if there is, we continue\n", - " return \"action\"\n", - "\n", - "\n", - "# Define the function that calls the model\n", - "def call_model(state: State):\n", - " response = model.invoke(state[\"messages\"])\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": response}" - ] - }, - { - "cell_type": "markdown", - "id": "ffd6e892-946c-4899-8cc0-7c9291c1f73b", - "metadata": {}, - "source": [ - "## Compile the graph\n", - "\n", - "We can now put it all together and define the graph!" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "812b4e70-4956-4415-8880-db48b3dcbad2", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import StateGraph, START\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(State)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# Set the entrypoint as `agent`\n", - "# This means that this node is the first one called\n", - "workflow.add_edge(START, \"agent\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `agent`.\n", - " # This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - " [\"action\", END],\n", - ")\n", - "\n", - "# We now add a normal edge from `tools` to `agent`.\n", - "# This means that after `tools` is called, `agent` node is called next.\n", - "workflow.add_edge(\"action\", \"agent\")" + "input_message = {\"type\": \"user\", \"content\": \"what's my name?\"}\n", + "for chunk in graph.stream({\"messages\": [input_message]}, stream_mode=\"values\"):\n", + " chunk[\"messages\"][-1].pretty_print()" ] }, { @@ -391,34 +225,23 @@ "id": "bc9c8536-f90b-44fa-958d-5df016c66d8f", "metadata": {}, "source": [ - "### Persistence\n", + "## Add persistence\n", "\n", - "To add in persistence, we pass in a checkpoint when compiling the graph" + "To add in persistence, we need to pass in a [Checkpointer](https://langchain-ai.github.io/langgraph/reference/checkpoints/#langgraph.checkpoint.base.BaseCheckpointSaver) when compiling the graph." ] }, { "cell_type": "code", - "execution_count": 8, - "id": "6845ed6a-d155-4105-9160-28849877248b", + "execution_count": 6, + "id": "f088933f-264c-477f-9a7d-03f6e9d4ee3a", "metadata": {}, "outputs": [], "source": [ "from langgraph.checkpoint.memory import MemorySaver\n", "\n", - "memory = MemorySaver()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "79d29875-8aa8-434c-9f20-1c58346a6249", - "metadata": {}, - "outputs": [], - "source": [ - "# Finally, we compile it!\n", - "# This compiles it into a LangChain Runnable,\n", - "# meaning you can use it as you would any other runnable\n", - "app = workflow.compile(checkpointer=memory)" + "memory = MemorySaver()\n", + "graph = builder.compile(checkpointer=memory)\n", + "# If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass the checkpointer when compiling the graph, since it's done automatically." ] }, { @@ -429,51 +252,22 @@ "
    \n", "

    Note

    \n", "

    \n", - " If you're using LangGraph Cloud, you don't need to pass checkpointer when compiling the graph, since it's done automatically.\n", + " If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass checkpointer when compiling the graph, since it's done automatically.\n", "

    \n", "
    " ] }, - { - "cell_type": "code", - "execution_count": 10, - "id": "0d49697f", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(app.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, { "cell_type": "markdown", "id": "2a1b56c5-bd61-4192-8bdb-458a1e9f0159", "metadata": {}, "source": [ - "## Use the graph\n", - "\n", - "We can now interact with the agent and see that it remembers previous messages!\n" + "We can now interact with the agent and see that it remembers previous messages!" ] }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 7, "id": "cfd140f0-a5a6-4697-8115-322242f197b5", "metadata": {}, "outputs": [ @@ -486,22 +280,28 @@ "hi! I'm bob\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Hello Bob! How can I assist you today?\n" + "Hello Bob! It's nice to meet you. How are you doing today? Is there anything in particular you'd like to chat about or any questions you have that I can help you with?\n" ] } ], "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "input_message = HumanMessage(content=\"hi! I'm bob\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" + "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + "input_message = {\"type\": \"user\", \"content\": \"hi! I'm bob\"}\n", + "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", + " chunk[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "1bb07bf8-68b7-4049-a0f1-eb67a4879a3a", + "metadata": {}, + "source": [ + "You can always resume previous threads:" ] }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 8, "id": "08ae8246-11d5-40e1-8567-361e5bef8917", "metadata": {}, "outputs": [ @@ -511,17 +311,17 @@ "text": [ "================================\u001b[1m Human Message \u001b[0m=================================\n", "\n", - "what is my name?\n", + "what's my name?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Your name is Bob.\n" + "Your name is Bob, as you introduced yourself at the beginning of our conversation.\n" ] } ], "source": [ - "input_message = HumanMessage(content=\"what is my name?\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" + "input_message = {\"type\": \"user\", \"content\": \"what's my name?\"}\n", + "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", + " chunk[\"messages\"][-1].pretty_print()" ] }, { @@ -529,12 +329,12 @@ "id": "3f47bbfc-d9ef-4288-ba4a-ebbc0136fa9d", "metadata": {}, "source": [ - "If we want to start a new conversation, we can pass in a different thread id. Poof! All the memories are gone!" + "If we want to start a new conversation, we can pass in a different `thread_id`. Poof! All the memories are gone!" ] }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 9, "id": "273d56a8-f40f-4a51-a27f-7c6bb2bda0ba", "metadata": {}, "outputs": [ @@ -544,58 +344,21 @@ "text": [ "================================\u001b[1m Human Message \u001b[0m=================================\n", "\n", - "what is my name?\n", + "what's is my name?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "I'm sorry, I do not know your name as I am an AI assistant and do not have access to personal information.\n" + "I apologize, but I don't have access to your personal information, including your name. As an AI language model, I don't have any information about individual users unless it's provided within the conversation. If you'd like to share your name, you're welcome to do so, but otherwise, I won't be able to know or guess it.\n" ] } ], "source": [ - "input_message = HumanMessage(content=\"what is my name?\")\n", - "for event in app.stream(\n", - " {\"messages\": [input_message]},\n", - " {\"configurable\": {\"thread_id\": \"3\"}},\n", - " stream_mode=\"values\",\n", - "):\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "e833f994", - "metadata": {}, - "source": [ - "All the checkpoints are persisted to the checkpointer, so you can always resume previous threads." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "8578a66d-6489-4e03-8c23-fd0530278455", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "You forgot??\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I apologize for the confusion. I am an AI assistant and I do not have the ability to remember information from previous interactions. How can I assist you today, Bob?\n" - ] - } - ], - "source": [ - "input_message = HumanMessage(content=\"You forgot??\")\n", - "for event in app.stream(\n", + "input_message = {\"type\": \"user\", \"content\": \"what's my name?\"}\n", + "for chunk in graph.stream(\n", " {\"messages\": [input_message]},\n", " {\"configurable\": {\"thread_id\": \"2\"}},\n", " stream_mode=\"values\",\n", "):\n", - " event[\"messages\"][-1].pretty_print()" + " chunk[\"messages\"][-1].pretty_print()" ] } ], @@ -615,7 +378,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 20c60d863..8fd5f6c68 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -136,14 +136,15 @@ nav: - Create map-reduce branches for parallel execution: how-tos/map-reduce.ipynb - Control graph recursion limit: how-tos/recursion-limit.ipynb - Persistence: - - Add persistence ("memory"): how-tos/persistence.ipynb - - Manage conversation history: how-tos/memory/manage-conversation-history.ipynb - - Delete messages: how-tos/memory/delete-messages.ipynb - - Add summary of the conversation history: how-tos/memory/add-summary-conversation-history.ipynb - - Share state between threads: how-tos/memory/shared-state.ipynb + - Add thread-level persistence: how-tos/persistence.ipynb + - Add cross-thread persistence: how-tos/cross-thread-persistence.ipynb - Use Postgres checkpointer for persistence: how-tos/persistence_postgres.ipynb - Create custom checkpointer using MongoDB: how-tos/persistence_mongodb.ipynb - Create custom checkpointer using Redis: how-tos/persistence_redis.ipynb + - Memory: + - Manage conversation history: how-tos/memory/manage-conversation-history.ipynb + - Delete messages: how-tos/memory/delete-messages.ipynb + - Add summary of the conversation history: how-tos/memory/add-summary-conversation-history.ipynb - Human-in-the-loop: - Add breakpoints: how-tos/human_in_the_loop/breakpoints.ipynb - Add dynamic breakpoints: how-tos/human_in_the_loop/dynamic_breakpoints.ipynb