aida-workbench 0.1.0b5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aida_workbench-0.1.0b5/.git-blame-ignore-revs +14 -0
- aida_workbench-0.1.0b5/.github/workflows/ci.yml +127 -0
- aida_workbench-0.1.0b5/.github/workflows/publish.yml +51 -0
- aida_workbench-0.1.0b5/.gitignore +40 -0
- aida_workbench-0.1.0b5/AIEVALUATOR_EPICS_MCP_SETUP.md +312 -0
- aida_workbench-0.1.0b5/CHANGELOG.md +452 -0
- aida_workbench-0.1.0b5/CONTRIBUTING.md +46 -0
- aida_workbench-0.1.0b5/Claude outputs/pyirena_theme_before_after.png +0 -0
- aida_workbench-0.1.0b5/LICENSE +21 -0
- aida_workbench-0.1.0b5/PKG-INFO +164 -0
- aida_workbench-0.1.0b5/PLAN.md +381 -0
- aida_workbench-0.1.0b5/PLAN_INSTRUMENT_INTEGRATION.md +516 -0
- aida_workbench-0.1.0b5/README.md +123 -0
- aida_workbench-0.1.0b5/docs/README.md +41 -0
- aida_workbench-0.1.0b5/docs/coding-and-scripting.md +187 -0
- aida_workbench-0.1.0b5/docs/context-and-limits.md +130 -0
- aida_workbench-0.1.0b5/docs/documents.md +108 -0
- aida_workbench-0.1.0b5/docs/gui-overview.md +177 -0
- aida_workbench-0.1.0b5/docs/installation.md +139 -0
- aida_workbench-0.1.0b5/docs/knowledge-bases.md +174 -0
- aida_workbench-0.1.0b5/docs/mcp-servers.md +323 -0
- aida_workbench-0.1.0b5/docs/organizing-conversations.md +109 -0
- aida_workbench-0.1.0b5/docs/providers-and-secrets.md +212 -0
- aida_workbench-0.1.0b5/docs/pyirena.md +165 -0
- aida_workbench-0.1.0b5/docs/safety-and-permissions.md +187 -0
- aida_workbench-0.1.0b5/docs/workflows.md +286 -0
- aida_workbench-0.1.0b5/docs/workspaces.md +133 -0
- aida_workbench-0.1.0b5/environment.yml +8 -0
- aida_workbench-0.1.0b5/examples/config/config.yaml +35 -0
- aida_workbench-0.1.0b5/examples/config/mcp.json +20 -0
- aida_workbench-0.1.0b5/examples/config/providers.yaml +60 -0
- aida_workbench-0.1.0b5/examples/config/workspaces.yaml +61 -0
- aida_workbench-0.1.0b5/planning/COMPLETED.md +546 -0
- aida_workbench-0.1.0b5/planning/DESIGN.md +402 -0
- aida_workbench-0.1.0b5/planning/context_management.md +312 -0
- aida_workbench-0.1.0b5/planning/credentials_and_browser_automation.md +174 -0
- aida_workbench-0.1.0b5/planning/document_images.md +270 -0
- aida_workbench-0.1.0b5/planning/documents_implementation.md +523 -0
- aida_workbench-0.1.0b5/planning/gui_implementation_guide.md +451 -0
- aida_workbench-0.1.0b5/planning/improvement_plan_2026-08.md +1150 -0
- aida_workbench-0.1.0b5/planning/local_scientific_ai_agent_proposal.md +938 -0
- aida_workbench-0.1.0b5/planning/multiuser_plan.md +524 -0
- aida_workbench-0.1.0b5/planning/phase01_foundation.md +96 -0
- aida_workbench-0.1.0b5/planning/phase02_agent_core.md +154 -0
- aida_workbench-0.1.0b5/planning/phase03_mcp.md +183 -0
- aida_workbench-0.1.0b5/planning/phase04_persistence_workspaces.md +113 -0
- aida_workbench-0.1.0b5/planning/phase05_gui.md +190 -0
- aida_workbench-0.1.0b5/planning/phase06_documents.md +438 -0
- aida_workbench-0.1.0b5/planning/phase07_mcp_management.md +386 -0
- aida_workbench-0.1.0b5/planning/phase08_rag.md +241 -0
- aida_workbench-0.1.0b5/planning/phase09_coding_scripting.md +126 -0
- aida_workbench-0.1.0b5/planning/phase10_automation_distribution.md +127 -0
- aida_workbench-0.1.0b5/planning/phase10_scheduling_design.md +459 -0
- aida_workbench-0.1.0b5/planning/phase_future.md +84 -0
- aida_workbench-0.1.0b5/pyproject.toml +105 -0
- aida_workbench-0.1.0b5/skills/README.md +52 -0
- aida_workbench-0.1.0b5/skills/pyirena-usage.md +75 -0
- aida_workbench-0.1.0b5/skills/review-checklist.md +93 -0
- aida_workbench-0.1.0b5/skills/saxs-basics.md +70 -0
- aida_workbench-0.1.0b5/src/aida/__init__.py +7 -0
- aida_workbench-0.1.0b5/src/aida/artifacts/__init__.py +30 -0
- aida_workbench-0.1.0b5/src/aida/artifacts/base.py +96 -0
- aida_workbench-0.1.0b5/src/aida/artifacts/policy.py +83 -0
- aida_workbench-0.1.0b5/src/aida/artifacts/store.py +156 -0
- aida_workbench-0.1.0b5/src/aida/cli/__init__.py +6 -0
- aida_workbench-0.1.0b5/src/aida/cli/__main__.py +123 -0
- aida_workbench-0.1.0b5/src/aida/cli/chat.py +388 -0
- aida_workbench-0.1.0b5/src/aida/cli/config_cmds.py +139 -0
- aida_workbench-0.1.0b5/src/aida/cli/conversations.py +366 -0
- aida_workbench-0.1.0b5/src/aida/cli/doctor.py +465 -0
- aida_workbench-0.1.0b5/src/aida/cli/documents_cmds.py +170 -0
- aida_workbench-0.1.0b5/src/aida/cli/kb_cmds.py +416 -0
- aida_workbench-0.1.0b5/src/aida/cli/mcp_cmds.py +579 -0
- aida_workbench-0.1.0b5/src/aida/cli/run.py +216 -0
- aida_workbench-0.1.0b5/src/aida/cli/schedule_cmds.py +222 -0
- aida_workbench-0.1.0b5/src/aida/cli/workflow_cmds.py +232 -0
- aida_workbench-0.1.0b5/src/aida/cli/workspace_cmds.py +283 -0
- aida_workbench-0.1.0b5/src/aida/coding/__init__.py +9 -0
- aida_workbench-0.1.0b5/src/aida/coding/runner.py +312 -0
- aida_workbench-0.1.0b5/src/aida/coding/templates.py +65 -0
- aida_workbench-0.1.0b5/src/aida/coding/tools.py +181 -0
- aida_workbench-0.1.0b5/src/aida/config/__init__.py +4 -0
- aida_workbench-0.1.0b5/src/aida/config/logging_setup.py +86 -0
- aida_workbench-0.1.0b5/src/aida/config/paths.py +231 -0
- aida_workbench-0.1.0b5/src/aida/config/secrets.py +75 -0
- aida_workbench-0.1.0b5/src/aida/config/settings.py +1522 -0
- aida_workbench-0.1.0b5/src/aida/config/users.py +168 -0
- aida_workbench-0.1.0b5/src/aida/core/__init__.py +1 -0
- aida_workbench-0.1.0b5/src/aida/core/agent.py +351 -0
- aida_workbench-0.1.0b5/src/aida/core/confirmation.py +172 -0
- aida_workbench-0.1.0b5/src/aida/core/context.py +683 -0
- aida_workbench-0.1.0b5/src/aida/core/cost.py +45 -0
- aida_workbench-0.1.0b5/src/aida/core/events.py +297 -0
- aida_workbench-0.1.0b5/src/aida/core/headless.py +46 -0
- aida_workbench-0.1.0b5/src/aida/core/proc_lock.py +70 -0
- aida_workbench-0.1.0b5/src/aida/core/scheduler_runtime.py +367 -0
- aida_workbench-0.1.0b5/src/aida/core/scheduling.py +151 -0
- aida_workbench-0.1.0b5/src/aida/core/session.py +1358 -0
- aida_workbench-0.1.0b5/src/aida/core/tools.py +109 -0
- aida_workbench-0.1.0b5/src/aida/core/workflows.py +279 -0
- aida_workbench-0.1.0b5/src/aida/documents/__init__.py +7 -0
- aida_workbench-0.1.0b5/src/aida/documents/attachments.py +159 -0
- aida_workbench-0.1.0b5/src/aida/documents/figure_tools.py +361 -0
- aida_workbench-0.1.0b5/src/aida/documents/figures.py +311 -0
- aida_workbench-0.1.0b5/src/aida/documents/ocr/__init__.py +22 -0
- aida_workbench-0.1.0b5/src/aida/documents/ocr/mistral.py +346 -0
- aida_workbench-0.1.0b5/src/aida/documents/readers.py +455 -0
- aida_workbench-0.1.0b5/src/aida/documents/tools.py +207 -0
- aida_workbench-0.1.0b5/src/aida/documents/writers/__init__.py +2 -0
- aida_workbench-0.1.0b5/src/aida/documents/writers/docx_writer.py +68 -0
- aida_workbench-0.1.0b5/src/aida/documents/writers/md_obsidian.py +152 -0
- aida_workbench-0.1.0b5/src/aida/knowledge/__init__.py +1 -0
- aida_workbench-0.1.0b5/src/aida/knowledge/rag/__init__.py +12 -0
- aida_workbench-0.1.0b5/src/aida/knowledge/rag/chunking.py +159 -0
- aida_workbench-0.1.0b5/src/aida/knowledge/rag/index.py +208 -0
- aida_workbench-0.1.0b5/src/aida/knowledge/rag/ingest.py +394 -0
- aida_workbench-0.1.0b5/src/aida/knowledge/rag/retrieval.py +141 -0
- aida_workbench-0.1.0b5/src/aida/mcp/__init__.py +22 -0
- aida_workbench-0.1.0b5/src/aida/mcp/argument_coercion.py +198 -0
- aida_workbench-0.1.0b5/src/aida/mcp/config_io.py +88 -0
- aida_workbench-0.1.0b5/src/aida/mcp/groups.py +125 -0
- aida_workbench-0.1.0b5/src/aida/mcp/manager.py +480 -0
- aida_workbench-0.1.0b5/src/aida/mcp/pyirena_setup.py +251 -0
- aida_workbench-0.1.0b5/src/aida/mcp/results.py +137 -0
- aida_workbench-0.1.0b5/src/aida/mcp/server.py +567 -0
- aida_workbench-0.1.0b5/src/aida/persistence/__init__.py +24 -0
- aida_workbench-0.1.0b5/src/aida/persistence/cleanup.py +247 -0
- aida_workbench-0.1.0b5/src/aida/persistence/db.py +195 -0
- aida_workbench-0.1.0b5/src/aida/persistence/recorder.py +343 -0
- aida_workbench-0.1.0b5/src/aida/persistence/records.py +230 -0
- aida_workbench-0.1.0b5/src/aida/persistence/store.py +622 -0
- aida_workbench-0.1.0b5/src/aida/providers/__init__.py +1 -0
- aida_workbench-0.1.0b5/src/aida/providers/anthropic_.py +533 -0
- aida_workbench-0.1.0b5/src/aida/providers/base.py +242 -0
- aida_workbench-0.1.0b5/src/aida/providers/embeddings_base.py +51 -0
- aida_workbench-0.1.0b5/src/aida/providers/mock.py +114 -0
- aida_workbench-0.1.0b5/src/aida/providers/mock_embeddings.py +60 -0
- aida_workbench-0.1.0b5/src/aida/providers/openai_compat.py +451 -0
- aida_workbench-0.1.0b5/src/aida/providers/openai_compat_embeddings.py +54 -0
- aida_workbench-0.1.0b5/src/aida/providers/profiles.py +169 -0
- aida_workbench-0.1.0b5/src/aida/providers/vision.py +121 -0
- aida_workbench-0.1.0b5/src/aida/ui/__init__.py +6 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/__init__.py +5 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/_qt.py +144 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/app.py +85 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/artifact_widgets.py +198 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/bridge.py +769 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/chat_panel.py +724 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/code_editor_dialog.py +218 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/collapsible.py +108 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/conversations_sidebar.py +435 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/icon.py +23 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/input_box.py +334 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/knowledge_management_dialog.py +433 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/main_window.py +2053 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/mcp_management_dialog.py +1295 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/notes_panel.py +134 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/onboarding_dialog.py +151 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/profiles_dialog.py +693 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/python_highlighter.py +63 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/quick_tasks_panel.py +229 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/resources/app_icon.png +0 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/retrieval_widget.py +75 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/schedule_management_dialog.py +414 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/scheduler_bridge.py +136 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/selectors.py +543 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/settings_dialog.py +379 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/tool_call_widget.py +173 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/users_dialog.py +253 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/window_state.py +53 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/workflow_management_dialog.py +471 -0
- aida_workbench-0.1.0b5/src/aida/ui/qt/workspace_management_dialog.py +495 -0
- aida_workbench-0.1.0b5/src/aida/workspace/__init__.py +29 -0
- aida_workbench-0.1.0b5/src/aida/workspace/command_allowlist.py +93 -0
- aida_workbench-0.1.0b5/src/aida/workspace/files.py +782 -0
- aida_workbench-0.1.0b5/src/aida/workspace/safety.py +408 -0
- aida_workbench-0.1.0b5/src/aida/workspace/web.py +126 -0
- aida_workbench-0.1.0b5/src/aida/workspace/workspaces.py +219 -0
- aida_workbench-0.1.0b5/tests/__init__.py +0 -0
- aida_workbench-0.1.0b5/tests/conftest.py +28 -0
- aida_workbench-0.1.0b5/tests/mock_mcp_server.py +106 -0
- aida_workbench-0.1.0b5/tests/test_agent_loop.py +681 -0
- aida_workbench-0.1.0b5/tests/test_anthropic_provider_ping.py +75 -0
- aida_workbench-0.1.0b5/tests/test_artifacts.py +171 -0
- aida_workbench-0.1.0b5/tests/test_attachments.py +375 -0
- aida_workbench-0.1.0b5/tests/test_chat_cli.py +1040 -0
- aida_workbench-0.1.0b5/tests/test_chunking.py +116 -0
- aida_workbench-0.1.0b5/tests/test_coding_runner.py +89 -0
- aida_workbench-0.1.0b5/tests/test_coding_templates.py +66 -0
- aida_workbench-0.1.0b5/tests/test_coding_tools.py +320 -0
- aida_workbench-0.1.0b5/tests/test_command_allowlist.py +59 -0
- aida_workbench-0.1.0b5/tests/test_compaction.py +186 -0
- aida_workbench-0.1.0b5/tests/test_config_cmds.py +177 -0
- aida_workbench-0.1.0b5/tests/test_confirmation.py +152 -0
- aida_workbench-0.1.0b5/tests/test_context.py +660 -0
- aida_workbench-0.1.0b5/tests/test_contract_layering.py +44 -0
- aida_workbench-0.1.0b5/tests/test_conversations_cli.py +268 -0
- aida_workbench-0.1.0b5/tests/test_cost.py +45 -0
- aida_workbench-0.1.0b5/tests/test_doctor.py +425 -0
- aida_workbench-0.1.0b5/tests/test_document_readers.py +424 -0
- aida_workbench-0.1.0b5/tests/test_document_tools.py +235 -0
- aida_workbench-0.1.0b5/tests/test_document_writers.py +252 -0
- aida_workbench-0.1.0b5/tests/test_events.py +60 -0
- aida_workbench-0.1.0b5/tests/test_figures.py +306 -0
- aida_workbench-0.1.0b5/tests/test_headless.py +115 -0
- aida_workbench-0.1.0b5/tests/test_kb_cmds.py +437 -0
- aida_workbench-0.1.0b5/tests/test_keystone_image_roundtrip.py +152 -0
- aida_workbench-0.1.0b5/tests/test_knowledge_index.py +151 -0
- aida_workbench-0.1.0b5/tests/test_knowledge_ingest.py +432 -0
- aida_workbench-0.1.0b5/tests/test_knowledge_retrieval.py +127 -0
- aida_workbench-0.1.0b5/tests/test_logging_setup.py +55 -0
- aida_workbench-0.1.0b5/tests/test_main_cli_dispatch.py +76 -0
- aida_workbench-0.1.0b5/tests/test_mcp_argument_coercion.py +160 -0
- aida_workbench-0.1.0b5/tests/test_mcp_cmds.py +444 -0
- aida_workbench-0.1.0b5/tests/test_mcp_config_io.py +98 -0
- aida_workbench-0.1.0b5/tests/test_mcp_groups.py +152 -0
- aida_workbench-0.1.0b5/tests/test_mcp_manager.py +673 -0
- aida_workbench-0.1.0b5/tests/test_mcp_results.py +236 -0
- aida_workbench-0.1.0b5/tests/test_mcp_server.py +492 -0
- aida_workbench-0.1.0b5/tests/test_mock_embeddings.py +71 -0
- aida_workbench-0.1.0b5/tests/test_ocr.py +469 -0
- aida_workbench-0.1.0b5/tests/test_paths.py +103 -0
- aida_workbench-0.1.0b5/tests/test_persistence_cleanup.py +156 -0
- aida_workbench-0.1.0b5/tests/test_persistence_db.py +198 -0
- aida_workbench-0.1.0b5/tests/test_persistence_recorder.py +269 -0
- aida_workbench-0.1.0b5/tests/test_persistence_records.py +223 -0
- aida_workbench-0.1.0b5/tests/test_persistence_store.py +309 -0
- aida_workbench-0.1.0b5/tests/test_phase4_acceptance.py +245 -0
- aida_workbench-0.1.0b5/tests/test_phase6_acceptance.py +216 -0
- aida_workbench-0.1.0b5/tests/test_proc_lock.py +51 -0
- aida_workbench-0.1.0b5/tests/test_profiles.py +177 -0
- aida_workbench-0.1.0b5/tests/test_provider_lifecycle.py +174 -0
- aida_workbench-0.1.0b5/tests/test_provider_param_fallback.py +338 -0
- aida_workbench-0.1.0b5/tests/test_provider_translation.py +921 -0
- aida_workbench-0.1.0b5/tests/test_pyirena_setup.py +148 -0
- aida_workbench-0.1.0b5/tests/test_regressions_phase6.py +332 -0
- aida_workbench-0.1.0b5/tests/test_review_2026_08_findings.py +556 -0
- aida_workbench-0.1.0b5/tests/test_run_cli.py +219 -0
- aida_workbench-0.1.0b5/tests/test_schedule_cmds.py +128 -0
- aida_workbench-0.1.0b5/tests/test_scheduler_runtime.py +465 -0
- aida_workbench-0.1.0b5/tests/test_scheduling.py +159 -0
- aida_workbench-0.1.0b5/tests/test_secrets.py +65 -0
- aida_workbench-0.1.0b5/tests/test_settings.py +941 -0
- aida_workbench-0.1.0b5/tests/test_start_session.py +1281 -0
- aida_workbench-0.1.0b5/tests/test_users.py +457 -0
- aida_workbench-0.1.0b5/tests/test_web_tools.py +153 -0
- aida_workbench-0.1.0b5/tests/test_workflow_cmds.py +185 -0
- aida_workbench-0.1.0b5/tests/test_workflows.py +338 -0
- aida_workbench-0.1.0b5/tests/test_workspace.py +259 -0
- aida_workbench-0.1.0b5/tests/test_workspace_cmds.py +478 -0
- aida_workbench-0.1.0b5/tests/test_workspace_files.py +514 -0
- aida_workbench-0.1.0b5/tests/test_workspace_safety.py +576 -0
- aida_workbench-0.1.0b5/tests/ui/__init__.py +0 -0
- aida_workbench-0.1.0b5/tests/ui/_qt_test_utils.py +40 -0
- aida_workbench-0.1.0b5/tests/ui/conftest.py +148 -0
- aida_workbench-0.1.0b5/tests/ui/test_app.py +67 -0
- aida_workbench-0.1.0b5/tests/ui/test_artifact_widgets.py +162 -0
- aida_workbench-0.1.0b5/tests/ui/test_bridge.py +495 -0
- aida_workbench-0.1.0b5/tests/ui/test_bridge_lifecycle.py +323 -0
- aida_workbench-0.1.0b5/tests/ui/test_chat_panel.py +679 -0
- aida_workbench-0.1.0b5/tests/ui/test_code_editor_dialog.py +218 -0
- aida_workbench-0.1.0b5/tests/ui/test_collapsible.py +67 -0
- aida_workbench-0.1.0b5/tests/ui/test_conversations_sidebar.py +668 -0
- aida_workbench-0.1.0b5/tests/ui/test_icon.py +17 -0
- aida_workbench-0.1.0b5/tests/ui/test_input_box.py +339 -0
- aida_workbench-0.1.0b5/tests/ui/test_knowledge_management_dialog.py +504 -0
- aida_workbench-0.1.0b5/tests/ui/test_main_window.py +3438 -0
- aida_workbench-0.1.0b5/tests/ui/test_mcp_management_dialog.py +844 -0
- aida_workbench-0.1.0b5/tests/ui/test_notes_panel.py +113 -0
- aida_workbench-0.1.0b5/tests/ui/test_onboarding_dialog.py +104 -0
- aida_workbench-0.1.0b5/tests/ui/test_profiles_dialog.py +376 -0
- aida_workbench-0.1.0b5/tests/ui/test_python_highlighter.py +61 -0
- aida_workbench-0.1.0b5/tests/ui/test_qt_contract.py +127 -0
- aida_workbench-0.1.0b5/tests/ui/test_quick_tasks_panel.py +197 -0
- aida_workbench-0.1.0b5/tests/ui/test_schedule_management_dialog.py +325 -0
- aida_workbench-0.1.0b5/tests/ui/test_scheduler_bridge.py +274 -0
- aida_workbench-0.1.0b5/tests/ui/test_selectors.py +572 -0
- aida_workbench-0.1.0b5/tests/ui/test_settings_dialog.py +381 -0
- aida_workbench-0.1.0b5/tests/ui/test_tool_call_widget.py +122 -0
- aida_workbench-0.1.0b5/tests/ui/test_users_dialog.py +206 -0
- aida_workbench-0.1.0b5/tests/ui/test_window_state.py +47 -0
- aida_workbench-0.1.0b5/tests/ui/test_workflow_management_dialog.py +338 -0
- aida_workbench-0.1.0b5/tests/ui/test_workspace_management_dialog.py +393 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Revisions `git blame` should look through rather than at.
|
|
2
|
+
#
|
|
3
|
+
# Enable it once per clone:
|
|
4
|
+
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
|
5
|
+
# (GitHub's blame view honours this file automatically.)
|
|
6
|
+
#
|
|
7
|
+
# Only ever add a commit that changed *no behaviour*. A mixed commit cannot
|
|
8
|
+
# be un-mixed later, which is why the formatting pass below was kept
|
|
9
|
+
# deliberately separate from the work around it.
|
|
10
|
+
|
|
11
|
+
# Formatting: ruff format across the tree, 2026-09-05.
|
|
12
|
+
# Verified AST-identical before and after, except 14 files where only
|
|
13
|
+
# docstring indentation changed.
|
|
14
|
+
70d5d0b90f53ba32333a2db864c77c0387de199b
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
15
|
+
python-version: ["3.11", "3.13"]
|
|
16
|
+
runs-on: ${{ matrix.os }}
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
# PySide6's QtGui module dynamically links these at import time even
|
|
26
|
+
# under QT_QPA_PLATFORM=offscreen (set in tests/ui/conftest.py) — the
|
|
27
|
+
# offscreen platform plugin avoids needing a real display, but the
|
|
28
|
+
# shared libraries themselves still have to be present. A bare
|
|
29
|
+
# ubuntu-latest runner has none of them, so tests/ui's whole
|
|
30
|
+
# collection failed at `import PySide6.QtGui` with
|
|
31
|
+
# "ImportError: libEGL.so.1: cannot open shared object file".
|
|
32
|
+
- name: Install Qt runtime libraries (Linux, headless)
|
|
33
|
+
if: runner.os == 'Linux'
|
|
34
|
+
run: |
|
|
35
|
+
sudo apt-get update
|
|
36
|
+
sudo apt-get install -y \
|
|
37
|
+
libegl1 libgl1 \
|
|
38
|
+
libxkbcommon0 libxkbcommon-x11-0 \
|
|
39
|
+
libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 \
|
|
40
|
+
libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 \
|
|
41
|
+
libdbus-1-3
|
|
42
|
+
|
|
43
|
+
- name: Install package (dev, gui, docs, ocr extras)
|
|
44
|
+
# `ocr` is only httpx, which the openai/anthropic SDKs already pull
|
|
45
|
+
# in — installing it explicitly means CI exercises the real
|
|
46
|
+
# optional-import path rather than the stubs alone.
|
|
47
|
+
run: pip install -e ".[dev,gui,docs,ocr]"
|
|
48
|
+
|
|
49
|
+
- name: Ruff lint
|
|
50
|
+
run: ruff check .
|
|
51
|
+
|
|
52
|
+
# Added after a one-off `ruff format` pass over the whole tree
|
|
53
|
+
# (see .git-blame-ignore-revs). Gating it only made sense once the
|
|
54
|
+
# tree was already clean: doing it the other way round turns main red
|
|
55
|
+
# on the very commit that fixes it.
|
|
56
|
+
- name: Ruff format check
|
|
57
|
+
run: ruff format --check .
|
|
58
|
+
|
|
59
|
+
# Two invocations, not one `pytest -v` over the whole tree: every GUI
|
|
60
|
+
# test shares a single process-wide QApplication (Qt disallows more
|
|
61
|
+
# than one) plus a fresh QThread+asyncio loop per test
|
|
62
|
+
# (tests/ui/conftest.py's `loop_thread`), and the non-GUI suite spawns
|
|
63
|
+
# its own real subprocesses (MCP manager/server tests, coding-tool
|
|
64
|
+
# tests). Combined into one pytest process, the two together push
|
|
65
|
+
# cumulative Qt object/thread churn on one long-lived QApplication
|
|
66
|
+
# high enough to occasionally hit a native crash deep in Qt's own
|
|
67
|
+
# event/timer dispatch — a segfault on Linux, an access violation on
|
|
68
|
+
# Windows, at a different call site each time, always somewhere under
|
|
69
|
+
# ChatBridge's background loop or later Qt event delivery, never at a
|
|
70
|
+
# line this project owns. Splitting the run in two roughly halves the
|
|
71
|
+
# cumulative churn either half accumulates and has not reproduced the
|
|
72
|
+
# crash across many repeated local runs (see
|
|
73
|
+
# planning/improvement_plan_2026-08.md's "Known issues" section for
|
|
74
|
+
# the full writeup and the longer-term follow-up options).
|
|
75
|
+
- name: Pytest (non-GUI)
|
|
76
|
+
run: pytest -v --ignore=tests/ui
|
|
77
|
+
|
|
78
|
+
- name: Pytest (GUI)
|
|
79
|
+
run: pytest -v tests/ui
|
|
80
|
+
|
|
81
|
+
# Validates the artifact users actually install, which the test job above
|
|
82
|
+
# does not: it runs against an editable install of the source tree, so a
|
|
83
|
+
# packaging mistake — a subpackage missing from the wheel, a bundled
|
|
84
|
+
# skills file not included, a dependency declared but unresolvable —
|
|
85
|
+
# passes every test and still breaks `pip install aida-workbench`. One
|
|
86
|
+
# cheap job, one OS: packaging errors of this kind are not
|
|
87
|
+
# platform-specific.
|
|
88
|
+
package:
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@v4
|
|
92
|
+
|
|
93
|
+
- name: Set up Python
|
|
94
|
+
uses: actions/setup-python@v5
|
|
95
|
+
with:
|
|
96
|
+
python-version: "3.11"
|
|
97
|
+
|
|
98
|
+
- name: Build the wheel and sdist
|
|
99
|
+
run: |
|
|
100
|
+
pip install build
|
|
101
|
+
python -m build
|
|
102
|
+
|
|
103
|
+
- name: Install the built wheel into a clean environment
|
|
104
|
+
run: |
|
|
105
|
+
python -m venv /tmp/wheel-check
|
|
106
|
+
/tmp/wheel-check/bin/pip install dist/*.whl
|
|
107
|
+
|
|
108
|
+
- name: Verify the installed package imports and its console script runs
|
|
109
|
+
run: |
|
|
110
|
+
/tmp/wheel-check/bin/python -c "import aida; print(aida.__version__ if hasattr(aida, '__version__') else 'ok')"
|
|
111
|
+
/tmp/wheel-check/bin/aida --help > /dev/null
|
|
112
|
+
|
|
113
|
+
- name: Verify the bundled skills travelled inside the wheel
|
|
114
|
+
# `pip install aida-workbench` users have no repo to copy these
|
|
115
|
+
# from — see the hatch build config's note on why they are packaged.
|
|
116
|
+
run: |
|
|
117
|
+
/tmp/wheel-check/bin/python -c "
|
|
118
|
+
from aida.config.paths import bundled_skills_dir
|
|
119
|
+
source = bundled_skills_dir()
|
|
120
|
+
assert source is not None, 'bundled skills are missing from the wheel'
|
|
121
|
+
entries = list(source.iterdir())
|
|
122
|
+
assert entries, f'{source} is present but empty'
|
|
123
|
+
print(f'{len(entries)} bundled skill entr(ies) present')
|
|
124
|
+
"
|
|
125
|
+
|
|
126
|
+
- name: pip check (declared dependencies actually resolve)
|
|
127
|
+
run: /tmp/wheel-check/bin/pip check
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
name: Build distribution
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
|
|
19
|
+
- name: Install build
|
|
20
|
+
run: python -m pip install --upgrade build
|
|
21
|
+
|
|
22
|
+
- name: Build package
|
|
23
|
+
run: python -m build
|
|
24
|
+
|
|
25
|
+
- name: Upload distributions
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: python-package-distributions
|
|
29
|
+
path: dist/
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
name: Publish to PyPI
|
|
33
|
+
needs: build
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
|
|
36
|
+
environment:
|
|
37
|
+
name: pypi
|
|
38
|
+
url: https://pypi.org/p/aida-workbench
|
|
39
|
+
|
|
40
|
+
permissions:
|
|
41
|
+
id-token: write
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Download distributions
|
|
45
|
+
uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: python-package-distributions
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
- name: Publish to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
|
|
11
|
+
# AIDA on-device state must never live in the repo.
|
|
12
|
+
# NOTE: intentionally NOT a bare `secrets*` glob — that pattern also matches
|
|
13
|
+
# (and silently drops from git / from built wheels) src/aida/config/secrets.py,
|
|
14
|
+
# the module that *implements* the no-secrets-on-disk guarantee. Real secrets
|
|
15
|
+
# never reach YAML/JSON in the first place (see aida.config.secrets +
|
|
16
|
+
# tests/test_secrets.py); these entries only guard against a stray file.
|
|
17
|
+
.aida/
|
|
18
|
+
*.db
|
|
19
|
+
logs/
|
|
20
|
+
secrets.yaml
|
|
21
|
+
secrets.json
|
|
22
|
+
secrets.env
|
|
23
|
+
.env
|
|
24
|
+
.env.*
|
|
25
|
+
|
|
26
|
+
# Editors / OS
|
|
27
|
+
.DS_Store
|
|
28
|
+
.idea/
|
|
29
|
+
.vscode/
|
|
30
|
+
*.swp
|
|
31
|
+
|
|
32
|
+
# Test / coverage
|
|
33
|
+
.pytest_cache/
|
|
34
|
+
.ruff_cache/
|
|
35
|
+
htmlcov/
|
|
36
|
+
.coverage
|
|
37
|
+
.playwright-mcp/*
|
|
38
|
+
|
|
39
|
+
#to delete
|
|
40
|
+
_to_delete/*
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# Wiring aievaluator-mcp and epics-mcp into Aida — setup + readiness check
|
|
2
|
+
|
|
3
|
+
**Status: 2026-09-03, night-before-testing checklist.** Both repos are far
|
|
4
|
+
further along than the plan from earlier today assumed — this isn't a "here's
|
|
5
|
+
the design" document, it's "here's what's actually built, here's the mcp.json
|
|
6
|
+
to add, and here's the exact list of things that still need doing before PV
|
|
7
|
+
access will work tomorrow."
|
|
8
|
+
|
|
9
|
+
I reviewed both repos' current code (not just docs) — `aievaluator` at
|
|
10
|
+
commit `6cfcc59`, `epics-mcp` at commit `dd3d0c9`. I could not run anything
|
|
11
|
+
against your real conda environments or the instrument from here (this
|
|
12
|
+
session's shell reaches your files but not your actual `aievaluator`/
|
|
13
|
+
`epics-mcp` conda environments or `usaxscontrol`), so the "run tomorrow"
|
|
14
|
+
commands below are the verification I couldn't do for you.
|
|
15
|
+
|
|
16
|
+
## 1. Bottom line
|
|
17
|
+
|
|
18
|
+
Both packages are **code-complete for a stdio, single-machine, read-mostly
|
|
19
|
+
test tomorrow.** Nothing structural is missing. What's actually left is:
|
|
20
|
+
(a) two setup steps neither README currently spells out that will silently
|
|
21
|
+
break the connection if skipped, (b) filling in your real
|
|
22
|
+
`EPICS_CA_ADDR_LIST`, (c) the mcp.json entries below, and (d) the
|
|
23
|
+
verification commands to run before opening Aida, so a failure shows up as
|
|
24
|
+
a clear CLI error instead of a confusing tool-call failure inside a chat.
|
|
25
|
+
|
|
26
|
+
## 2. What's actually implemented (I read the code, not just the plan)
|
|
27
|
+
|
|
28
|
+
### aievaluator (0.1.0)
|
|
29
|
+
|
|
30
|
+
Fully built: `checks/{beam,energy,flux,tunes,fitness}.py` as library
|
|
31
|
+
functions, `epics_io.py` (single CA interface), YAML config
|
|
32
|
+
(`~/.aievaluator/instrument.yaml`, auto-seeded), `cli.py` (9 subcommands),
|
|
33
|
+
`aievaluator-mcp` (7 tools: `check_beam_status`, `check_energy_match`,
|
|
34
|
+
`check_flux`, `check_tunes`, `fitness_report`, `read_pvs`,
|
|
35
|
+
`describe_checks`), `doctor.py`, three skill files, a test suite that runs
|
|
36
|
+
with no IOC. `tools/*.py` and `fitness_report.sh` are kept as deprecation
|
|
37
|
+
shims, so nothing that already depends on them broke.
|
|
38
|
+
|
|
39
|
+
Genuinely open (from the repo's own PLAN.md, not my speculation):
|
|
40
|
+
|
|
41
|
+
- **The PV names and thresholds in `instrument_usaxs.yaml` have never been
|
|
42
|
+
checked against the live instrument.** They were carried over verbatim
|
|
43
|
+
from the old `tools/*.py` scripts while the instrument was offline for
|
|
44
|
+
commissioning. PLAN.md calls this out explicitly as a gate that still
|
|
45
|
+
has to happen "before this package is used for a real fitness report or
|
|
46
|
+
a real 'is the beam OK' answer." **This is what tomorrow's test actually
|
|
47
|
+
validates** — go in expecting to find at least one stale PV name or
|
|
48
|
+
threshold, not expecting everything to just work.
|
|
49
|
+
- BeamlineAdvisor hasn't been switched over to import `aievaluator.checks`
|
|
50
|
+
yet (still has its own duplicate PV logic) — not a blocker for you
|
|
51
|
+
testing aievaluator-mcp from Aida, just still open.
|
|
52
|
+
- `--transport http` prints "not implemented" and exits — irrelevant
|
|
53
|
+
tomorrow, since Aida launches this as a local stdio subprocess.
|
|
54
|
+
|
|
55
|
+
### epics-mcp (0.1.0.dev0)
|
|
56
|
+
|
|
57
|
+
Also fully built, further than its own README currently admits — **the
|
|
58
|
+
README's top line still says "Status: pre-alpha. No implementation yet,"
|
|
59
|
+
which is now false; everything below exists in `src/epics_mcp/`:**
|
|
60
|
+
`policy.py` (539 lines — the deny/allow/write engine, glob + `re:` regex,
|
|
61
|
+
deny-shadowing checks, confirm tokens), `ca_client.py` (pyepics + a
|
|
62
|
+
`FakeBackend` for testing without EPICS), `catalog.py`, `audit.py`,
|
|
63
|
+
`ratelimit.py`, `server.py` (6 tools: `epics_pv_get`, `epics_pv_info`,
|
|
64
|
+
`epics_pv_watch`, `epics_policy_describe`, `epics_pv_search`, and
|
|
65
|
+
`epics_pv_put` — registered only when the policy allows writes at all),
|
|
66
|
+
`cli.py`, `doctor.py`. Two example policies
|
|
67
|
+
(`policy_usaxs_readonly.yaml`, `policy_usaxs_staff.yaml`) and a PV catalog.
|
|
68
|
+
Tests cover the policy engine, CA client, catalog, audit, rate limiter,
|
|
69
|
+
CLI, and a full stdio session against `FakeBackend`.
|
|
70
|
+
|
|
71
|
+
Genuinely open:
|
|
72
|
+
|
|
73
|
+
- **Never exercised against a live IOC or even a `softIoc`.** The write
|
|
74
|
+
path (confirm tokens, rate limiting, audit) is verified end-to-end
|
|
75
|
+
against `FakeBackend` only. Tomorrow, with real PV access, is the first
|
|
76
|
+
time any of this touches a real Channel Access server.
|
|
77
|
+
- The staff policy's write rules beyond `usxLAX:userCalc*.A` are marked
|
|
78
|
+
`TODO(verify)` in the file itself — PV names taken from a design doc,
|
|
79
|
+
not a live `caget`. **Don't deploy `policy_usaxs_staff.yaml` as-is; start
|
|
80
|
+
read-only.** (Detail below.)
|
|
81
|
+
- `--transport http` has no bearer-token auth yet — irrelevant tomorrow,
|
|
82
|
+
same reason as aievaluator.
|
|
83
|
+
- **Fix the README's status line** — five-minute doc fix, but worth doing
|
|
84
|
+
so nobody re-derives "is this built yet?" from a stale sentence again.
|
|
85
|
+
|
|
86
|
+
## 3. Two setup steps that will silently break things if skipped
|
|
87
|
+
|
|
88
|
+
Neither of these is a bug — they're just not obvious from either README,
|
|
89
|
+
and both fail *quietly* (a PV that should connect just won't, or a skill
|
|
90
|
+
that should load just won't be there) rather than with a clear error.
|
|
91
|
+
|
|
92
|
+
**A. Aida does not pass your shell's environment through to MCP
|
|
93
|
+
subprocesses.** I checked `src/aida/mcp/server.py`: it builds an explicit
|
|
94
|
+
`env` dict for each server subprocess (scratch `TMPDIR`/`TEMP`/`TMP` plus
|
|
95
|
+
whatever `mcp.json`'s own `env` block says) and hands that to the MCP
|
|
96
|
+
SDK's `StdioServerParameters`, which does **not** inherit your terminal's
|
|
97
|
+
full environment the way a normally-launched `aievaluator-mcp` from a
|
|
98
|
+
terminal would. Concretely: **if `EPICS_CA_ADDR_LIST` isn't set explicitly
|
|
99
|
+
in the server's `env` block in `mcp.json`, the subprocess Aida launches
|
|
100
|
+
won't have it**, even though `aievaluator doctor` run by hand in the same
|
|
101
|
+
terminal works fine. The symptom would be every PV coming back
|
|
102
|
+
`"connected": false` from inside Aida while the CLI tools work standalone
|
|
103
|
+
— confusing to debug blind. The mcp.json below sets this explicitly; you
|
|
104
|
+
need to fill in the real value(s) for your network (marked below).
|
|
105
|
+
|
|
106
|
+
**B. The PV catalog file has to sit next to the policy file you copy, not
|
|
107
|
+
just next to the example.** `epics-mcp`'s policy loader resolves
|
|
108
|
+
`catalog: pv_catalog_usaxs.txt` relative to the *copied* policy file's own
|
|
109
|
+
directory (`policy.py`'s `Policy.load`), not the repo's `examples/`
|
|
110
|
+
directory. The README's copy command only copies the policy file:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
cp examples/policy_usaxs_readonly.yaml ~/.epics-mcp/policies/usaxs-user.yaml
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Without also copying the catalog, `epics_pv_search` silently returns
|
|
117
|
+
nothing (the server logs a warning and starts anyway — it does not
|
|
118
|
+
refuse to start, so this is easy to miss). Copy both:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
mkdir -p ~/.epics-mcp/policies
|
|
122
|
+
cp examples/policy_usaxs_readonly.yaml ~/.epics-mcp/policies/usaxs-user.yaml
|
|
123
|
+
cp examples/pv_catalog_usaxs.txt ~/.epics-mcp/policies/pv_catalog_usaxs.txt
|
|
124
|
+
# staff policy, if/when you use it:
|
|
125
|
+
cp examples/policy_usaxs_staff.yaml ~/.epics-mcp/policies/usaxs-staff.yaml
|
|
126
|
+
cp examples/pv_catalog_usaxs.txt ~/.epics-mcp/policies/pv_catalog_usaxs.txt # same file, already there
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**C. (smaller) Skills have to be copied into `~/.aida/skills/`, not
|
|
130
|
+
referenced from the aievaluator repo path.** Aida resolves a workspace's
|
|
131
|
+
`skills: [...]` names against `~/.aida/skills/<name>.md` (`aida.core.context.
|
|
132
|
+
skill_path`) — it does not read them from wherever aievaluator happens to
|
|
133
|
+
be checked out.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
mkdir -p ~/.aida/skills
|
|
137
|
+
cp ~/GitHub/aievaluator/skills/aievaluator.md ~/.aida/skills/
|
|
138
|
+
cp ~/GitHub/aievaluator/skills/usaxs-instrument.md ~/.aida/skills/
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`epics-mcp` doesn't ship a skill file at all yet (each tool's own docstring
|
|
142
|
+
is reasonably thorough, since FastMCP surfaces those to the model — this
|
|
143
|
+
is a nice-to-have, not a blocker for tomorrow).
|
|
144
|
+
|
|
145
|
+
## 4. mcp.json entries to add
|
|
146
|
+
|
|
147
|
+
Merge this into your real `~/.aida/mcp.json` (I can't write to that path
|
|
148
|
+
from here — it's outside the folders connected to this session; the
|
|
149
|
+
folders I can reach are the three repo checkouts). Adjust the two
|
|
150
|
+
`command` paths if your actual conda env prefixes differ from what your
|
|
151
|
+
shell showed me (`/opt/miniconda3/envs/aievaluator`,
|
|
152
|
+
`/opt/miniconda3/envs/epics-mcp`), and **fill in the real
|
|
153
|
+
`EPICS_CA_ADDR_LIST`** — I don't have your beamline's actual CA gateway
|
|
154
|
+
address, and a wrong or placeholder value will connect to nothing.
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"mcpServers": {
|
|
159
|
+
"aievaluator-mcp": {
|
|
160
|
+
"command": "/opt/miniconda3/envs/aievaluator/bin/aievaluator-mcp",
|
|
161
|
+
"args": [],
|
|
162
|
+
"env": {
|
|
163
|
+
"EPICS_CA_ADDR_LIST": "FILL_IN_YOUR_CA_GATEWAY",
|
|
164
|
+
"EPICS_CA_AUTO_ADDR_LIST": "NO"
|
|
165
|
+
},
|
|
166
|
+
"groups": ["instrument-status", "instrument-staff"],
|
|
167
|
+
"skills": ["aievaluator", "usaxs-instrument"],
|
|
168
|
+
"confirm_tools": ["fitness_report"]
|
|
169
|
+
},
|
|
170
|
+
"epics-mcp-user": {
|
|
171
|
+
"command": "/opt/miniconda3/envs/epics-mcp/bin/epics-mcp",
|
|
172
|
+
"args": ["--policy", "usaxs-user"],
|
|
173
|
+
"env": {
|
|
174
|
+
"EPICS_CA_ADDR_LIST": "FILL_IN_YOUR_CA_GATEWAY",
|
|
175
|
+
"EPICS_CA_AUTO_ADDR_LIST": "NO"
|
|
176
|
+
},
|
|
177
|
+
"groups": ["instrument-status"],
|
|
178
|
+
"skills": [],
|
|
179
|
+
"disabled_tools": []
|
|
180
|
+
},
|
|
181
|
+
"epics-mcp-staff": {
|
|
182
|
+
"command": "/opt/miniconda3/envs/epics-mcp/bin/epics-mcp",
|
|
183
|
+
"args": ["--policy", "usaxs-staff"],
|
|
184
|
+
"env": {
|
|
185
|
+
"EPICS_CA_ADDR_LIST": "FILL_IN_YOUR_CA_GATEWAY",
|
|
186
|
+
"EPICS_CA_AUTO_ADDR_LIST": "NO"
|
|
187
|
+
},
|
|
188
|
+
"groups": ["instrument-staff"],
|
|
189
|
+
"skills": [],
|
|
190
|
+
"confirm_tools": ["epics_pv_put"]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Notes on the choices above:
|
|
197
|
+
|
|
198
|
+
- **Two `epics-mcp` server entries, not one.** A single `mcp.json` entry
|
|
199
|
+
is one fixed `command`/`args`, and the policy is chosen by
|
|
200
|
+
`--policy NAME` on the command line — there's no way to expose both a
|
|
201
|
+
read-only and a write-capable mode from one entry. `epics-mcp-user`
|
|
202
|
+
(read-only) and `epics-mcp-staff` (write-enabled) are two separate
|
|
203
|
+
subprocesses, two separate groups, so a `usaxs-user` workspace can point
|
|
204
|
+
`mcp_group` at `instrument-status` and structurally never see
|
|
205
|
+
`epics_pv_put`.
|
|
206
|
+
- **`confirm_tools: ["epics_pv_put"]` on the staff server is a second,
|
|
207
|
+
client-side layer on top of the confirm-token protocol
|
|
208
|
+
`epics_pv_put` already has built in** (a non-`confirm: true` write rule,
|
|
209
|
+
like `usxLAX:userCalc*.A`, writes on the first call otherwise). Given
|
|
210
|
+
neither the write path nor the instrument have ever been tested
|
|
211
|
+
together, I'd keep this on even after things are working — it's cheap
|
|
212
|
+
insurance for a tool that changes hardware state.
|
|
213
|
+
- **`confirm_tools: ["fitness_report"]`** on aievaluator matches the
|
|
214
|
+
hand-off table the aievaluator repo's own PLAN.md wrote for AIDA — it's
|
|
215
|
+
the one tool in that server that writes anything (to the Obsidian
|
|
216
|
+
vault).
|
|
217
|
+
- **I put `aievaluator-mcp` in both groups** since its tools are read-only
|
|
218
|
+
regardless of who's asking; only the `epics-mcp-*` split needs to differ
|
|
219
|
+
between the two groups.
|
|
220
|
+
- `EPICS_CA_AUTO_ADDR_LIST: "NO"` is a guess at your usual convention
|
|
221
|
+
(explicit address list, no auto-discovery) — set it to match however
|
|
222
|
+
you normally run `caget` on this network; if you don't know, leave it
|
|
223
|
+
unset and only set `EPICS_CA_ADDR_LIST`.
|
|
224
|
+
|
|
225
|
+
You don't have to fold these into workspaces to test connectivity — `aida
|
|
226
|
+
mcp server test <name>` (step 5 below) works against the raw server entry.
|
|
227
|
+
Workspaces (`usaxs-user` / `usaxs-staff` pointing `mcp_group` at
|
|
228
|
+
`instrument-status` / `instrument-staff`) are worth creating once the
|
|
229
|
+
servers themselves are confirmed working — happy to draft
|
|
230
|
+
`workspaces.yaml` entries for those next, once tomorrow's test tells us
|
|
231
|
+
whether the group split above is actually the shape you want.
|
|
232
|
+
|
|
233
|
+
## 5. Exact commands to run before opening Aida tomorrow
|
|
234
|
+
|
|
235
|
+
In order — each one gates the next, and each failure tells you exactly
|
|
236
|
+
what's still missing rather than surfacing as a vague tool-call error
|
|
237
|
+
inside a chat session.
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# 1. Confirm both console scripts actually exist and import cleanly —
|
|
241
|
+
# catches an incomplete `pip install -e` before anything else does.
|
|
242
|
+
conda run -n aievaluator aievaluator --help
|
|
243
|
+
conda run -n epics-mcp epics-mcp --version
|
|
244
|
+
|
|
245
|
+
# 2. aievaluator's own reachability check (config, pyepics, one PV,
|
|
246
|
+
# Tiled, the Obsidian mount) — run this FIRST, it's the fastest way
|
|
247
|
+
# to find a wrong PV name or an unreachable network mount.
|
|
248
|
+
conda run -n aievaluator aievaluator doctor
|
|
249
|
+
|
|
250
|
+
# 3. Policy setup, if not already done (see §3.B above) — then validate
|
|
251
|
+
# the policy file loads and shows the rules you expect, with no live
|
|
252
|
+
# PV access yet.
|
|
253
|
+
conda run -n epics-mcp epics-mcp --policy usaxs-user --check
|
|
254
|
+
|
|
255
|
+
# 4. epics-mcp's own reachability check — same shape as #2, plus
|
|
256
|
+
# catalog + audit-log-writable checks specific to epics-mcp.
|
|
257
|
+
conda run -n epics-mcp epics-mcp doctor --policy usaxs-user
|
|
258
|
+
|
|
259
|
+
# 5. A real PV read from each package's own CLI, bypassing Aida and MCP
|
|
260
|
+
# entirely — the cleanest possible signal that Channel Access itself
|
|
261
|
+
# works from this machine before adding Aida's subprocess-env layer
|
|
262
|
+
# (§3.A) on top.
|
|
263
|
+
conda run -n aievaluator aievaluator check-beam --pretty
|
|
264
|
+
conda run -n epics-mcp epics-mcp --policy usaxs-user --check # rules only
|
|
265
|
+
# then, once EPICS_CA_ADDR_LIST is exported in this shell:
|
|
266
|
+
conda run -n aievaluator python -c "from aievaluator.epics_io import EpicsIO; io = EpicsIO(timeout=5.0); print(io.read('XFD:srCurrent')); io.close()"
|
|
267
|
+
|
|
268
|
+
# 6. Only once 1-5 are all green: add the mcp.json entries from §4 (with
|
|
269
|
+
# the real EPICS_CA_ADDR_LIST filled in), then from Aida:
|
|
270
|
+
aida mcp server test aievaluator-mcp # expect: OK — 7 tool(s)
|
|
271
|
+
aida mcp server test epics-mcp-user # expect: OK — 5 tool(s) (no pv_put, read-only)
|
|
272
|
+
aida mcp server test epics-mcp-staff # expect: OK — 6 tool(s) (pv_put present)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
If step 2 or 4 fails on the Tiled or Obsidian checks specifically, that's
|
|
276
|
+
network/mount reachability from wherever you're running this (a laptop vs.
|
|
277
|
+
`usaxscontrol` will differ), not a code problem — worth knowing before you
|
|
278
|
+
read too much into it.
|
|
279
|
+
|
|
280
|
+
## 6. If PV access itself isn't available tomorrow
|
|
281
|
+
|
|
282
|
+
Both servers work today with the read-only checks disabled and everything
|
|
283
|
+
else exercised: `epics-mcp --backend fake` serves canned values with no
|
|
284
|
+
EPICS installed at all (built for exactly this), and every aievaluator
|
|
285
|
+
test already runs against `FakeEpicsIO`. So even without real PV access
|
|
286
|
+
tomorrow you can still validate: both console scripts run, both `--check`/
|
|
287
|
+
`doctor` commands behave sensibly, `aida mcp server test` lists the right
|
|
288
|
+
tool counts for each of the three entries, and — for `epics-mcp-user`,
|
|
289
|
+
which is the one that most needs to be right before staff ever sees it —
|
|
290
|
+
that `epics_pv_put` really is absent from the tool list Aida sees. That
|
|
291
|
+
last check *is* the read-only boundary working; it doesn't need beam.
|
|
292
|
+
|
|
293
|
+
## 7. Priority order if you only have time for some of this
|
|
294
|
+
|
|
295
|
+
1. §3.A and §3.B (env passthrough, catalog copy) — skip these and nothing
|
|
296
|
+
above will work, and the failure will look like an instrument problem.
|
|
297
|
+
2. §5 steps 1–5, standalone, no Aida involved — isolates "is Channel
|
|
298
|
+
Access working from this machine at all" from "is Aida configured
|
|
299
|
+
right."
|
|
300
|
+
3. §4's mcp.json, with the real `EPICS_CA_ADDR_LIST`.
|
|
301
|
+
4. §5 step 6 — `aida mcp server test` for all three entries.
|
|
302
|
+
5. Only after all of the above are green: try the staff write path
|
|
303
|
+
(`usxLAX:userCalc*.A`, the one verified-safe write rule) — through
|
|
304
|
+
`epics-mcp --policy usaxs-staff` on its own CLI-adjacent doctor first
|
|
305
|
+
if one existed, otherwise directly through `epics_pv_put` in a Aida
|
|
306
|
+
chat, expecting the `confirm_required` round-trip on any rule marked
|
|
307
|
+
`confirm: true`, and no round-trip at all (single call, immediate
|
|
308
|
+
write) for `usxLAX:userCalc*.A`, which has `confirm: false`.
|
|
309
|
+
6. Everything else in §2 ("genuinely open") is real work but isn't gating
|
|
310
|
+
tomorrow's test — including the live-instrument PV/threshold
|
|
311
|
+
validation, which tomorrow's test *starts* rather than something that
|
|
312
|
+
has to be finished first.
|