diff --git a/notebooks/run_agent_api_key_keyring.ipynb b/notebooks/run_agent_api_key_keyring.ipynb new file mode 100644 index 0000000..ee7b9ac --- /dev/null +++ b/notebooks/run_agent_api_key_keyring.ipynb @@ -0,0 +1,581 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ebf13cb8", + "metadata": {}, + "source": [ + "## Before running this notebook\n", + "\n", + "- Start Asyncroscopy MCP server + Tango devices \n", + " Repo: https://github.com/pycroscopy/asyncroscopy \n", + " Script: `scripts/run_mcp_and_devices.py`\n", + "\n", + "- Useful references \n", + " - `docs/Operation/tango_db_mode.md`\n", + " - `notebooks/9_MCP_Server_Tutorial.ipynb`\n", + "\n", + "- Keep a Gemini/HF/OPenrouter API key ready.\n", + "\n", + "---\n", + "\n", + "## Note from my setup On my MacBook\n", + "\n", + "I used `ThermoMicroscope` with the real microscope backend.\n", + "\n", + "Steps I followed:\n", + "\n", + "1. Followed `9_MCP_Server_Tutorial.ipynb`\n", + "2. Started Tango devices manually\n", + "3. Started MCP server:\n", + "\n", + "```bash\n", + "uv run scripts/start_mcp_server_cli.py\n", + "Enter Tango DB host [127.0.0.1]: localhost\n", + "Enter Tango DB port [9094]: 9094" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "5ec55c30", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/utkarshpratiush/project/just-learning/Atomonous/.venv/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import os\n", + "import sys\n", + "\n", + "sys.path.insert(0, os.path.abspath(os.path.join(os.getcwd(), \"..\")))\n", + "\n", + "from atomonous import settings\n", + "\n", + "# Uncomment the line below if you want to specify the local model's download path.\n", + "# settings.hf_cache_dir = \"/lustre/isaac24/scratch/dpelaia/hf_cache/\"" + ] + }, + { + "cell_type": "markdown", + "id": "de2f5bd7", + "metadata": {}, + "source": [ + "## Save your Gemini API key securely\n", + "\n", + "We use `keyring` to store the Gemini API key securely, instead of hardcoding it in the notebook.\n", + "\n", + "Run this cell **once**:\n", + "\n", + "```python\n", + "import keyring\n", + "\n", + "keyring.set_password(\n", + " \"gemini\", # service name\n", + " \"utkarsh\", # key identifier / username\n", + " \"YOUR_API_KEY\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "386e0e99", + "metadata": {}, + "outputs": [], + "source": [ + "# Below cell needs to be run just one and then comment it out\n", + "# import getpass\n", + "# import keyring\n", + "\n", + "# api_key = getpass.getpass(\"Enter Gemini API key: \")\n", + "\n", + "# keyring.set_password(\n", + "# \"openrouter\",\n", + "# \"utkarsh\",\n", + "# api_key\n", + "# )\n", + "\n", + "# print(\"API key saved successfully.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6de0fad6", + "metadata": {}, + "outputs": [], + "source": [ + "import keyring\n", + "from atomonous.agent.core import Agent\n", + "\n", + "api_key = keyring.get_password(\n", + " \"openrouter\",\n", + " \"utkarsh\"\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e539f042", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[SessionMemory] Created session: artifacts/2026-05-25_13-59-58\n" + ] + } + ], + "source": [ + "agent = Agent.from_api_key(\n", + "model_id=\"openrouter/google/gemma-3-27b-it\",\n", + "api_base=\"https://openrouter.ai/api/v1\",\n", + "api_key=api_key\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "08ea65ea", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Available Agent Tools:\n", + "- symbolic_regression\n", + "- final_answer\n", + "- list_devices\n", + "- ThermoMicroscope_Connect\n", + "- ThermoMicroscope_Disconnect\n", + "- ThermoMicroscope_State\n", + "- ThermoMicroscope_Status\n", + "- ThermoMicroscope_auto_focus\n", + "- ThermoMicroscope_blank_beam\n", + "- ThermoMicroscope_get_camera_image\n", + "- ThermoMicroscope_get_fov\n", + "- ThermoMicroscope_get_image_data_cached\n", + "- ThermoMicroscope_get_images\n", + "- ThermoMicroscope_get_scanned_image\n", + "- ThermoMicroscope_get_screen_current\n", + "- ThermoMicroscope_get_spectrum\n", + "- ThermoMicroscope_get_stage\n", + "- ThermoMicroscope_move_stage\n", + "- ThermoMicroscope_place_beam\n", + "- ThermoMicroscope_place_beam_list\n", + "- ThermoMicroscope_set_fov\n", + "- ThermoMicroscope_set_image_shift\n", + "- ThermoMicroscope_set_screen_current\n", + "- ThermoMicroscope_unblank_beam\n", + "- SCAN_Activate\n", + "- SCAN_State\n", + "- SCAN_Status\n" + ] + } + ], + "source": [ + "# Connect to the MCP client (by default, this connects settings.mcp_url over https)\n", + "agent.connect_mcp_client(\n", + " server_parameters={\n", + " \"url\": \"http://localhost:8000/mcp\",\n", + " \"transport\": \"streamable-http\"\n", + " }\n", + ")\n", + "\n", + "# Print the loaded tools\n", + "print(\"Available Agent Tools:\")\n", + "for tool in agent.tools:\n", + " print(f\"- {tool.name}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8d0bfc7f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
╭──────────────────────────────────────────────────── New run ────────────────────────────────────────────────────╮\n",
+       "                                                                                                                 \n",
+       " Take a new image use get_scanned_image()                                                                        \n",
+       "                                                                                                                 \n",
+       "╰─ SafeLiteLLMModel - openrouter/google/gemma-3-27b-it ───────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[38;2;212;183;2m╭─\u001b[0m\u001b[38;2;212;183;2m───────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m \u001b[0m\u001b[1;38;2;212;183;2mNew run\u001b[0m\u001b[38;2;212;183;2m \u001b[0m\u001b[38;2;212;183;2m───────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m─╮\u001b[0m\n", + "\u001b[38;2;212;183;2m│\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n", + "\u001b[38;2;212;183;2m│\u001b[0m \u001b[1mTake a new image use get_scanned_image()\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n", + "\u001b[38;2;212;183;2m│\u001b[0m \u001b[38;2;212;183;2m│\u001b[0m\n", + "\u001b[38;2;212;183;2m╰─\u001b[0m\u001b[38;2;212;183;2m SafeLiteLLMModel - openrouter/google/gemma-3-27b-it \u001b[0m\u001b[38;2;212;183;2m──────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;212;183;2m─╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[38;2;212;183;2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[0m\u001b[1;37mStep 1\u001b[0m\u001b[38;2;212;183;2m ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Provider List: https://docs.litellm.ai/docs/providers\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;31mProvider List: https://docs.litellm.ai/docs/providers\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Provider List: https://docs.litellm.ai/docs/providers\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;31mProvider List: https://docs.litellm.ai/docs/providers\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
Executing parsed code: ──────────────────────────────────────────────────────────────────────────────────────── \n",
+       "  image_data = ThermoMicroscope_get_scanned_image()                                                                \n",
+       "  print(image_data)                                                                                                \n",
+       " ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── \n",
+       "
\n" + ], + "text/plain": [ + " ─ \u001b[1mExecuting parsed code:\u001b[0m ──────────────────────────────────────────────────────────────────────────────────────── \n", + " \u001b[38;2;248;248;242;48;2;39;40;34mimage_data\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m=\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mThermoMicroscope_get_scanned_image\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m(\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m)\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n", + " \u001b[38;2;248;248;242;48;2;39;40;34mprint\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m(\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mimage_data\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m)\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n", + " ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Execution logs:\n",
+       "<PIL.Image.Image image mode=L size=512x512 at 0x133655F40>\n",
+       "\n",
+       "Out: None\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mExecution logs:\u001b[0m\n", + "\n", + "\n", + "Out: None\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[SessionMemory] Saved PIL image: /Users/utkarshpratiush/project/just-learning/Atomonous/notebooks/artifacts/2026-05-25_13-59-58/image_step_1_20260525_140048_427350.png\n" + ] + }, + { + "data": { + "text/html": [ + "
[Step 1: Duration 3.23 seconds| Input tokens: 0 | Output tokens: 0]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[2m[Step 1: Duration 3.23 seconds| Input tokens: 0 | Output tokens: 0]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 2 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[38;2;212;183;2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \u001b[0m\u001b[1;37mStep 2\u001b[0m\u001b[38;2;212;183;2m ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Provider List: https://docs.litellm.ai/docs/providers\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;31mProvider List: https://docs.litellm.ai/docs/providers\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Provider List: https://docs.litellm.ai/docs/providers\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;31mProvider List: https://docs.litellm.ai/docs/providers\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
Executing parsed code: ──────────────────────────────────────────────────────────────────────────────────────── \n",
+       "  final_answer(image_data)                                                                                         \n",
+       " ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── \n",
+       "
\n" + ], + "text/plain": [ + " ─ \u001b[1mExecuting parsed code:\u001b[0m ──────────────────────────────────────────────────────────────────────────────────────── \n", + " \u001b[38;2;248;248;242;48;2;39;40;34mfinal_answer\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m(\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34mimage_data\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m)\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \n", + " ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
Final answer: <PIL.Image.Image image mode=L size=512x512 at 0x133655F40>\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;38;2;212;183;2mFinal answer: \u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
[Step 2: Duration 1.33 seconds| Input tokens: 0 | Output tokens: 0]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[2m[Step 2: Duration 1.33 seconds| Input tokens: 0 | Output tokens: 0]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Ask the agent something\n", + "query = \"Take a new image use get_scanned_image()\"\n", + "# You do not need to print the result (though you can)\n", + "# Because smolagents automatically streams the run\n", + "response = agent.chat(query)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20451f27", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "microscopy-ai-agent-demo (3.12.9)", + "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.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pyproject.toml b/pyproject.toml index 2232886..e6f280e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ dependencies = [ "h5py", "torch", "gplearn", + "keyring>=25.7.0", ] [project.optional-dependencies] diff --git a/uv.lock b/uv.lock index 49ff69b..432c59a 100644 --- a/uv.lock +++ b/uv.lock @@ -590,6 +590,48 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "jaraco-classes" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "more-itertools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" }, +] + +[[package]] +name = "jaraco-context" +version = "6.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/50/4763cd07e722bb6285316d390a164bc7e479db9d90daa769f22578f698b4/jaraco_context-6.1.2.tar.gz", hash = "sha256:f1a6c9d391e661cc5b8d39861ff077a7dc24dc23833ccee564b234b81c82dfe3", size = 16801, upload-time = "2026-03-20T22:13:33.922Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl", hash = "sha256:bf8150b79a2d5d91ae48629d8b427a8f7ba0e1097dd6202a9059f29a36379535", size = 7871, upload-time = "2026-03-20T22:13:32.808Z" }, +] + +[[package]] +name = "jaraco-functools" +version = "4.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "more-itertools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/cf/ea4ef2920830dea3f5ab2ea4da6fb67724e6dca80ee2553788c3607243d0/jaraco_functools-4.5.0.tar.gz", hash = "sha256:3bb5665ea4a020cf78a7040e89154c77edadb3ca74f366479669c5999aa70b03", size = 20272, upload-time = "2026-05-15T21:34:10.025Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/9a/982e48afcffcd727a9144506720ffd4224b6b7e355c98641866f38b7c043/jaraco_functools-4.5.0-py3-none-any.whl", hash = "sha256:79ce39246eddbde4b3a03b77ea5f0f7878dc669b166a66cf3fa8e266aa3fa2f4", size = 10594, upload-time = "2026-05-15T21:34:08.595Z" }, +] + +[[package]] +name = "jeepney" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -672,6 +714,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] +[[package]] +name = "keyring" +version = "25.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jaraco-classes" }, + { name = "jaraco-context" }, + { name = "jaraco-functools" }, + { name = "jeepney", marker = "sys_platform == 'linux'" }, + { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, + { name = "secretstorage", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" }, +] + [[package]] name = "kiwisolver" version = "1.5.0" @@ -882,6 +941,7 @@ dependencies = [ { name = "gplearn" }, { name = "graphviz" }, { name = "h5py" }, + { name = "keyring" }, { name = "litellm" }, { name = "matplotlib" }, { name = "numpy" }, @@ -910,6 +970,7 @@ requires-dist = [ { name = "gplearn" }, { name = "graphviz" }, { name = "h5py" }, + { name = "keyring", specifier = ">=25.7.0" }, { name = "litellm", specifier = "==1.82.2" }, { name = "matplotlib" }, { name = "numpy" }, @@ -928,6 +989,15 @@ requires-dist = [ ] provides-extras = ["serving"] +[[package]] +name = "more-itertools" +version = "11.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/1d/f4da6f02cdffe04d6362210b807146a26044c88d839208aec273bb0d9184/more_itertools-11.1.0.tar.gz", hash = "sha256:48e8f4d9e7e5878571ecf6f2b4e57634f93cd474cc8cfbd2376f2d11b396e30d", size = 145772, upload-time = "2026-05-22T14:14:29.909Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl", hash = "sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192", size = 72226, upload-time = "2026-05-22T14:14:28.824Z" }, +] + [[package]] name = "mpmath" version = "1.3.0" @@ -1420,6 +1490,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, ] +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -1590,6 +1669,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" }, ] +[[package]] +name = "secretstorage" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "jeepney", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" }, +] + [[package]] name = "setuptools" version = "80.10.2"