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",
+ "[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: [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"