Clean up old swarm code

This commit is contained in:
akhisud3195 2025-03-21 15:45:22 +05:30 committed by Ramnique Singh
parent 6ea2d6b568
commit 1fa5c39716
15 changed files with 245 additions and 790 deletions

181
apps/agents/poetry.lock generated
View file

@ -86,6 +86,87 @@ files = [
{file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"},
]
[[package]]
name = "cffi"
version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
{file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
{file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
{file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
{file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
{file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
{file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
{file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
{file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
{file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
{file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
{file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
{file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
{file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
{file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
{file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
{file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
{file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
{file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
{file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
{file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
]
[package.dependencies]
pycparser = "*"
[[package]]
name = "charset-normalizer"
version = "3.4.1"
@ -212,7 +293,7 @@ description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["main"]
markers = "python_version <= \"3.11\" and platform_system == \"Windows\" or python_version >= \"3.12\" and platform_system == \"Windows\""
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@ -342,6 +423,22 @@ Werkzeug = ">=3.1"
async = ["asgiref (>=3.2)"]
dotenv = ["python-dotenv"]
[[package]]
name = "griffe"
version = "1.6.2"
description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "griffe-1.6.2-py3-none-any.whl", hash = "sha256:6399f7e663150e4278a312a8e8a14d2f3d7bd86e2ef2f8056a1058e38579c2ee"},
{file = "griffe-1.6.2.tar.gz", hash = "sha256:3a46fa7bd83280909b63c12b9a975732a927dd97809efe5b7972290b606c5d91"},
]
[package.dependencies]
colorama = ">=0.4"
[[package]]
name = "gunicorn"
version = "23.0.0"
@ -912,15 +1009,15 @@ files = [
[[package]]
name = "openai"
version = "1.59.7"
version = "1.68.0"
description = "The official Python library for the openai API"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "openai-1.59.7-py3-none-any.whl", hash = "sha256:cfa806556226fa96df7380ab2e29814181d56fea44738c2b0e581b462c268692"},
{file = "openai-1.59.7.tar.gz", hash = "sha256:043603def78c00befb857df9f0a16ee76a3af5984ba40cb7ee5e2f40db4646bf"},
{file = "openai-1.68.0-py3-none-any.whl", hash = "sha256:20e279b0f3a78cb4a95f3eab2a180f3ee30c6a196aeebd6bf642a4f88ab85ee1"},
{file = "openai-1.68.0.tar.gz", hash = "sha256:c570c06c9ba10f98b891ac30a3dd7b5c89ed48094c711c7a3f35fb5ade6c0757"},
]
[package.dependencies]
@ -928,8 +1025,10 @@ anyio = ">=3.5.0,<5"
distro = ">=1.7.0,<2"
httpx = ">=0.23.0,<1"
jiter = ">=0.4.0,<1"
numpy = ">=2.0.2"
pydantic = ">=1.9.0,<3"
sniffio = "*"
sounddevice = ">=0.5.1"
tqdm = ">4"
typing-extensions = ">=4.11,<5"
@ -937,6 +1036,27 @@ typing-extensions = ">=4.11,<5"
datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
realtime = ["websockets (>=13,<15)"]
[[package]]
name = "openai-agents"
version = "0.0.4"
description = "OpenAI Agents SDK"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "openai_agents-0.0.4-py3-none-any.whl", hash = "sha256:5577c3ee994fe0bd200d7283e4f7a614b3af19afeebcfb07b6ca6039a8a50a5c"},
{file = "openai_agents-0.0.4.tar.gz", hash = "sha256:297e8d5faeca753e1b303d860b7ac94d03a7e10382be738163dc6a10a3b7cc1c"},
]
[package.dependencies]
griffe = ">=1.5.6,<2"
openai = ">=1.66.2"
pydantic = ">=2.10,<3"
requests = ">=2.0,<3"
types-requests = ">=2.0,<3"
typing-extensions = ">=4.12.2,<5"
[[package]]
name = "openpyxl"
version = "3.1.5"
@ -1054,6 +1174,19 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d
test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"]
xml = ["lxml (>=4.9.2)"]
[[package]]
name = "pycparser"
version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
[[package]]
name = "pydantic"
version = "2.10.5"
@ -1406,6 +1539,28 @@ files = [
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
[[package]]
name = "sounddevice"
version = "0.5.1"
description = "Play and Record Sound with Python"
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "sounddevice-0.5.1-py3-none-any.whl", hash = "sha256:e2017f182888c3f3c280d9fbac92e5dbddac024a7e3442f6e6116bd79dab8a9c"},
{file = "sounddevice-0.5.1-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:d16cb23d92322526a86a9490c427bf8d49e273d9ccc0bd096feecd229cde6031"},
{file = "sounddevice-0.5.1-py3-none-win32.whl", hash = "sha256:d84cc6231526e7a08e89beff229c37f762baefe5e0cc2747cbe8e3a565470055"},
{file = "sounddevice-0.5.1-py3-none-win_amd64.whl", hash = "sha256:4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1"},
{file = "sounddevice-0.5.1.tar.gz", hash = "sha256:09ca991daeda8ce4be9ac91e15a9a81c8f81efa6b695a348c9171ea0c16cb041"},
]
[package.dependencies]
CFFI = ">=1.0"
[package.extras]
numpy = ["NumPy"]
[[package]]
name = "soupsieve"
version = "2.6"
@ -1458,6 +1613,22 @@ notebook = ["ipywidgets (>=6)"]
slack = ["slack-sdk"]
telegram = ["requests"]
[[package]]
name = "types-requests"
version = "2.32.0.20250306"
description = "Typing stubs for requests"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "types_requests-2.32.0.20250306-py3-none-any.whl", hash = "sha256:25f2cbb5c8710b2022f8bbee7b2b66f319ef14aeea2f35d80f18c9dbf3b60a0b"},
{file = "types_requests-2.32.0.20250306.tar.gz", hash = "sha256:0962352694ec5b2f95fda877ee60a159abdf84a0fc6fdace599f20acb41a03d1"},
]
[package.dependencies]
urllib3 = ">=2"
[[package]]
name = "typing-extensions"
version = "4.12.2"
@ -1655,4 +1826,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<4.0"
content-hash = "ef220af6b184e760ccc9b45e26ec9f58a54cb9327c562a612798433a7f9c08e4"
content-hash = "ee79f77afa3bbdb99810fd4a1a9cae366a307e2af74fd70c6d3376c6fdab61b3"

View file

@ -41,6 +41,7 @@ mypy-extensions = "^1.0.0"
nest-asyncio = "^1.6.0"
numpy = "^2.1.2"
openai = "^1.52.2"
openai-agents = "^0.0.4"
openpyxl = "^3.1.5"
pandas = "^2.2.3"
pydantic = "^2.9.2"

View file

@ -43,6 +43,7 @@ mypy-extensions==1.0.0
nest-asyncio==1.6.0
numpy==2.2.1
openai==1.59.7
openai-agents==0.0.4
openpyxl==3.1.5
packaging==24.2
pandas==2.2.3

View file

@ -37,67 +37,49 @@ def require_api_key(f):
@app.route("/chat", methods=["POST"])
@require_api_key
def chat():
print('='*200)
logger.info('='*200)
logger.info(f"{'*'*50}Running server mode{'*'*50}")
try:
data = request.get_json()
print('Complete request:')
logger.info('Complete request')
print(data)
logger.info('Complete request:')
logger.info(data)
print('-'*200)
logger.info('-'*200)
start_time = datetime.now()
config = read_json_from_file("./configs/default_config.json")
logger.info('Beginning turn')
resp_messages, resp_tokens_used, resp_state = run_turn(
messages=data.get("messages", []),
start_agent_name=data.get("startAgent", ""),
agent_configs=data.get("agents", []),
tool_configs=data.get("tools", []),
localize_history=config.get("localize_history", True),
return_diff_messages=config.get("return_diff_messages", True),
prompt_configs=data.get("prompts", []),
start_turn_with_start_agent=config.get("start_turn_with_start_agent", False),
children_aware_of_parent=config.get("children_aware_of_parent", False),
parent_has_child_history=config.get("parent_has_child_history", True),
state=data.get("state", {}),
additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL],
max_messages_per_turn=config.get("max_messages_per_turn", 2),
max_messages_per_error_escalation_turn=config.get("max_messages_per_error_escalation_turn", 2),
escalate_errors=config.get("escalate_errors", True),
max_overall_turns=config.get("max_overall_turns", 10)
additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL]
)
print('-'*200)
logger.info('-'*200)
logger.info('Raw output:')
logger.info((resp_messages, resp_tokens_used, resp_state))
out = {
"messages": resp_messages,
"tokens_used": resp_tokens_used,
"state": resp_state,
}
print("Output: ")
logger.info(f"Output: ")
logger.info("Output:")
for k, v in out.items():
print(f"{k}: {v}")
print('*'*200)
logger.info(f"{k}: {v}")
logger.info('*'*200)
print("Processing time:")
print('='*200)
logger.info('='*200)
print(f"Processing time: {datetime.now() - start_time}")
logger.info(f"Processing time: {datetime.now() - start_time}")
return jsonify(out)
except Exception as e:
print(e)
logger.error(f"Error: {e}")
return jsonify({"error": str(e)}), 500

View file

@ -1,23 +1,20 @@
from copy import deepcopy
import logging
from .types import AgentRole
from .helpers.access import (
get_agent_by_name,
get_external_tools, pop_agent_config_by_type
get_external_tools,
)
from .helpers.state import (
add_recent_messages_to_history, construct_state_from_response, reset_current_turn, reset_current_turn_agent_history
)
from .helpers.instructions import (
get_universal_system_message
construct_state_from_response
)
from .helpers.control import get_latest_assistant_msg, get_latest_non_assistant_messages, get_last_agent_name
from .swarm_wrapper import run as swarm_run, create_response, get_agents
from src.utils.common import common_logger as logger
# Create a dedicated logger for swarm wrapper
logger = logging.getLogger("graph")
logger.setLevel(logging.INFO)
print("Logger level set to INFO")
def order_messages(messages):
@ -52,7 +49,7 @@ def clean_up_history(agent_data):
data["history"] = order_messages(data["history"])
return agent_data
def create_final_response(response, turn_messages, messages, tokens_used, all_agents, return_diff_messages):
def create_final_response(response, turn_messages, tokens_used, all_agents):
"""
Constructs the final response data (messages, tokens_used, updated state) that a caller would need.
"""
@ -61,7 +58,7 @@ def create_final_response(response, turn_messages, messages, tokens_used, all_ag
response.messages = []
# Assign the appropriate messages to the response
response.messages = turn_messages if return_diff_messages else messages + turn_messages
response.messages = turn_messages
# Ensure tokens_used is a valid dictionary
if not isinstance(tokens_used, dict):
@ -83,17 +80,14 @@ def create_final_response(response, turn_messages, messages, tokens_used, all_ag
def run_turn(
messages, start_agent_name, agent_configs, tool_configs, available_tool_mappings={},
localize_history=True, return_diff_messages=True, prompt_configs=[], start_turn_with_start_agent=False,
children_aware_of_parent=False, parent_has_child_history=True, state={}, additional_tool_configs=[],
error_tool_call=True, max_messages_per_turn=10, max_messages_per_error_escalation_turn=4,
escalate_errors=True, max_overall_turns=10
messages, start_agent_name, agent_configs, tool_configs, start_turn_with_start_agent, state={}, additional_tool_configs=[]
):
"""
Coordinates a single 'turn' of conversation or processing among agents.
Includes validation, agent setup, optional greeting logic, error handling, and post-processing steps.
"""
logger.info("Running stateless turn")
print("Running stateless turn")
# Sort messages by the specified ordering
#messages = order_messages(messages)
@ -107,17 +101,11 @@ def run_turn(
# Initialize tokens_used as a dictionary
tokens_used = {"total": 0, "prompt": 0, "completion": 0}
# Extract special agent configs
post_processing_agent_config, agent_configs = pop_agent_config_by_type(agent_configs, AgentRole.POST_PROCESSING.value)
guardrails_agent_config, agent_configs = pop_agent_config_by_type(agent_configs, AgentRole.GUARDRAILS.value)
agent_data = state.get("agent_data", [])
universal_sys_msg = ""
# If not a greeting turn, localize the last user or system messages
if not greeting_turn:
latest_assistant_msg = get_latest_assistant_msg(messages)
universal_sys_msg = get_universal_system_message(messages)
latest_non_assistant_msgs = get_latest_non_assistant_messages(messages)
msg_type = latest_non_assistant_msgs[-1]["role"]
@ -130,19 +118,6 @@ def run_turn(
latest_assistant_msg=latest_assistant_msg,
start_turn_with_start_agent=start_turn_with_start_agent
)
# Localize history
if msg_type == "user":
messages = reset_current_turn(messages)
agent_data = reset_current_turn_agent_history(agent_data, [last_agent_name])
#agent_data = clean_up_history(agent_data)
agent_data = add_recent_messages_to_history(
recent_messages=latest_non_assistant_msgs,
last_agent_name=last_agent_name,
agent_data=agent_data,
messages=messages,
parent_has_child_history=parent_has_child_history
)
else:
# For a greeting turn, we assume the last agent is the start_agent_name
last_agent_name = start_agent_name
@ -151,39 +126,34 @@ def run_turn(
# Initialize all agents
logger.info("Initializing agents")
all_agents, new_agents = get_agents(
print("Initializing agents")
new_agents = get_agents(
agent_configs=agent_configs,
tool_configs=tool_configs,
available_tool_mappings=available_tool_mappings,
agent_data=agent_data,
localize_history=localize_history,
start_turn_with_start_agent=start_turn_with_start_agent,
children_aware_of_parent=children_aware_of_parent,
universal_sys_msg=universal_sys_msg
tool_configs=tool_configs
)
# Prepare escalation agent
# Get the last agent and validate
last_agent = get_agent_by_name(last_agent_name, all_agents)
last_new_agent = get_agent_by_name(last_agent_name, new_agents)
# Gather external tools for Swarm
external_tools = get_external_tools(tool_configs)
logger.info(f"Found {len(external_tools)} external tools")
print(f"Found {len(external_tools)} external tools")
# If no validation error yet, proceed with the main run
logger.info("Running swarm run")
print("Running swarm run")
response = swarm_run(
agent=last_new_agent,
messages=messages,
execute_tools=True,
external_tools=external_tools,
localize_history=localize_history,
parent_has_child_history=parent_has_child_history,
max_messages_per_turn=max_messages_per_turn,
tokens_used=tokens_used
)
logger.info("Swarm run completed")
print("Swarm run completed")
# Initialize response.messages if it doesn't exist
if not hasattr(response, 'messages'):
response.messages = []
@ -202,7 +172,7 @@ def run_turn(
standard_message = {
"role": raw_item.role if hasattr(raw_item, 'role') else "assistant",
"content": content,
"sender": last_agent.name,
"sender": last_new_agent.name,
"created_at": None,
"response_type": "internal"
}
@ -210,6 +180,9 @@ def run_turn(
# Add the converted message to response messages
response.messages.append(standard_message)
logger.info("Converted message added to response messages")
print("Converted message added to response messages")
# Use a dictionary for tokens_used instead of a hard-coded integer
tokens_used = {"total": 100, "prompt": 50, "completion": 50} # Dummy values as placeholders
@ -217,11 +190,13 @@ def run_turn(
if hasattr(response, 'messages') and isinstance(response.messages, list):
turn_messages.extend(response.messages)
logger.info(f"Completed run of agent: {last_agent.name}")
logger.info(f"Completed run of agent: {last_new_agent.name}")
print(f"Completed run of agent: {last_new_agent.name}")
# Otherwise, duplicate the last response as external
logger.info("No post-processing agent found. Duplicating last response and setting to external.")
print("No post-processing agent found. Duplicating last response and setting to external.")
if turn_messages:
duplicate_msg = deepcopy(turn_messages[-1])
duplicate_msg["response_type"] = "external"
@ -234,7 +209,7 @@ def run_turn(
response = create_response(
messages=[duplicate_msg],
tokens_used=tokens_used,
agent=last_agent,
agent=last_new_agent,
error_msg=''
)
@ -243,11 +218,11 @@ def run_turn(
turn_messages.extend(response.messages)
# Finalize the response
logger.info("Finalizing response")
print("Finalizing response")
return create_final_response(
response=response,
turn_messages=turn_messages,
messages=messages,
tokens_used=tokens_used,
all_agents=all_agents,
return_diff_messages=return_diff_messages
all_agents=new_agents
)

View file

@ -49,13 +49,7 @@ def construct_state_from_response(response, agents):
for agent in agents:
agent_data.append({
"name": agent.name,
"instructions": agent.instructions,
"parent_function": agent.parent_function.__name__ if agent.parent_function else None,
"child_functions": [f.__name__ for f in agent.child_functions.values()] if agent.child_functions else [],
"internal_tools": [t.get("function").get("name") for t in agent.internal_tools] if agent.internal_tools else [],
"external_tools": [t.get("function").get("name") for t in agent.external_tools] if agent.external_tools else [],
"history": agent.history,
"most_recent_parent_name": agent.most_recent_parent.name if agent.most_recent_parent else ""
"instructions": agent.instructions
})
state = {

View file

@ -1,30 +1,31 @@
from src.swarm.types import Agent as SwarmAgent, Response as SwarmResponse
import logging
import json
# Import helper functions needed for get_agents
from .helpers.access import (
get_agent_data_by_name, get_agent_by_name, get_tool_config_by_name,
get_tool_config_by_name,
get_tool_config_by_type
)
from .helpers.transfer import create_transfer_function_to_agent, create_transfer_function_to_parent_agent
from .helpers.instructions import (
add_transfer_instructions_to_child_agents, add_transfer_instructions_to_parent_agents,
add_rag_instructions_to_agent, add_universal_system_message_to_agent
add_rag_instructions_to_agent
)
from agents import Agent as NewAgent, Runner, FunctionTool, function_tool, RunContextWrapper
from agents import Agent as NewAgent, Runner, FunctionTool, RunContextWrapper
# Add import for OpenAI functionality
from src.utils.common import generate_openai_output
from src.utils.common import common_logger as logger, generate_openai_output
from typing import Any
# Create a dedicated logger for swarm wrapper
logger = logging.getLogger("swarm_wrapper")
logger.setLevel(logging.INFO)
#logger = logging.getLogger("swarm_wrapper")
#logger.setLevel(logging.INFO)
# Re-export the types from src.swarm.types
Agent = SwarmAgent
Response = SwarmResponse
from pydantic import BaseModel
from typing import List, Optional, Dict
class NewResponse(BaseModel):
messages: List[Dict]
agent: Optional[Any] = None
tokens_used: Optional[dict] = {}
error_msg: Optional[str] = ""
async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool_config: dict) -> str:
print(f"Catch all called for tool: {tool_name}")
@ -43,25 +44,22 @@ async def catch_all(ctx: RunContextWrapper[Any], args: str, tool_name: str, tool
print(response_content)
return(response_content)
def get_agents(agent_configs, tool_configs, localize_history, available_tool_mappings,
agent_data, start_turn_with_start_agent, children_aware_of_parent, universal_sys_msg):
def get_agents(agent_configs, tool_configs):
"""
Creates and initializes Agent objects based on their configurations and connections.
This function also sets up parent-child relationships, transfer instructions, and
universal system messages.
"""
if not isinstance(agent_configs, list):
raise ValueError("Agents config is not a list in get_agents")
if not isinstance(tool_configs, list):
raise ValueError("Tools config is not a list in get_agents")
agents = []
new_agents = []
new_agent_to_children = {}
new_agent_name_to_index = {}
# Create Agent objects from config
for agent_config in agent_configs:
logger.debug(f"Processing config for agent: {agent_config['name']}")
print(f"Processing config for agent: {agent_config['name']}")
# If hasRagSources, append the RAG tool to the agent's tools
if agent_config.get("hasRagSources", False):
@ -71,11 +69,9 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map
# Prepare tool lists for this agent
external_tools = []
candidate_parent_functions = {}
child_functions = {}
logger.debug(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools")
print(tool_configs)
print(f"Agent {agent_config['name']} has {len(agent_config['tools'])} configured tools")
new_tools = []
for tool_name in agent_config["tools"]:
@ -97,33 +93,15 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map
)
new_tools.append(tool)
logger.debug(f"Added tool {tool_name} to agent {agent_config['name']}")
print(f"Added tool {tool_name} to agent {agent_config['name']}")
else:
logger.warning(f"Tool {tool_name} not found in tool_configs")
# Localize history (if applicable)
history = []
this_agent_data = get_agent_data_by_name(agent_config["name"], agent_data)
if this_agent_data and localize_history:
history = this_agent_data.get("history", [])
print(f"WARNING: Tool {tool_name} not found in tool_configs")
# Create the agent object
logger.debug(f"Creating Agent object for {agent_config['name']}")
print(f"Creating Agent object for {agent_config['name']}")
try:
agent = Agent(
name=agent_config["name"],
type=agent_config.get("type", "default"),
instructions=agent_config["instructions"],
description=agent_config.get("description", ""),
internal_tools=[],
external_tools=external_tools,
candidate_parent_functions=candidate_parent_functions,
child_functions=child_functions,
model=agent_config["model"],
respond_to_user=agent_config.get("respond_to_user", False),
history=history,
children_names=agent_config.get("connectedAgents", []),
most_recent_parent=None
)
new_agent = NewAgent(
name=agent_config["name"],
instructions=agent_config["instructions"],
@ -134,54 +112,13 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map
new_agent_to_children[agent_config["name"]] = agent_config.get("connectedAgents", [])
new_agent_name_to_index[agent_config["name"]] = len(new_agents)
new_agents.append(new_agent)
agents.append(agent)
logger.debug(f"Successfully created agent: {agent_config['name']}")
print(f"Successfully created agent: {agent_config['name']}")
except Exception as e:
logger.error(f"Failed to create agent {agent_config['name']}: {str(e)}")
print(f"ERROR: Failed to create agent {agent_config['name']}: {str(e)}")
raise
# Reattach most_recent_parent if it exists
for agent in agents:
this_agent_data = get_agent_data_by_name(agent.name, agent_data)
if this_agent_data:
most_recent_parent_name = this_agent_data.get("most_recent_parent_name", "")
if most_recent_parent_name:
parent_agent = get_agent_by_name(most_recent_parent_name, agents)
if parent_agent:
agent.most_recent_parent = parent_agent
# Attach children
logger.info("Adding children agents to parent agents")
for agent in agents:
agent.children = {
potential_child.name: potential_child
for potential_child in agents
if potential_child.name in agent.children_names
}
# Generate transfer functions for child agents
logger.info("Generating transfer functions for transferring to children agents")
transfer_functions = {
agent.name: create_transfer_function_to_agent(agent)
for agent in agents
}
# Add transfer functions to parent agents for each child
logger.info("Adding transfer functions for parents to transfer to children")
for agent in agents:
for child in agent.children.values():
agent.child_functions[child.name] = transfer_functions[child.name]
# Add parent-related instructions
logger.info("Adding child transfer-related instructions to parent agents")
for agent in agents:
if agent.children:
add_transfer_instructions_to_parent_agents(agent, agent.children, transfer_functions)
# Finally add a universal system message to all agents
for agent in agents:
add_universal_system_message_to_agent(agent, universal_sys_msg)
for new_agent in new_agents:
# Initialize the handoffs attribute if it doesn't exist
if not hasattr(new_agent, 'handoffs'):
@ -189,7 +126,7 @@ def get_agents(agent_configs, tool_configs, localize_history, available_tool_map
# Look up the agent's children from the old agent and create a list called handoffs in new_agent with pointers to the children in new_agents
new_agent.handoffs = [new_agents[new_agent_name_to_index[child]] for child in new_agent_to_children[new_agent.name]]
return agents, new_agents
return new_agents
def create_response(messages=None, tokens_used=None, agent=None, error_msg=''):
@ -210,10 +147,10 @@ def create_response(messages=None, tokens_used=None, agent=None, error_msg=''):
if tokens_used is None:
tokens_used = {}
return Response(
return NewResponse(
messages=messages,
tokens_used=tokens_used,
agent=agent,
tokens_used=tokens_used,
error_msg=error_msg
)
@ -221,11 +158,7 @@ def create_response(messages=None, tokens_used=None, agent=None, error_msg=''):
def run(
agent,
messages,
execute_tools=True,
external_tools=None,
localize_history=True,
parent_has_child_history=True,
max_messages_per_turn=10,
tokens_used=None
):
"""
@ -245,6 +178,7 @@ def run(
Response object from the Swarm client
"""
logger.info(f"Initializing Swarm client for agent: {agent.name}")
print(f"Initializing Swarm client for agent: {agent.name}")
# Initialize default parameters
if external_tools is None:
@ -271,7 +205,10 @@ def run(
})
# Run the agent with the formatted messages
logger.info("Beginning Swarm run with run_sync")
print("Beginning Swarm run with run_sync")
response2 = Runner.run_sync(agent, formatted_messages)
logger.info(f"Completed Swarm run for agent: {agent.name}")
print(f"Completed Swarm run for agent: {agent.name}")
return response2

View file

@ -1,4 +0,0 @@
from .core import Swarm
from .types import Agent, Response
__all__ = ["Swarm", "Agent", "Response"]

View file

@ -1,275 +0,0 @@
# Standard library imports
import copy
import json
from collections import defaultdict
from typing import List, Callable, Union
from datetime import datetime
# Package/library imports
from openai import OpenAI
import random
# Local imports
from .util import *
from .types import (
Agent,
AgentFunction,
ChatCompletionMessage,
ChatCompletionMessageToolCall,
Function,
Response,
Result,
)
__CTX_VARS_NAME__ = "context_variables"
class Swarm:
def __init__(self, client=None):
if not client:
client = OpenAI(api_key=OPENAI_API_KEY)
self.client = client
self.history = defaultdict(lambda : [])
def get_chat_completion(
self,
agent: Agent,
history: List,
context_variables: dict,
model_override: str,
stream: bool,
debug: bool,
temperature: float
) -> ChatCompletionMessage:
context_variables = defaultdict(str, context_variables)
instructions = (
agent.instructions(context_variables)
if callable(agent.instructions)
else agent.instructions
)
messages = [{"role": "system", "content": instructions}] + history
debug_print(debug, "Getting chat completion for...:", messages)
all_functions = list(agent.child_functions.values()) + ([agent.parent_function] if agent.parent_function else [])
all_tools = agent.external_tools + agent.internal_tools
funcs_and_tools = [function_to_json(f) for f in all_functions] + [t for t in all_tools]
# hide context_variables from model
for tool in funcs_and_tools:
params = tool["function"]["parameters"]
params["properties"].pop(__CTX_VARS_NAME__, None)
if __CTX_VARS_NAME__ in params.get("required", []):
params["required"].remove(__CTX_VARS_NAME__)
create_params = {
"model": model_override or agent.model,
"messages": messages,
"tools": funcs_and_tools or None,
"tool_choice": agent.tool_choice,
"stream": stream,
"temperature": temperature
}
if funcs_and_tools:
create_params["parallel_tool_calls"] = agent.parallel_tool_calls
return self.client.chat.completions.create(**create_params)
def handle_function_result(self, result, debug) -> Result:
# Check if result is already a Result instance
if isinstance(result, Result):
return result
# Check if result is an Agent instance
if isinstance(result, Agent):
return Result(
value=json.dumps({"assistant": result.name}),
agent=result,
)
# Handle all other cases
try:
return Result(value=str(result))
except Exception as e:
error_message = f"Failed to cast response to string: {result}. Make sure agent functions return a string or Result object. Error: {str(e)}"
debug_print(debug, error_message)
raise TypeError(error_message)
def handle_function_calls(
self,
tool_calls: List[ChatCompletionMessageToolCall],
functions: List[AgentFunction],
context_variables: dict,
debug: bool,
) -> Response:
function_map = {f.__name__: f for f in functions}
partial_response = Response(
messages=[], agent=None, context_variables={})
for tool_call in tool_calls:
name = tool_call.function.name
# handle missing tool case, skip to next tool
if name not in function_map:
debug_print(debug, f"Tool {name} not found in function map.")
partial_response.messages.append(
{
"role": "tool",
"tool_call_id": tool_call.id,
"tool_name": name,
"content": f"Error: Tool {name} not found.",
}
)
continue
args = json.loads(tool_call.function.arguments)
debug_print(
debug, f"Processing tool call: {name} with arguments {args}")
func = function_map[name]
# pass context_variables to agent functions
if __CTX_VARS_NAME__ in func.__code__.co_varnames:
args[__CTX_VARS_NAME__] = context_variables
raw_result = function_map[name](**args)
result: Result = self.handle_function_result(raw_result, debug)
partial_response.messages.append(
{
"role": "tool",
"tool_call_id": tool_call.id,
"tool_name": name,
"content": result.value,
}
)
partial_response.context_variables.update(result.context_variables)
if result.agent:
partial_response.agent = result.agent
return partial_response
def run(
self,
agent: Agent,
messages: List,
context_variables: dict = {},
model_override: str = None,
stream: bool = False,
debug: bool = False,
max_messages_per_turn: int = 10,
execute_tools: bool = True,
external_tools: List[str] = [],
localize_history: bool = True,
parent_has_child_history: bool = True,
tokens_used: dict = {},
temperature: float = 0.0
) -> Response:
active_agent = agent
context_variables = copy.deepcopy(context_variables)
global_history = copy.deepcopy(messages)
init_len = len(messages)
while len(global_history) - init_len < max_messages_per_turn and active_agent:
history = active_agent.history if localize_history else global_history
history = arrange_messages_keys_in_order(history)
parent = active_agent.most_recent_parent
children_names_backup, children_backup, child_functions_backup = copy.deepcopy(active_agent.children_names), copy.deepcopy(active_agent.children), copy.deepcopy(active_agent.child_functions)
active_agent = check_and_remove_repeat_tool_call_to_child(active_agent, history)
# get completion with current history, agent
completion = self.get_chat_completion(
agent=active_agent,
history=history,
context_variables=context_variables,
model_override=model_override,
stream=stream,
debug=debug,
temperature=temperature
)
tokens_used = update_tokens_used(provider="openai", model=model_override or active_agent.model, tokens_used=tokens_used, completion=completion)
# Restore children and child functions
active_agent.children_names, active_agent.children, active_agent.child_functions = children_names_backup, children_backup, child_functions_backup
message = completion.choices[0].message
debug_print(debug, "Received completion:", message)
message.sender = active_agent.name
message_json = json.loads(message.model_dump_json())
message_json = add_message_metadata(message_json, active_agent)
if localize_history:
active_agent = update_histories(active_agent, message_json)
if parent and parent_has_child_history:
parent = update_histories(parent, message_json)
global_history.append(message_json)
external_tool_calls = []
internal_tool_calls = []
if message.tool_calls:
message_json["response_type"] = "internal"
for tool_call in message.tool_calls:
tool_name = tool_call.function.name
if tool_name in external_tools:
external_tool_calls.append(tool_call)
else:
internal_tool_calls.append(tool_call)
message.tool_calls = internal_tool_calls
if not message.tool_calls or not execute_tools:
if external_tool_calls:
message.tool_calls.extend(external_tool_calls)
debug_print(debug, "Ending turn.")
break
# handle function calls, updating context_variables, and switching agents
all_functions = list(active_agent.child_functions.values()) + ([active_agent.parent_function] if active_agent.parent_function else [])
partial_response = self.handle_function_calls(
message.tool_calls, all_functions, context_variables, debug
)
for msg in partial_response.messages:
msg = add_message_metadata(msg, active_agent)
if localize_history:
active_agent = update_histories(active_agent, msg)
if parent and parent_has_child_history:
parent = update_histories(parent, msg)
global_history.extend(partial_response.messages)
context_variables.update(partial_response.context_variables)
# Parent to child transfer
if partial_response.agent:
prev_agent = active_agent
active_agent = partial_response.agent
# Parent to child transfer
if active_agent.name in prev_agent.children_names:
active_agent.most_recent_parent = prev_agent
active_agent.parent_function = active_agent.candidate_parent_functions[active_agent.most_recent_parent.name]
if localize_history:
if not parent_has_child_history:
prev_agent.history = remove_irrelevant_messages(prev_agent.history)
new_active_agent_history = get_current_turn_messages(global_history, only_user = True)
active_agent.history.extend(new_active_agent_history)
# Child to parent transfer
else:
assert parent == active_agent, "Parent and active agent do not match when active agent is not a child of previous agent"
child = prev_agent
if localize_history:
child.history = remove_irrelevant_messages(child.history)
return_messages = global_history[init_len:]
error_msg = ""
if len(global_history) - init_len >= max_messages_per_turn:
error_msg = "Max messages per turn reached"
return Response(
messages=return_messages,
agent=active_agent,
context_variables=context_variables,
error_msg=error_msg,
tokens_used=tokens_used
)

View file

@ -1 +0,0 @@
from .repl import run_demo_loop

View file

@ -1,87 +0,0 @@
import json
from swarm import Swarm
def process_and_print_streaming_response(response):
content = ""
last_sender = ""
for chunk in response:
if "sender" in chunk:
last_sender = chunk["sender"]
if "content" in chunk and chunk["content"] is not None:
if not content and last_sender:
print(f"\033[94m{last_sender}:\033[0m", end=" ", flush=True)
last_sender = ""
print(chunk["content"], end="", flush=True)
content += chunk["content"]
if "tool_calls" in chunk and chunk["tool_calls"] is not None:
for tool_call in chunk["tool_calls"]:
f = tool_call["function"]
name = f["name"]
if not name:
continue
print(f"\033[94m{last_sender}: \033[95m{name}\033[0m()")
if "delim" in chunk and chunk["delim"] == "end" and content:
print() # End of response message
content = ""
if "response" in chunk:
return chunk["response"]
def pretty_print_messages(messages) -> None:
for message in messages:
if message["role"] != "assistant":
continue
# print agent name in blue
print(f"\033[94m{message['sender']}\033[0m:", end=" ")
# print response, if any
if message["content"]:
print(message["content"])
# print tool calls in purple, if any
tool_calls = message.get("tool_calls") or []
if len(tool_calls) > 1:
print()
for tool_call in tool_calls:
f = tool_call["function"]
name, args = f["name"], f["arguments"]
arg_str = json.dumps(json.loads(args)).replace(":", "=")
print(f"\033[95m{name}\033[0m({arg_str[1:-1]})")
def run_demo_loop(
starting_agent, context_variables=None, stream=False, debug=False
) -> None:
client = Swarm()
print("Starting Swarm CLI 🐝")
messages = []
agent = starting_agent
while True:
user_input = input("\033[90mUser\033[0m: ")
messages.append({"role": "user", "content": user_input})
response = client.run(
agent=agent,
messages=messages,
context_variables=context_variables or {},
stream=stream,
debug=debug,
)
if stream:
response = process_and_print_streaming_response(response)
else:
pretty_print_messages(response.messages)
messages.extend(response.messages)
agent = response.agent

View file

@ -1,54 +0,0 @@
from __future__ import annotations
from openai.types.chat import ChatCompletionMessage
from openai.types.chat.chat_completion_message_tool_call import (
ChatCompletionMessageToolCall,
Function,
)
from typing import List, Callable, Union, Optional, Dict
# Third-party imports
from pydantic import BaseModel
AgentFunction = Callable[[], Union[str, "Agent", dict]]
class Agent(BaseModel):
name: str = "Agent"
model: str = "gpt-4o"
type: str = ""
instructions: Union[str, Callable[[], str]] = "You are a helpful agent.",
description: str = "This is a helpful agent."
candidate_parent_functions: Dict[str, AgentFunction] = {}
parent_function: AgentFunction = None
child_functions: Dict[str, AgentFunction] = {}
internal_tools: List[Dict] = []
external_tools: List[Dict] = []
tool_choice: str = None
parallel_tool_calls: bool = True
respond_to_user: bool = True
history: List[Dict] = []
children_names: List[str] = []
children: Dict[str, "Agent"] = {}
most_recent_parent: Optional["Agent"] = None
parent: "Agent" = None
class Response(BaseModel):
messages: List = []
agent: Optional[Agent] = None
context_variables: dict = {}
error_msg: Optional[str] = ""
tokens_used: dict = {}
class Result(BaseModel):
"""
Encapsulates the possible return values for an agent function.
Attributes:
value (str): The result value as a string.
agent (Agent): The agent instance, if applicable.
context_variables (dict): A dictionary of context variables.
"""
value: str = ""
agent: Optional[Agent] = None
context_variables: dict = {}

View file

@ -1,175 +0,0 @@
import inspect
import json
from datetime import datetime
import os
from dotenv import load_dotenv
from src.utils.common import read_json_from_file, get_api_key
load_dotenv()
OPENAI_API_KEY = get_api_key("OPENAI_API_KEY")
def debug_print(debug: bool, *args: str) -> None:
if not debug:
return
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
message = " ".join(map(str, args))
print(f"\033[97m[\033[90m{timestamp}\033[97m]\033[90m {message}\033[0m")
def merge_fields(target, source):
for key, value in source.items():
if isinstance(value, str):
target[key] += value
elif value is not None and isinstance(value, dict):
merge_fields(target[key], value)
def merge_chunk(final_response: dict, delta: dict) -> None:
delta.pop("role", None)
merge_fields(final_response, delta)
tool_calls = delta.get("tool_calls")
if tool_calls and len(tool_calls) > 0:
index = tool_calls[0].pop("index")
merge_fields(final_response["tool_calls"][index], tool_calls[0])
def function_to_json(func) -> dict:
"""
Converts a Python function into a JSON-serializable dictionary
that describes the function's signature, including its name,
description, and parameters.
Args:
func: The function to be converted.
Returns:
A dictionary representing the function's signature in JSON format.
"""
type_map = {
str: "string",
int: "integer",
float: "number",
bool: "boolean",
list: "array",
dict: "object",
type(None): "null",
}
try:
signature = inspect.signature(func)
except ValueError as e:
raise ValueError(
f"Failed to get signature for function {func.__name__}: {str(e)}"
)
parameters = {}
for param in signature.parameters.values():
try:
param_type = type_map.get(param.annotation, "string")
except KeyError as e:
raise KeyError(
f"Unknown type annotation {param.annotation} for parameter {param.name}: {str(e)}"
)
parameters[param.name] = {"type": param_type}
required = [
param.name
for param in signature.parameters.values()
if param.default == inspect._empty
]
return {
"type": "function",
"function": {
"name": func.__name__,
"description": func.__doc__ or "",
"parameters": {
"type": "object",
"properties": parameters,
"required": required,
},
},
}
def get_current_turn_messages(messages, only_user = False):
if only_user:
return [msg for msg in messages if msg.get("current_turn") and msg.get("role") == "user"]
else:
return [msg for msg in messages if msg.get("current_turn")]
def arrange_messages_keys_in_order(messages):
"""Arranges message keys in a specific order: id, role, sender, relevant_agents, content, created_at, timestamp, followed by rest alphabetically"""
key_order = ['role', 'sender', 'content', 'created_at']
def sort_keys(message):
# Create new dict with specified key order
ordered = {}
# Add keys in specified order if they exist
for key in key_order:
if key in message:
ordered[key] = message[key]
# Add remaining keys in alphabetical order
for key in sorted(message.keys()):
if key not in key_order:
ordered[key] = message[key]
return ordered
return [sort_keys(message) for message in messages]
def remove_irrelevant_messages(messages):
"""Removes all messages from and including the latest user message"""
for i in range(len(messages)-1, -1, -1):
if messages[i].get("role") == "user":
return messages[:i]
return messages
def update_histories(active_agent, message):
active_agent.history.append(message)
return active_agent
def remove_none_fields(message):
return {k: v for k, v in message.items() if v is not None}
def add_message_metadata(message, active_agent):
message = remove_none_fields(message)
message["created_at"] = datetime.now().isoformat()
message["current_turn"] = True
if active_agent.respond_to_user:
message["response_type"] = "external"
else:
message["response_type"] = "internal"
return message
def check_and_remove_repeat_tool_call_to_child(agent, messages):
# If in the current turn, the most recent assistant message (need not be the last message overall, just needs to be the last message with role as assistant) is a tool call from a child agent, which transfers control to the agent using its parent function, then remove the tool call to transfer to that child again from this agent. This is to prevent back and forth between this agent and the child agent.
for message in reversed(messages):
if message.get("role") == "assistant" and message.get("sender") in agent.children_names and message.get("tool_calls"):
tool_call = message.get("tool_calls")[0]
child_agent = agent.children.get(message.get("sender"), None)
if not child_agent:
continue
child_agent_name = child_agent.name
if tool_call.get("function").get("name") == child_agent.parent_function:
agent.children_names.remove(child_agent_name)
agent.children.pop(child_agent_name)
agent.child_functions.pop(child_agent_name)
break
return agent
def update_tokens_used(provider, model, tokens_used, completion):
provider_model = f"{provider}/{model}"
input_tokens = completion.usage.prompt_tokens
output_tokens = completion.usage.completion_tokens
if provider_model not in tokens_used:
tokens_used[provider_model] = {
'input_tokens': 0,
'output_tokens': 0,
}
tokens_used[provider_model]['input_tokens'] += input_tokens
tokens_used[provider_model]['output_tokens'] += output_tokens
return tokens_used

View file

@ -4,7 +4,6 @@ import os
import subprocess
import sys
import time
from collections import defaultdict
from dotenv import load_dotenv
from openai import OpenAI

View file

@ -87,18 +87,9 @@ if __name__ == "__main__":
start_agent_name=start_agent_name,
agent_configs=agent_configs,
tool_configs=tool_configs,
return_diff_messages=config.get("return_diff_messages", True),
prompt_configs=prompt_configs,
start_turn_with_start_agent=config.get("start_turn_with_start_agent", False),
children_aware_of_parent=config.get("children_aware_of_parent", False),
parent_has_child_history=config.get("parent_has_child_history", True),
state=state,
additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL],
error_tool_call=config.get("error_tool_call", True),
max_messages_per_turn=config.get("max_messages_per_turn", 10),
max_messages_per_error_escalation_turn=config.get("max_messages_per_error_escalation_turn", 4),
escalate_errors=config.get("escalate_errors", True),
max_overall_turns=config.get("max_overall_turns", 10)
additional_tool_configs=[RAG_TOOL, CLOSE_CHAT_TOOL]
)
state = resp_state
resp_messages = order_messages(resp_messages)