#
tokens: 46754/50000 2/1784 files (page 110/145)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 110 of 145. Use http://codebase.md/microsoft/semanticworkbench?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .devcontainer
│   ├── .vscode
│   │   └── settings.json
│   ├── devcontainer.json
│   ├── OPTIMIZING_FOR_CODESPACES.md
│   ├── POST_SETUP_README.md
│   └── README.md
├── .dockerignore
├── .gitattributes
├── .github
│   ├── policheck.yml
│   └── workflows
│       ├── assistants-codespace-assistant.yml
│       ├── assistants-document-assistant.yml
│       ├── assistants-explorer-assistant.yml
│       ├── assistants-guided-conversation-assistant.yml
│       ├── assistants-knowledge-transfer-assistant.yml
│       ├── assistants-navigator-assistant.yml
│       ├── assistants-project-assistant.yml
│       ├── assistants-prospector-assistant.yml
│       ├── assistants-skill-assistant.yml
│       ├── libraries.yml
│       ├── mcp-server-giphy.yml
│       ├── mcp-server-memory-filesystem-edit.yml
│       ├── mcp-server-memory-user-bio.yml
│       ├── mcp-server-memory-whiteboard.yml
│       ├── mcp-server-open-deep-research-clone.yml
│       ├── mcp-server-web-research.yml
│       ├── workbench-app.yml
│       └── workbench-service.yml
├── .gitignore
├── .multi-root-tools
│   ├── Makefile
│   └── README.md
├── .vscode
│   ├── extensions.json
│   ├── launch.json
│   └── settings.json
├── ai_context
│   └── generated
│       ├── ASPIRE_ORCHESTRATOR.md
│       ├── ASSISTANT_CODESPACE.md
│       ├── ASSISTANT_DOCUMENT.md
│       ├── ASSISTANT_NAVIGATOR.md
│       ├── ASSISTANT_PROJECT.md
│       ├── ASSISTANT_PROSPECTOR.md
│       ├── ASSISTANTS_OTHER.md
│       ├── ASSISTANTS_OVERVIEW.md
│       ├── CONFIGURATION.md
│       ├── DOTNET_LIBRARIES.md
│       ├── EXAMPLES.md
│       ├── MCP_SERVERS.md
│       ├── PYTHON_LIBRARIES_AI_CLIENTS.md
│       ├── PYTHON_LIBRARIES_CORE.md
│       ├── PYTHON_LIBRARIES_EXTENSIONS.md
│       ├── PYTHON_LIBRARIES_SKILLS.md
│       ├── PYTHON_LIBRARIES_SPECIALIZED.md
│       ├── TOOLS.md
│       ├── WORKBENCH_FRONTEND.md
│       └── WORKBENCH_SERVICE.md
├── aspire-orchestrator
│   ├── .editorconfig
│   ├── Aspire.AppHost
│   │   ├── .gitignore
│   │   ├── appsettings.json
│   │   ├── Aspire.AppHost.csproj
│   │   ├── Program.cs
│   │   └── Properties
│   │       └── launchSettings.json
│   ├── Aspire.Extensions
│   │   ├── Aspire.Extensions.csproj
│   │   ├── Dashboard.cs
│   │   ├── DockerFileExtensions.cs
│   │   ├── PathNormalizer.cs
│   │   ├── UvAppHostingExtensions.cs
│   │   ├── UvAppResource.cs
│   │   ├── VirtualEnvironment.cs
│   │   └── WorkbenchServiceHostingExtensions.cs
│   ├── Aspire.ServiceDefaults
│   │   ├── Aspire.ServiceDefaults.csproj
│   │   └── Extensions.cs
│   ├── README.md
│   ├── run.sh
│   ├── SemanticWorkbench.Aspire.sln
│   └── SemanticWorkbench.Aspire.sln.DotSettings
├── assistants
│   ├── codespace-assistant
│   │   ├── .claude
│   │   │   └── settings.local.json
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── extensions.json
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── assets
│   │   │   │   ├── icon_context_transfer.svg
│   │   │   │   └── icon.svg
│   │   │   ├── chat.py
│   │   │   ├── config.py
│   │   │   ├── helpers.py
│   │   │   ├── response
│   │   │   │   ├── __init__.py
│   │   │   │   ├── completion_handler.py
│   │   │   │   ├── models.py
│   │   │   │   ├── request_builder.py
│   │   │   │   ├── response.py
│   │   │   │   ├── step_handler.py
│   │   │   │   └── utils
│   │   │   │       ├── __init__.py
│   │   │   │       ├── abbreviations.py
│   │   │   │       ├── formatting_utils.py
│   │   │   │       ├── message_utils.py
│   │   │   │       └── openai_utils.py
│   │   │   ├── text_includes
│   │   │   │   ├── card_content_context_transfer.md
│   │   │   │   ├── card_content.md
│   │   │   │   ├── codespace_assistant_info.md
│   │   │   │   ├── context_transfer_assistant_info.md
│   │   │   │   ├── guardrails_prompt.txt
│   │   │   │   ├── guidance_prompt_context_transfer.txt
│   │   │   │   ├── guidance_prompt.txt
│   │   │   │   ├── instruction_prompt_context_transfer.txt
│   │   │   │   └── instruction_prompt.txt
│   │   │   └── whiteboard
│   │   │       ├── __init__.py
│   │   │       ├── _inspector.py
│   │   │       └── _whiteboard.py
│   │   ├── assistant.code-workspace
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── document-assistant
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── assets
│   │   │   │   └── icon.svg
│   │   │   ├── chat.py
│   │   │   ├── config.py
│   │   │   ├── context_management
│   │   │   │   ├── __init__.py
│   │   │   │   └── inspector.py
│   │   │   ├── filesystem
│   │   │   │   ├── __init__.py
│   │   │   │   ├── _convert.py
│   │   │   │   ├── _file_sources.py
│   │   │   │   ├── _filesystem.py
│   │   │   │   ├── _inspector.py
│   │   │   │   ├── _model.py
│   │   │   │   ├── _prompts.py
│   │   │   │   └── _tasks.py
│   │   │   ├── guidance
│   │   │   │   ├── __init__.py
│   │   │   │   ├── dynamic_ui_inspector.py
│   │   │   │   ├── guidance_config.py
│   │   │   │   ├── guidance_prompts.py
│   │   │   │   └── README.md
│   │   │   ├── response
│   │   │   │   ├── __init__.py
│   │   │   │   ├── completion_handler.py
│   │   │   │   ├── models.py
│   │   │   │   ├── prompts.py
│   │   │   │   ├── responder.py
│   │   │   │   └── utils
│   │   │   │       ├── __init__.py
│   │   │   │       ├── formatting_utils.py
│   │   │   │       ├── message_utils.py
│   │   │   │       ├── openai_utils.py
│   │   │   │       ├── tokens_tiktoken.py
│   │   │   │       └── workbench_messages.py
│   │   │   ├── text_includes
│   │   │   │   └── document_assistant_info.md
│   │   │   ├── types.py
│   │   │   └── whiteboard
│   │   │       ├── __init__.py
│   │   │       ├── _inspector.py
│   │   │       └── _whiteboard.py
│   │   ├── assistant.code-workspace
│   │   ├── CLAUDE.md
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_convert.py
│   │   │   └── test_data
│   │   │       ├── blank_image.png
│   │   │       ├── Formatting Test.docx
│   │   │       ├── sample_data.csv
│   │   │       ├── sample_data.xlsx
│   │   │       ├── sample_page.html
│   │   │       ├── sample_presentation.pptx
│   │   │       └── simple_pdf.pdf
│   │   └── uv.lock
│   ├── explorer-assistant
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── chat.py
│   │   │   ├── config.py
│   │   │   ├── helpers.py
│   │   │   ├── response
│   │   │   │   ├── __init__.py
│   │   │   │   ├── model.py
│   │   │   │   ├── response_anthropic.py
│   │   │   │   ├── response_openai.py
│   │   │   │   └── response.py
│   │   │   └── text_includes
│   │   │       └── guardrails_prompt.txt
│   │   ├── assistant.code-workspace
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── guided-conversation-assistant
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── agents
│   │   │   │   ├── guided_conversation
│   │   │   │   │   ├── config.py
│   │   │   │   │   ├── definition.py
│   │   │   │   │   └── definitions
│   │   │   │   │       ├── er_triage.py
│   │   │   │   │       ├── interview.py
│   │   │   │   │       ├── patient_intake.py
│   │   │   │   │       └── poem_feedback.py
│   │   │   │   └── guided_conversation_agent.py
│   │   │   ├── chat.py
│   │   │   ├── config.py
│   │   │   └── text_includes
│   │   │       └── guardrails_prompt.txt
│   │   ├── assistant.code-workspace
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── knowledge-transfer-assistant
│   │   ├── .claude
│   │   │   └── settings.local.json
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── agentic
│   │   │   │   ├── __init__.py
│   │   │   │   ├── analysis.py
│   │   │   │   ├── coordinator_support.py
│   │   │   │   └── team_welcome.py
│   │   │   ├── assets
│   │   │   │   ├── icon-knowledge-transfer.svg
│   │   │   │   └── icon.svg
│   │   │   ├── assistant.py
│   │   │   ├── common.py
│   │   │   ├── config.py
│   │   │   ├── conversation_clients.py
│   │   │   ├── conversation_share_link.py
│   │   │   ├── data.py
│   │   │   ├── domain
│   │   │   │   ├── __init__.py
│   │   │   │   ├── audience_manager.py
│   │   │   │   ├── information_request_manager.py
│   │   │   │   ├── knowledge_brief_manager.py
│   │   │   │   ├── knowledge_digest_manager.py
│   │   │   │   ├── learning_objectives_manager.py
│   │   │   │   └── share_manager.py
│   │   │   ├── files.py
│   │   │   ├── logging.py
│   │   │   ├── notifications.py
│   │   │   ├── respond.py
│   │   │   ├── storage_models.py
│   │   │   ├── storage.py
│   │   │   ├── string_utils.py
│   │   │   ├── text_includes
│   │   │   │   ├── assistant_info.md
│   │   │   │   ├── card_content.md
│   │   │   │   ├── coordinator_instructions.txt
│   │   │   │   ├── coordinator_role.txt
│   │   │   │   ├── knowledge_digest_instructions.txt
│   │   │   │   ├── knowledge_digest_prompt.txt
│   │   │   │   ├── share_information_request_detection.txt
│   │   │   │   ├── team_instructions.txt
│   │   │   │   ├── team_role.txt
│   │   │   │   └── welcome_message_generation.txt
│   │   │   ├── tools
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base.py
│   │   │   │   ├── information_requests.py
│   │   │   │   ├── learning_objectives.py
│   │   │   │   ├── learning_outcomes.py
│   │   │   │   ├── progress_tracking.py
│   │   │   │   └── share_setup.py
│   │   │   ├── ui_tabs
│   │   │   │   ├── __init__.py
│   │   │   │   ├── brief.py
│   │   │   │   ├── common.py
│   │   │   │   ├── debug.py
│   │   │   │   ├── learning.py
│   │   │   │   └── sharing.py
│   │   │   └── utils.py
│   │   ├── CLAUDE.md
│   │   ├── docs
│   │   │   ├── design
│   │   │   │   ├── actions.md
│   │   │   │   └── inference.md
│   │   │   ├── DEV_GUIDE.md
│   │   │   ├── how-kta-works.md
│   │   │   ├── JTBD.md
│   │   │   ├── knowledge-transfer-goals.md
│   │   │   ├── learning_assistance.md
│   │   │   ├── notable_claude_conversations
│   │   │   │   ├── clarifying_quad_modal_design.md
│   │   │   │   ├── CLAUDE_PROMPTS.md
│   │   │   │   ├── transfer_state.md
│   │   │   │   └── trying_the_context_agent.md
│   │   │   └── opportunities-of-knowledge-transfer.md
│   │   ├── knowledge-transfer-assistant.code-workspace
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_artifact_loading.py
│   │   │   ├── test_inspector.py
│   │   │   ├── test_share_manager.py
│   │   │   ├── test_share_storage.py
│   │   │   ├── test_share_tools.py
│   │   │   └── test_team_mode.py
│   │   └── uv.lock
│   ├── Makefile
│   ├── navigator-assistant
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── assets
│   │   │   │   ├── card_content.md
│   │   │   │   └── icon.svg
│   │   │   ├── chat.py
│   │   │   ├── config.py
│   │   │   ├── helpers.py
│   │   │   ├── response
│   │   │   │   ├── __init__.py
│   │   │   │   ├── completion_handler.py
│   │   │   │   ├── completion_requestor.py
│   │   │   │   ├── local_tool
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── add_assistant_to_conversation.py
│   │   │   │   │   ├── list_assistant_services.py
│   │   │   │   │   └── model.py
│   │   │   │   ├── models.py
│   │   │   │   ├── prompt.py
│   │   │   │   ├── request_builder.py
│   │   │   │   ├── response.py
│   │   │   │   ├── step_handler.py
│   │   │   │   └── utils
│   │   │   │       ├── __init__.py
│   │   │   │       ├── formatting_utils.py
│   │   │   │       ├── message_utils.py
│   │   │   │       ├── openai_utils.py
│   │   │   │       └── tools.py
│   │   │   ├── text_includes
│   │   │   │   ├── guardrails_prompt.md
│   │   │   │   ├── guidance_prompt.md
│   │   │   │   ├── instruction_prompt.md
│   │   │   │   ├── navigator_assistant_info.md
│   │   │   │   └── semantic_workbench_features.md
│   │   │   └── whiteboard
│   │   │       ├── __init__.py
│   │   │       ├── _inspector.py
│   │   │       └── _whiteboard.py
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── project-assistant
│   │   ├── .cspell
│   │   │   └── custom-dictionary-workspace.txt
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── agentic
│   │   │   │   ├── __init__.py
│   │   │   │   ├── act.py
│   │   │   │   ├── coordinator_next_action.py
│   │   │   │   ├── create_invitation.py
│   │   │   │   ├── detect_audience_and_takeaways.py
│   │   │   │   ├── detect_coordinator_actions.py
│   │   │   │   ├── detect_information_request_needs.py
│   │   │   │   ├── detect_knowledge_package_gaps.py
│   │   │   │   ├── focus.py
│   │   │   │   ├── respond.py
│   │   │   │   ├── team_welcome.py
│   │   │   │   └── update_digest.py
│   │   │   ├── assets
│   │   │   │   ├── icon-knowledge-transfer.svg
│   │   │   │   └── icon.svg
│   │   │   ├── assistant.py
│   │   │   ├── common.py
│   │   │   ├── config.py
│   │   │   ├── conversation_clients.py
│   │   │   ├── data.py
│   │   │   ├── domain
│   │   │   │   ├── __init__.py
│   │   │   │   ├── audience_manager.py
│   │   │   │   ├── conversation_preferences_manager.py
│   │   │   │   ├── information_request_manager.py
│   │   │   │   ├── knowledge_brief_manager.py
│   │   │   │   ├── knowledge_digest_manager.py
│   │   │   │   ├── learning_objectives_manager.py
│   │   │   │   ├── share_manager.py
│   │   │   │   ├── tasks_manager.py
│   │   │   │   └── transfer_manager.py
│   │   │   ├── errors.py
│   │   │   ├── files.py
│   │   │   ├── logging.py
│   │   │   ├── notifications.py
│   │   │   ├── prompt_utils.py
│   │   │   ├── storage.py
│   │   │   ├── string_utils.py
│   │   │   ├── text_includes
│   │   │   │   ├── actor_instructions.md
│   │   │   │   ├── assistant_info.md
│   │   │   │   ├── card_content.md
│   │   │   │   ├── coordinator_instructions copy.md
│   │   │   │   ├── coordinator_instructions.md
│   │   │   │   ├── create_invitation.md
│   │   │   │   ├── detect_audience.md
│   │   │   │   ├── detect_coordinator_actions.md
│   │   │   │   ├── detect_information_request_needs.md
│   │   │   │   ├── detect_knowledge_package_gaps.md
│   │   │   │   ├── focus.md
│   │   │   │   ├── knowledge_digest_instructions.txt
│   │   │   │   ├── team_instructions.txt
│   │   │   │   ├── to_do.md
│   │   │   │   ├── update_knowledge_brief.md
│   │   │   │   ├── update_knowledge_digest.md
│   │   │   │   └── welcome_message_generation.txt
│   │   │   ├── tools
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base.py
│   │   │   │   ├── conversation_preferences.py
│   │   │   │   ├── information_requests.py
│   │   │   │   ├── learning_objectives.py
│   │   │   │   ├── learning_outcomes.py
│   │   │   │   ├── progress_tracking.py
│   │   │   │   ├── share_setup.py
│   │   │   │   ├── system_reminders.py
│   │   │   │   ├── tasks.py
│   │   │   │   └── todo.py
│   │   │   ├── ui_tabs
│   │   │   │   ├── __init__.py
│   │   │   │   ├── brief.py
│   │   │   │   ├── common.py
│   │   │   │   ├── debug.py
│   │   │   │   ├── learning.py
│   │   │   │   └── sharing.py
│   │   │   └── utils.py
│   │   ├── CLAUDE.md
│   │   ├── docs
│   │   │   ├── design
│   │   │   │   ├── actions.md
│   │   │   │   ├── control_options.md
│   │   │   │   ├── design.md
│   │   │   │   ├── inference.md
│   │   │   │   └── PXL_20250814_190140267.jpg
│   │   │   ├── DEV_GUIDE.md
│   │   │   ├── how-kta-works.md
│   │   │   ├── JTBD.md
│   │   │   ├── knowledge-transfer-goals.md
│   │   │   ├── learning_assistance.md
│   │   │   ├── notable_claude_conversations
│   │   │   │   ├── clarifying_quad_modal_design.md
│   │   │   │   ├── CLAUDE_PROMPTS.md
│   │   │   │   ├── transfer_state.md
│   │   │   │   └── trying_the_context_agent.md
│   │   │   └── opportunities-of-knowledge-transfer.md
│   │   ├── knowledge-transfer-assistant.code-workspace
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_artifact_loading.py
│   │   │   ├── test_inspector.py
│   │   │   ├── test_share_manager.py
│   │   │   ├── test_share_storage.py
│   │   │   └── test_team_mode.py
│   │   └── uv.lock
│   ├── prospector-assistant
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── assistant
│   │   │   ├── __init__.py
│   │   │   ├── agents
│   │   │   │   ├── artifact_agent.py
│   │   │   │   ├── document
│   │   │   │   │   ├── config.py
│   │   │   │   │   ├── gc_draft_content_feedback_config.py
│   │   │   │   │   ├── gc_draft_outline_feedback_config.py
│   │   │   │   │   ├── guided_conversation.py
│   │   │   │   │   └── state.py
│   │   │   │   └── document_agent.py
│   │   │   ├── artifact_creation_extension
│   │   │   │   ├── __init__.py
│   │   │   │   ├── _llm.py
│   │   │   │   ├── config.py
│   │   │   │   ├── document.py
│   │   │   │   ├── extension.py
│   │   │   │   ├── store.py
│   │   │   │   ├── test
│   │   │   │   │   ├── conftest.py
│   │   │   │   │   ├── evaluation.py
│   │   │   │   │   ├── test_completion_with_tools.py
│   │   │   │   │   └── test_extension.py
│   │   │   │   └── tools.py
│   │   │   ├── chat.py
│   │   │   ├── config.py
│   │   │   ├── form_fill_extension
│   │   │   │   ├── __init__.py
│   │   │   │   ├── config.py
│   │   │   │   ├── extension.py
│   │   │   │   ├── inspector.py
│   │   │   │   ├── state.py
│   │   │   │   └── steps
│   │   │   │       ├── __init__.py
│   │   │   │       ├── _guided_conversation.py
│   │   │   │       ├── _llm.py
│   │   │   │       ├── acquire_form_step.py
│   │   │   │       ├── extract_form_fields_step.py
│   │   │   │       ├── fill_form_step.py
│   │   │   │       └── types.py
│   │   │   ├── helpers.py
│   │   │   ├── legacy.py
│   │   │   └── text_includes
│   │   │       ├── artifact_agent_enabled.md
│   │   │       ├── guardrails_prompt.txt
│   │   │       ├── guided_conversation_agent_enabled.md
│   │   │       └── skills_agent_enabled.md
│   │   ├── assistant.code-workspace
│   │   ├── gc_learnings
│   │   │   ├── gc_learnings.md
│   │   │   └── images
│   │   │       ├── gc_conversation_plan_fcn.png
│   │   │       ├── gc_conversation_plan_template.png
│   │   │       ├── gc_execute_plan_callstack.png
│   │   │       ├── gc_functions.png
│   │   │       ├── gc_generate_plan_callstack.png
│   │   │       ├── gc_get_resource_instructions.png
│   │   │       ├── gc_get_termination_instructions.png
│   │   │       ├── gc_kernel_arguments.png
│   │   │       ├── gc_plan_calls.png
│   │   │       ├── gc_termination_instructions.png
│   │   │       ├── sk_get_chat_message_contents.png
│   │   │       ├── sk_inner_get_chat_message_contents.png
│   │   │       ├── sk_send_request_prep.png
│   │   │       └── sk_send_request.png
│   │   ├── Makefile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   └── skill-assistant
│       ├── .env.example
│       ├── .vscode
│       │   ├── launch.json
│       │   └── settings.json
│       ├── assistant
│       │   ├── __init__.py
│       │   ├── config.py
│       │   ├── logging.py
│       │   ├── skill_assistant.py
│       │   ├── skill_engine_registry.py
│       │   ├── skill_event_mapper.py
│       │   ├── text_includes
│       │   │   └── guardrails_prompt.txt
│       │   └── workbench_helpers.py
│       ├── assistant.code-workspace
│       ├── Makefile
│       ├── pyproject.toml
│       ├── README.md
│       ├── tests
│       │   └── test_setup.py
│       └── uv.lock
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── docs
│   ├── .vscode
│   │   └── settings.json
│   ├── ASSISTANT_CONFIG.md
│   ├── ASSISTANT_DEVELOPMENT_GUIDE.md
│   ├── CUSTOM_APP_REGISTRATION.md
│   ├── HOSTED_ASSISTANT_WITH_LOCAL_MCP_SERVERS.md
│   ├── images
│   │   ├── architecture-animation.gif
│   │   ├── configure_assistant.png
│   │   ├── conversation_canvas_open.png
│   │   ├── conversation_duplicate.png
│   │   ├── conversation_export.png
│   │   ├── conversation_share_dialog.png
│   │   ├── conversation_share_link.png
│   │   ├── dashboard_configured_view.png
│   │   ├── dashboard_view.png
│   │   ├── license_agreement.png
│   │   ├── message_bar.png
│   │   ├── message_inspection.png
│   │   ├── message_link.png
│   │   ├── new_prospector_assistant_dialog.png
│   │   ├── open_conversation_canvas.png
│   │   ├── prospector_example.png
│   │   ├── readme1.png
│   │   ├── readme2.png
│   │   ├── readme3.png
│   │   ├── rewind.png
│   │   ├── signin_page.png
│   │   └── splash_screen.png
│   ├── LOCAL_ASSISTANT_WITH_REMOTE_WORKBENCH.md
│   ├── SETUP_DEV_ENVIRONMENT.md
│   └── WORKBENCH_APP.md
├── examples
│   ├── dotnet
│   │   ├── .editorconfig
│   │   ├── dotnet-01-echo-bot
│   │   │   ├── appsettings.json
│   │   │   ├── dotnet-01-echo-bot.csproj
│   │   │   ├── MyAgent.cs
│   │   │   ├── MyAgentConfig.cs
│   │   │   ├── MyWorkbenchConnector.cs
│   │   │   ├── Program.cs
│   │   │   └── README.md
│   │   ├── dotnet-02-message-types-demo
│   │   │   ├── appsettings.json
│   │   │   ├── ConnectorExtensions.cs
│   │   │   ├── docs
│   │   │   │   ├── abc.png
│   │   │   │   ├── code.png
│   │   │   │   ├── config.png
│   │   │   │   ├── echo.png
│   │   │   │   ├── markdown.png
│   │   │   │   ├── mermaid.png
│   │   │   │   ├── reverse.png
│   │   │   │   └── safety-check.png
│   │   │   ├── dotnet-02-message-types-demo.csproj
│   │   │   ├── MyAgent.cs
│   │   │   ├── MyAgentConfig.cs
│   │   │   ├── MyWorkbenchConnector.cs
│   │   │   ├── Program.cs
│   │   │   └── README.md
│   │   └── dotnet-03-simple-chatbot
│   │       ├── appsettings.json
│   │       ├── ConnectorExtensions.cs
│   │       ├── dotnet-03-simple-chatbot.csproj
│   │       ├── MyAgent.cs
│   │       ├── MyAgentConfig.cs
│   │       ├── MyWorkbenchConnector.cs
│   │       ├── Program.cs
│   │       └── README.md
│   ├── Makefile
│   └── python
│       ├── python-01-echo-bot
│       │   ├── .env.example
│       │   ├── .vscode
│       │   │   ├── launch.json
│       │   │   └── settings.json
│       │   ├── assistant
│       │   │   ├── __init__.py
│       │   │   ├── chat.py
│       │   │   └── config.py
│       │   ├── assistant.code-workspace
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       ├── python-02-simple-chatbot
│       │   ├── .env.example
│       │   ├── .vscode
│       │   │   ├── launch.json
│       │   │   └── settings.json
│       │   ├── assistant
│       │   │   ├── __init__.py
│       │   │   ├── chat.py
│       │   │   ├── config.py
│       │   │   └── text_includes
│       │   │       └── guardrails_prompt.txt
│       │   ├── assistant.code-workspace
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       └── python-03-multimodel-chatbot
│           ├── .env.example
│           ├── .vscode
│           │   ├── launch.json
│           │   └── settings.json
│           ├── assistant
│           │   ├── __init__.py
│           │   ├── chat.py
│           │   ├── config.py
│           │   ├── model_adapters.py
│           │   └── text_includes
│           │       └── guardrails_prompt.txt
│           ├── assistant.code-workspace
│           ├── Makefile
│           ├── pyproject.toml
│           ├── README.md
│           └── uv.lock
├── KNOWN_ISSUES.md
├── libraries
│   ├── dotnet
│   │   ├── .editorconfig
│   │   ├── pack.sh
│   │   ├── README.md
│   │   ├── SemanticWorkbench.sln
│   │   ├── SemanticWorkbench.sln.DotSettings
│   │   └── WorkbenchConnector
│   │       ├── AgentBase.cs
│   │       ├── AgentConfig
│   │       │   ├── AgentConfigBase.cs
│   │       │   ├── AgentConfigPropertyAttribute.cs
│   │       │   └── ConfigUtils.cs
│   │       ├── Constants.cs
│   │       ├── IAgentBase.cs
│   │       ├── icon.png
│   │       ├── Models
│   │       │   ├── Command.cs
│   │       │   ├── Conversation.cs
│   │       │   ├── ConversationEvent.cs
│   │       │   ├── DebugInfo.cs
│   │       │   ├── Insight.cs
│   │       │   ├── Message.cs
│   │       │   ├── MessageMetadata.cs
│   │       │   ├── Participant.cs
│   │       │   ├── Sender.cs
│   │       │   └── ServiceInfo.cs
│   │       ├── Storage
│   │       │   ├── AgentInfo.cs
│   │       │   ├── AgentServiceStorage.cs
│   │       │   └── IAgentServiceStorage.cs
│   │       ├── StringLoggingExtensions.cs
│   │       ├── Webservice.cs
│   │       ├── WorkbenchConfig.cs
│   │       ├── WorkbenchConnector.cs
│   │       └── WorkbenchConnector.csproj
│   ├── Makefile
│   └── python
│       ├── anthropic-client
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── anthropic_client
│       │   │   ├── __init__.py
│       │   │   ├── client.py
│       │   │   ├── config.py
│       │   │   └── messages.py
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       ├── assistant-data-gen
│       │   ├── .vscode
│       │   │   ├── launch.json
│       │   │   └── settings.json
│       │   ├── assistant_data_gen
│       │   │   ├── __init__.py
│       │   │   ├── assistant_api.py
│       │   │   ├── config.py
│       │   │   ├── gce
│       │   │   │   ├── __init__.py
│       │   │   │   ├── gce_agent.py
│       │   │   │   └── prompts.py
│       │   │   └── pydantic_ai_utils.py
│       │   ├── configs
│       │   │   └── document_assistant_example_config.yaml
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   ├── scripts
│       │   │   ├── gce_simulation.py
│       │   │   └── generate_scenario.py
│       │   └── uv.lock
│       ├── assistant-drive
│       │   ├── .gitignore
│       │   ├── .vscode
│       │   │   ├── extensions.json
│       │   │   └── settings.json
│       │   ├── assistant_drive
│       │   │   ├── __init__.py
│       │   │   ├── drive.py
│       │   │   └── tests
│       │   │       └── test_basic.py
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── pytest.ini
│       │   ├── README.md
│       │   ├── usage.ipynb
│       │   └── uv.lock
│       ├── assistant-extensions
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── assistant_extensions
│       │   │   ├── __init__.py
│       │   │   ├── ai_clients
│       │   │   │   └── config.py
│       │   │   ├── artifacts
│       │   │   │   ├── __init__.py
│       │   │   │   ├── _artifacts.py
│       │   │   │   ├── _inspector.py
│       │   │   │   └── _model.py
│       │   │   ├── attachments
│       │   │   │   ├── __init__.py
│       │   │   │   ├── _attachments.py
│       │   │   │   ├── _convert.py
│       │   │   │   ├── _model.py
│       │   │   │   ├── _shared.py
│       │   │   │   └── _summarizer.py
│       │   │   ├── chat_context_toolkit
│       │   │   │   ├── __init__.py
│       │   │   │   ├── _config.py
│       │   │   │   ├── archive
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── _archive.py
│       │   │   │   │   └── _summarizer.py
│       │   │   │   ├── message_history
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── _history.py
│       │   │   │   │   └── _message.py
│       │   │   │   └── virtual_filesystem
│       │   │   │       ├── __init__.py
│       │   │   │       ├── _archive_file_source.py
│       │   │   │       └── _attachments_file_source.py
│       │   │   ├── dashboard_card
│       │   │   │   ├── __init__.py
│       │   │   │   └── _dashboard_card.py
│       │   │   ├── document_editor
│       │   │   │   ├── __init__.py
│       │   │   │   ├── _extension.py
│       │   │   │   ├── _inspector.py
│       │   │   │   └── _model.py
│       │   │   ├── mcp
│       │   │   │   ├── __init__.py
│       │   │   │   ├── _assistant_file_resource_handler.py
│       │   │   │   ├── _client_utils.py
│       │   │   │   ├── _devtunnel.py
│       │   │   │   ├── _model.py
│       │   │   │   ├── _openai_utils.py
│       │   │   │   ├── _sampling_handler.py
│       │   │   │   ├── _tool_utils.py
│       │   │   │   └── _workbench_file_resource_handler.py
│       │   │   ├── navigator
│       │   │   │   ├── __init__.py
│       │   │   │   └── _navigator.py
│       │   │   └── workflows
│       │   │       ├── __init__.py
│       │   │       ├── _model.py
│       │   │       ├── _workflows.py
│       │   │       └── runners
│       │   │           └── _user_proxy.py
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   ├── test
│       │   │   └── attachments
│       │   │       └── test_attachments.py
│       │   └── uv.lock
│       ├── chat-context-toolkit
│       │   ├── .claude
│       │   │   └── settings.local.json
│       │   ├── .env.sample
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── assets
│       │   │   ├── archive_v1.png
│       │   │   ├── history_v1.png
│       │   │   └── vfs_v1.png
│       │   ├── chat_context_toolkit
│       │   │   ├── __init__.py
│       │   │   ├── archive
│       │   │   │   ├── __init__.py
│       │   │   │   ├── _archive_reader.py
│       │   │   │   ├── _archive_task_queue.py
│       │   │   │   ├── _state.py
│       │   │   │   ├── _types.py
│       │   │   │   └── summarization
│       │   │   │       ├── __init__.py
│       │   │   │       └── _summarizer.py
│       │   │   ├── history
│       │   │   │   ├── __init__.py
│       │   │   │   ├── _budget.py
│       │   │   │   ├── _decorators.py
│       │   │   │   ├── _history.py
│       │   │   │   ├── _prioritize.py
│       │   │   │   ├── _types.py
│       │   │   │   └── tool_abbreviations
│       │   │   │       ├── __init__.py
│       │   │   │       └── _tool_abbreviations.py
│       │   │   └── virtual_filesystem
│       │   │       ├── __init__.py
│       │   │       ├── _types.py
│       │   │       ├── _virtual_filesystem.py
│       │   │       ├── README.md
│       │   │       └── tools
│       │   │           ├── __init__.py
│       │   │           ├── _ls_tool.py
│       │   │           ├── _tools.py
│       │   │           └── _view_tool.py
│       │   ├── CLAUDE.md
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   ├── test
│       │   │   ├── archive
│       │   │   │   └── test_archive_reader.py
│       │   │   ├── history
│       │   │   │   ├── test_abbreviate_messages.py
│       │   │   │   ├── test_history.py
│       │   │   │   ├── test_pair_and_order_tool_messages.py
│       │   │   │   ├── test_prioritize.py
│       │   │   │   └── test_truncate_messages.py
│       │   │   └── virtual_filesystem
│       │   │       ├── test_virtual_filesystem.py
│       │   │       └── tools
│       │   │           ├── test_ls_tool.py
│       │   │           ├── test_tools.py
│       │   │           └── test_view_tool.py
│       │   └── uv.lock
│       ├── content-safety
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── content_safety
│       │   │   ├── __init__.py
│       │   │   ├── evaluators
│       │   │   │   ├── __init__.py
│       │   │   │   ├── azure_content_safety
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── config.py
│       │   │   │   │   └── evaluator.py
│       │   │   │   ├── config.py
│       │   │   │   ├── evaluator.py
│       │   │   │   └── openai_moderations
│       │   │   │       ├── __init__.py
│       │   │   │       ├── config.py
│       │   │   │       └── evaluator.py
│       │   │   └── README.md
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       ├── events
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── events
│       │   │   ├── __init__.py
│       │   │   └── events.py
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       ├── guided-conversation
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── guided_conversation
│       │   │   ├── __init__.py
│       │   │   ├── functions
│       │   │   │   ├── __init__.py
│       │   │   │   ├── conversation_plan.py
│       │   │   │   ├── execution.py
│       │   │   │   └── final_update_plan.py
│       │   │   ├── guided_conversation_agent.py
│       │   │   ├── plugins
│       │   │   │   ├── __init__.py
│       │   │   │   ├── agenda.py
│       │   │   │   └── artifact.py
│       │   │   └── utils
│       │   │       ├── __init__.py
│       │   │       ├── base_model_llm.py
│       │   │       ├── conversation_helpers.py
│       │   │       ├── openai_tool_calling.py
│       │   │       ├── plugin_helpers.py
│       │   │       └── resources.py
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       ├── llm-client
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── llm_client
│       │   │   ├── __init__.py
│       │   │   └── model.py
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       ├── Makefile
│       ├── mcp-extensions
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── Makefile
│       │   ├── mcp_extensions
│       │   │   ├── __init__.py
│       │   │   ├── _client_session.py
│       │   │   ├── _model.py
│       │   │   ├── _sampling.py
│       │   │   ├── _server_extensions.py
│       │   │   ├── _tool_utils.py
│       │   │   ├── llm
│       │   │   │   ├── __init__.py
│       │   │   │   ├── chat_completion.py
│       │   │   │   ├── helpers.py
│       │   │   │   ├── llm_types.py
│       │   │   │   ├── mcp_chat_completion.py
│       │   │   │   └── openai_chat_completion.py
│       │   │   └── server
│       │   │       ├── __init__.py
│       │   │       └── storage.py
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   ├── tests
│       │   │   └── test_tool_utils.py
│       │   └── uv.lock
│       ├── mcp-tunnel
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── Makefile
│       │   ├── mcp_tunnel
│       │   │   ├── __init__.py
│       │   │   ├── _devtunnel.py
│       │   │   ├── _dir.py
│       │   │   └── _main.py
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   └── uv.lock
│       ├── openai-client
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── Makefile
│       │   ├── openai_client
│       │   │   ├── __init__.py
│       │   │   ├── chat_driver
│       │   │   │   ├── __init__.py
│       │   │   │   ├── chat_driver.ipynb
│       │   │   │   ├── chat_driver.py
│       │   │   │   ├── message_history_providers
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── in_memory_message_history_provider.py
│       │   │   │   │   ├── local_message_history_provider.py
│       │   │   │   │   ├── message_history_provider.py
│       │   │   │   │   └── tests
│       │   │   │   │       └── formatted_instructions_test.py
│       │   │   │   └── README.md
│       │   │   ├── client.py
│       │   │   ├── completion.py
│       │   │   ├── config.py
│       │   │   ├── errors.py
│       │   │   ├── logging.py
│       │   │   ├── messages.py
│       │   │   ├── tokens.py
│       │   │   └── tools.py
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   ├── tests
│       │   │   ├── test_command_parsing.py
│       │   │   ├── test_formatted_messages.py
│       │   │   ├── test_messages.py
│       │   │   └── test_tokens.py
│       │   └── uv.lock
│       ├── semantic-workbench-api-model
│       │   ├── .vscode
│       │   │   └── settings.json
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   ├── semantic_workbench_api_model
│       │   │   ├── __init__.py
│       │   │   ├── assistant_model.py
│       │   │   ├── assistant_service_client.py
│       │   │   ├── workbench_model.py
│       │   │   └── workbench_service_client.py
│       │   └── uv.lock
│       ├── semantic-workbench-assistant
│       │   ├── .vscode
│       │   │   ├── launch.json
│       │   │   └── settings.json
│       │   ├── Makefile
│       │   ├── pyproject.toml
│       │   ├── README.md
│       │   ├── semantic_workbench_assistant
│       │   │   ├── __init__.py
│       │   │   ├── assistant_app
│       │   │   │   ├── __init__.py
│       │   │   │   ├── assistant.py
│       │   │   │   ├── config.py
│       │   │   │   ├── content_safety.py
│       │   │   │   ├── context.py
│       │   │   │   ├── error.py
│       │   │   │   ├── export_import.py
│       │   │   │   ├── protocol.py
│       │   │   │   └── service.py
│       │   │   ├── assistant_service.py
│       │   │   ├── auth.py
│       │   │   ├── canonical.py
│       │   │   ├── command.py
│       │   │   ├── config.py
│       │   │   ├── logging_config.py
│       │   │   ├── settings.py
│       │   │   ├── start.py
│       │   │   └── storage.py
│       │   ├── tests
│       │   │   ├── conftest.py
│       │   │   ├── test_assistant_app.py
│       │   │   ├── test_canonical.py
│       │   │   ├── test_config.py
│       │   │   └── test_storage.py
│       │   └── uv.lock
│       └── skills
│           ├── .vscode
│           │   └── settings.json
│           ├── Makefile
│           ├── README.md
│           └── skill-library
│               ├── .vscode
│               │   └── settings.json
│               ├── docs
│               │   └── vs-recipe-tool.md
│               ├── Makefile
│               ├── pyproject.toml
│               ├── README.md
│               ├── skill_library
│               │   ├── __init__.py
│               │   ├── chat_driver_helpers.py
│               │   ├── cli
│               │   │   ├── azure_openai.py
│               │   │   ├── conversation_history.py
│               │   │   ├── README.md
│               │   │   ├── run_routine.py
│               │   │   ├── settings.py
│               │   │   └── skill_logger.py
│               │   ├── engine.py
│               │   ├── llm_info.txt
│               │   ├── logging.py
│               │   ├── README.md
│               │   ├── routine_stack.py
│               │   ├── skill.py
│               │   ├── skills
│               │   │   ├── common
│               │   │   │   ├── __init__.py
│               │   │   │   ├── common_skill.py
│               │   │   │   └── routines
│               │   │   │       ├── bing_search.py
│               │   │   │       ├── consolidate.py
│               │   │   │       ├── echo.py
│               │   │   │       ├── gather_context.py
│               │   │   │       ├── get_content_from_url.py
│               │   │   │       ├── gpt_complete.py
│               │   │   │       ├── select_user_intent.py
│               │   │   │       └── summarize.py
│               │   │   ├── eval
│               │   │   │   ├── __init__.py
│               │   │   │   ├── eval_skill.py
│               │   │   │   └── routines
│               │   │   │       └── eval.py
│               │   │   ├── fabric
│               │   │   │   ├── __init__.py
│               │   │   │   ├── fabric_skill.py
│               │   │   │   ├── patterns
│               │   │   │   │   ├── agility_story
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── ai
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_answers
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_candidates
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_cfp_submission
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_claims
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_comments
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_debate
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_email_headers
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_incident
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_interviewer_techniques
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_logs
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_malware
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_military_strategy
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_mistakes
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_paper
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_patent
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_personality
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_presentation
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_product_feedback
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_proposition
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_prose
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_prose_json
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_prose_pinker
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_risk
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_sales_call
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_spiritual_text
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_tech_impact
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_threat_report
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── analyze_threat_report_cmds
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── analyze_threat_report_trends
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── answer_interview_question
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── ask_secure_by_design_questions
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── ask_uncle_duke
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── capture_thinkers_work
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── check_agreement
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── clean_text
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── coding_master
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── compare_and_contrast
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── convert_to_markdown
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_5_sentence_summary
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_academic_paper
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_ai_jobs_analysis
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_aphorisms
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_art_prompt
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_better_frame
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_coding_project
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_command
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_cyber_summary
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_design_document
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_diy
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_formal_email
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_git_diff_commit
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_graph_from_input
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_hormozi_offer
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_idea_compass
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_investigation_visualization
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_keynote
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_logo
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_markmap_visualization
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_mermaid_visualization
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_mermaid_visualization_for_github
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_micro_summary
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_network_threat_landscape
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_newsletter_entry
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_npc
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_pattern
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_prd
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_prediction_block
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_quiz
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_reading_plan
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_recursive_outline
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_report_finding
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_rpg_summary
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_security_update
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_show_intro
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_sigma_rules
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_story_explanation
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_stride_threat_model
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_summary
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_tags
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_threat_scenarios
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_ttrc_graph
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_ttrc_narrative
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_upgrade_pack
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_user_story
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── create_video_chapters
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── create_visualization
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── dialog_with_socrates
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── enrich_blog_post
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── explain_code
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── explain_docs
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── explain_math
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── explain_project
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── explain_terms
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── export_data_as_csv
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_algorithm_update_recommendations
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── extract_article_wisdom
│               │   │   │   │   │   ├── dmiessler
│               │   │   │   │   │   │   └── extract_wisdom-1.0.0
│               │   │   │   │   │   │       ├── system.md
│               │   │   │   │   │   │       └── user.md
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── extract_book_ideas
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_book_recommendations
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_business_ideas
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_controversial_ideas
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_core_message
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_ctf_writeup
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_domains
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_extraordinary_claims
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_ideas
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_insights
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_insights_dm
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_instructions
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_jokes
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_latest_video
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_main_idea
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_most_redeeming_thing
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_patterns
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_poc
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── extract_predictions
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_primary_problem
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_primary_solution
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_product_features
│               │   │   │   │   │   ├── dmiessler
│               │   │   │   │   │   │   └── extract_wisdom-1.0.0
│               │   │   │   │   │   │       ├── system.md
│               │   │   │   │   │   │       └── user.md
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_questions
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_recipe
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_recommendations
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── extract_references
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── extract_skills
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_song_meaning
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_sponsors
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_videoid
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── extract_wisdom
│               │   │   │   │   │   ├── dmiessler
│               │   │   │   │   │   │   └── extract_wisdom-1.0.0
│               │   │   │   │   │   │       ├── system.md
│               │   │   │   │   │   │       └── user.md
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_wisdom_agents
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_wisdom_dm
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── extract_wisdom_nometa
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── find_hidden_message
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── find_logical_fallacies
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── get_wow_per_minute
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── get_youtube_rss
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── humanize
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── identify_dsrp_distinctions
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── identify_dsrp_perspectives
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── identify_dsrp_relationships
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── identify_dsrp_systems
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── identify_job_stories
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── improve_academic_writing
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── improve_prompt
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── improve_report_finding
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── improve_writing
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── judge_output
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── label_and_rate
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── loaded
│               │   │   │   │   ├── md_callout
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── official_pattern_template
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── pattern_explanations.md
│               │   │   │   │   ├── prepare_7s_strategy
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── provide_guidance
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── rate_ai_response
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── rate_ai_result
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── rate_content
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── rate_value
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── raw_query
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── raycast
│               │   │   │   │   │   ├── capture_thinkers_work
│               │   │   │   │   │   ├── create_story_explanation
│               │   │   │   │   │   ├── extract_primary_problem
│               │   │   │   │   │   ├── extract_wisdom
│               │   │   │   │   │   └── yt
│               │   │   │   │   ├── recommend_artists
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── recommend_pipeline_upgrades
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── recommend_talkpanel_topics
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── refine_design_document
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── review_design
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── sanitize_broken_html_to_markdown
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── show_fabric_options_markmap
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── solve_with_cot
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── stringify
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── suggest_pattern
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── summarize
│               │   │   │   │   │   ├── dmiessler
│               │   │   │   │   │   │   └── summarize
│               │   │   │   │   │   │       ├── system.md
│               │   │   │   │   │   │       └── user.md
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── summarize_debate
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── summarize_git_changes
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── summarize_git_diff
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── summarize_lecture
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── summarize_legislation
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── summarize_meeting
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── summarize_micro
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── summarize_newsletter
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── summarize_paper
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── summarize_prompt
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── summarize_pull-requests
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── summarize_rpg_session
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_analyze_challenge_handling
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_check_metrics
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_create_h3_career
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_create_opening_sentences
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_describe_life_outlook
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_extract_intro_sentences
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_extract_panel_topics
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_find_blindspots
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_find_negative_thinking
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_find_neglected_goals
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_give_encouragement
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_red_team_thinking
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_threat_model_plans
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_visualize_mission_goals_projects
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── t_year_in_review
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── to_flashcards
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── transcribe_minutes
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── translate
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── tweet
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── write_essay
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── write_hackerone_report
│               │   │   │   │   │   ├── README.md
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── write_latex
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── write_micro_essay
│               │   │   │   │   │   └── system.md
│               │   │   │   │   ├── write_nuclei_template_rule
│               │   │   │   │   │   ├── system.md
│               │   │   │   │   │   └── user.md
│               │   │   │   │   ├── write_pull-request
│               │   │   │   │   │   └── system.md
│               │   │   │   │   └── write_semgrep_rule
│               │   │   │   │       ├── system.md
│               │   │   │   │       └── user.md
│               │   │   │   └── routines
│               │   │   │       ├── list.py
│               │   │   │       ├── run.py
│               │   │   │       └── show.py
│               │   │   ├── guided_conversation
│               │   │   │   ├── __init__.py
│               │   │   │   ├── agenda.py
│               │   │   │   ├── artifact_helpers.py
│               │   │   │   ├── chat_completions
│               │   │   │   │   ├── fix_agenda_error.py
│               │   │   │   │   ├── fix_artifact_error.py
│               │   │   │   │   ├── generate_agenda.py
│               │   │   │   │   ├── generate_artifact_updates.py
│               │   │   │   │   ├── generate_final_artifact.py
│               │   │   │   │   └── generate_message.py
│               │   │   │   ├── conversation_guides
│               │   │   │   │   ├── __init__.py
│               │   │   │   │   ├── acrostic_poem.py
│               │   │   │   │   ├── er_triage.py
│               │   │   │   │   ├── interview.py
│               │   │   │   │   └── patient_intake.py
│               │   │   │   ├── guide.py
│               │   │   │   ├── guided_conversation_skill.py
│               │   │   │   ├── logging.py
│               │   │   │   ├── message.py
│               │   │   │   ├── resources.py
│               │   │   │   ├── routines
│               │   │   │   │   └── guided_conversation.py
│               │   │   │   └── tests
│               │   │   │       ├── conftest.py
│               │   │   │       ├── test_artifact_helpers.py
│               │   │   │       ├── test_generate_agenda.py
│               │   │   │       ├── test_generate_artifact_updates.py
│               │   │   │       ├── test_generate_final_artifact.py
│               │   │   │       └── test_resource.py
│               │   │   ├── meta
│               │   │   │   ├── __init__.py
│               │   │   │   ├── meta_skill.py
│               │   │   │   ├── README.md
│               │   │   │   └── routines
│               │   │   │       └── generate_routine.py
│               │   │   ├── posix
│               │   │   │   ├── __init__.py
│               │   │   │   ├── posix_skill.py
│               │   │   │   ├── routines
│               │   │   │   │   ├── append_file.py
│               │   │   │   │   ├── cd.py
│               │   │   │   │   ├── ls.py
│               │   │   │   │   ├── make_home_dir.py
│               │   │   │   │   ├── mkdir.py
│               │   │   │   │   ├── mv.py
│               │   │   │   │   ├── pwd.py
│               │   │   │   │   ├── read_file.py
│               │   │   │   │   ├── rm.py
│               │   │   │   │   ├── touch.py
│               │   │   │   │   └── write_file.py
│               │   │   │   └── sandbox_shell.py
│               │   │   ├── README.md
│               │   │   ├── research
│               │   │   │   ├── __init__.py
│               │   │   │   ├── README.md
│               │   │   │   ├── research_skill.py
│               │   │   │   └── routines
│               │   │   │       ├── answer_question_about_content.py
│               │   │   │       ├── evaluate_answer.py
│               │   │   │       ├── generate_research_plan.py
│               │   │   │       ├── generate_search_query.py
│               │   │   │       ├── update_research_plan.py
│               │   │   │       ├── web_research.py
│               │   │   │       └── web_search.py
│               │   │   ├── research2
│               │   │   │   ├── __init__.py
│               │   │   │   ├── README.md
│               │   │   │   ├── research_skill.py
│               │   │   │   └── routines
│               │   │   │       ├── facts.py
│               │   │   │       ├── make_final_report.py
│               │   │   │       ├── research.py
│               │   │   │       ├── search_plan.py
│               │   │   │       ├── search.py
│               │   │   │       └── visit_pages.py
│               │   │   └── web_research
│               │   │       ├── __init__.py
│               │   │       ├── README.md
│               │   │       ├── research_skill.py
│               │   │       └── routines
│               │   │           ├── facts.py
│               │   │           ├── make_final_report.py
│               │   │           ├── research.py
│               │   │           ├── search_plan.py
│               │   │           ├── search.py
│               │   │           └── visit_pages.py
│               │   ├── tests
│               │   │   ├── test_common_skill.py
│               │   │   ├── test_integration.py
│               │   │   ├── test_routine_stack.py
│               │   │   ├── tst_skill
│               │   │   │   ├── __init__.py
│               │   │   │   └── routines
│               │   │   │       ├── __init__.py
│               │   │   │       └── a_routine.py
│               │   │   └── utilities
│               │   │       ├── test_find_template_vars.py
│               │   │       ├── test_make_arg_set.py
│               │   │       ├── test_paramspec.py
│               │   │       ├── test_parse_command_string.py
│               │   │       └── test_to_string.py
│               │   ├── types.py
│               │   ├── usage.py
│               │   └── utilities.py
│               └── uv.lock
├── LICENSE
├── Makefile
├── mcp-servers
│   ├── ai-assist-content
│   │   ├── .vscode
│   │   │   └── settings.json
│   │   ├── mcp-example-brave-search.md
│   │   ├── mcp-fastmcp-typescript-README.md
│   │   ├── mcp-llms-full.txt
│   │   ├── mcp-metadata-tips.md
│   │   ├── mcp-python-sdk-README.md
│   │   ├── mcp-typescript-sdk-README.md
│   │   ├── pydanticai-documentation.md
│   │   ├── pydanticai-example-question-graph.md
│   │   ├── pydanticai-example-weather.md
│   │   ├── pydanticai-tutorial.md
│   │   └── README.md
│   ├── Makefile
│   ├── mcp-server-bing-search
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server_bing_search
│   │   │   ├── __init__.py
│   │   │   ├── config.py
│   │   │   ├── prompts
│   │   │   │   ├── __init__.py
│   │   │   │   ├── clean_website.py
│   │   │   │   └── filter_links.py
│   │   │   ├── server.py
│   │   │   ├── start.py
│   │   │   ├── tools.py
│   │   │   ├── types.py
│   │   │   ├── utils.py
│   │   │   └── web
│   │   │       ├── __init__.py
│   │   │       ├── get_content.py
│   │   │       ├── llm_processing.py
│   │   │       ├── process_website.py
│   │   │       └── search_bing.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   └── test_tools.py
│   │   └── uv.lock
│   ├── mcp-server-bundle
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server_bundle
│   │   │   ├── __init__.py
│   │   │   └── main.py
│   │   ├── pyinstaller.spec
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── mcp-server-filesystem
│   │   ├── .env.example
│   │   ├── .github
│   │   │   └── workflows
│   │   │       └── ci.yml
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server_filesystem
│   │   │   ├── __init__.py
│   │   │   ├── config.py
│   │   │   ├── server.py
│   │   │   └── start.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   └── test_filesystem.py
│   │   └── uv.lock
│   ├── mcp-server-filesystem-edit
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── data
│   │   │   ├── attachments
│   │   │   │   ├── Daily Game Ideas.txt
│   │   │   │   ├── Frontend Framework Proposal.txt
│   │   │   │   ├── ReDoodle.txt
│   │   │   │   └── Research Template.tex
│   │   │   ├── test_cases.yaml
│   │   │   └── transcripts
│   │   │       ├── transcript_research_simple.md
│   │   │       ├── transcript_Startup_Idea_1_202503031513.md
│   │   │       ├── transcript_Startup_Idea_2_202503031659.md
│   │   │       └── transcript_Web_Frontends_202502281551.md
│   │   ├── Makefile
│   │   ├── mcp_server_filesystem_edit
│   │   │   ├── __init__.py
│   │   │   ├── app_handling
│   │   │   │   ├── __init__.py
│   │   │   │   ├── excel.py
│   │   │   │   ├── miktex.py
│   │   │   │   ├── office_common.py
│   │   │   │   ├── powerpoint.py
│   │   │   │   └── word.py
│   │   │   ├── config.py
│   │   │   ├── evals
│   │   │   │   ├── __init__.py
│   │   │   │   ├── common.py
│   │   │   │   ├── run_comments.py
│   │   │   │   ├── run_edit.py
│   │   │   │   └── run_ppt_edit.py
│   │   │   ├── prompts
│   │   │   │   ├── __init__.py
│   │   │   │   ├── add_comments.py
│   │   │   │   ├── analyze_comments.py
│   │   │   │   ├── latex_edit.py
│   │   │   │   ├── markdown_draft.py
│   │   │   │   ├── markdown_edit.py
│   │   │   │   └── powerpoint_edit.py
│   │   │   ├── server.py
│   │   │   ├── start.py
│   │   │   ├── tools
│   │   │   │   ├── __init__.py
│   │   │   │   ├── add_comments.py
│   │   │   │   ├── edit_adapters
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── common.py
│   │   │   │   │   ├── latex.py
│   │   │   │   │   └── markdown.py
│   │   │   │   ├── edit.py
│   │   │   │   └── helpers.py
│   │   │   └── types.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── app_handling
│   │   │   │   ├── test_excel.py
│   │   │   │   ├── test_miktext.py
│   │   │   │   ├── test_office_common.py
│   │   │   │   ├── test_powerpoint.py
│   │   │   │   └── test_word.py
│   │   │   ├── conftest.py
│   │   │   └── tools
│   │   │       └── edit_adapters
│   │   │           ├── test_latex.py
│   │   │           └── test_markdown.py
│   │   └── uv.lock
│   ├── mcp-server-fusion
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── AddInIcon.svg
│   │   ├── config.py
│   │   ├── FusionMCPServerAddIn.manifest
│   │   ├── FusionMCPServerAddIn.py
│   │   ├── mcp_server_fusion
│   │   │   ├── __init__.py
│   │   │   ├── fusion_mcp_server.py
│   │   │   ├── fusion_utils
│   │   │   │   ├── __init__.py
│   │   │   │   ├── event_utils.py
│   │   │   │   ├── general_utils.py
│   │   │   │   └── tool_utils.py
│   │   │   ├── mcp_tools
│   │   │   │   ├── __init__.py
│   │   │   │   ├── fusion_3d_operation.py
│   │   │   │   ├── fusion_geometry.py
│   │   │   │   ├── fusion_pattern.py
│   │   │   │   └── fusion_sketch.py
│   │   │   └── vendor
│   │   │       └── README.md
│   │   ├── README.md
│   │   └── requirements.txt
│   ├── mcp-server-giphy
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server
│   │   │   ├── __init__.py
│   │   │   ├── config.py
│   │   │   ├── giphy_search.py
│   │   │   ├── sampling.py
│   │   │   ├── server.py
│   │   │   ├── start.py
│   │   │   └── utils.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── mcp-server-memory-user-bio
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server_memory_user_bio
│   │   │   ├── __init__.py
│   │   │   ├── config.py
│   │   │   ├── server.py
│   │   │   └── start.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── mcp-server-memory-whiteboard
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server_memory_whiteboard
│   │   │   ├── __init__.py
│   │   │   ├── config.py
│   │   │   ├── server.py
│   │   │   └── start.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── mcp-server-office
│   │   ├── .env.example
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── build.sh
│   │   ├── data
│   │   │   ├── attachments
│   │   │   │   ├── Daily Game Ideas.txt
│   │   │   │   ├── Frontend Framework Proposal.txt
│   │   │   │   └── ReDoodle.txt
│   │   │   └── word
│   │   │       ├── test_cases.yaml
│   │   │       └── transcripts
│   │   │           ├── transcript_Startup_Idea_1_202503031513.md
│   │   │           ├── transcript_Startup_Idea_2_202503031659.md
│   │   │           └── transcript_Web_Frontends_202502281551.md
│   │   ├── Makefile
│   │   ├── mcp_server
│   │   │   ├── __init__.py
│   │   │   ├── app_interaction
│   │   │   │   ├── __init__.py
│   │   │   │   ├── excel_editor.py
│   │   │   │   ├── powerpoint_editor.py
│   │   │   │   └── word_editor.py
│   │   │   ├── config.py
│   │   │   ├── constants.py
│   │   │   ├── evals
│   │   │   │   ├── __init__.py
│   │   │   │   ├── common.py
│   │   │   │   ├── run_comment_analysis.py
│   │   │   │   ├── run_feedback.py
│   │   │   │   └── run_markdown_edit.py
│   │   │   ├── helpers.py
│   │   │   ├── markdown_edit
│   │   │   │   ├── __init__.py
│   │   │   │   ├── comment_analysis.py
│   │   │   │   ├── feedback_step.py
│   │   │   │   ├── markdown_edit.py
│   │   │   │   └── utils.py
│   │   │   ├── prompts
│   │   │   │   ├── __init__.py
│   │   │   │   ├── comment_analysis.py
│   │   │   │   ├── feedback.py
│   │   │   │   ├── markdown_draft.py
│   │   │   │   └── markdown_edit.py
│   │   │   ├── server.py
│   │   │   ├── start.py
│   │   │   └── types.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   └── test_word_editor.py
│   │   └── uv.lock
│   ├── mcp-server-open-deep-research
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server
│   │   │   ├── __init__.py
│   │   │   ├── config.py
│   │   │   ├── libs
│   │   │   │   └── open_deep_research
│   │   │   │       ├── cookies.py
│   │   │   │       ├── mdconvert.py
│   │   │   │       ├── run_agents.py
│   │   │   │       ├── text_inspector_tool.py
│   │   │   │       ├── text_web_browser.py
│   │   │   │       └── visual_qa.py
│   │   │   ├── open_deep_research.py
│   │   │   ├── server.py
│   │   │   └── start.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   └── uv.lock
│   ├── mcp-server-open-deep-research-clone
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── .vscode
│   │   │   ├── launch.json
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── mcp_server_open_deep_research_clone
│   │   │   ├── __init__.py
│   │   │   ├── azure_openai.py
│   │   │   ├── config.py
│   │   │   ├── logging.py
│   │   │   ├── sampling.py
│   │   │   ├── server.py
│   │   │   ├── start.py
│   │   │   ├── utils.py
│   │   │   └── web_research.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── test
│   │   │   └── test_open_deep_research_clone.py
│   │   └── uv.lock
│   ├── mcp-server-template
│   │   ├── .taplo.toml
│   │   ├── .vscode
│   │   │   └── settings.json
│   │   ├── copier.yml
│   │   ├── README.md
│   │   └── template
│   │       └── {{ project_slug }}
│   │           ├── .env.example.jinja
│   │           ├── .gitignore
│   │           ├── .vscode
│   │           │   ├── launch.json.jinja
│   │           │   └── settings.json
│   │           ├── {{ module_name }}
│   │           │   ├── __init__.py
│   │           │   ├── config.py.jinja
│   │           │   ├── server.py.jinja
│   │           │   └── start.py.jinja
│   │           ├── Makefile.jinja
│   │           ├── pyproject.toml.jinja
│   │           └── README.md.jinja
│   ├── mcp-server-vscode
│   │   ├── .eslintrc.cjs
│   │   ├── .gitignore
│   │   ├── .npmrc
│   │   ├── .vscode
│   │   │   ├── extensions.json
│   │   │   ├── launch.json
│   │   │   ├── settings.json
│   │   │   └── tasks.json
│   │   ├── .vscode-test.mjs
│   │   ├── .vscodeignore
│   │   ├── ASSISTANT_BOOTSTRAP.md
│   │   ├── eslint.config.mjs
│   │   ├── images
│   │   │   └── icon.png
│   │   ├── LICENSE
│   │   ├── Makefile
│   │   ├── out
│   │   │   ├── extension.d.ts
│   │   │   ├── extension.js
│   │   │   ├── test
│   │   │   │   ├── extension.test.d.ts
│   │   │   │   └── extension.test.js
│   │   │   ├── tools
│   │   │   │   ├── code_checker.d.ts
│   │   │   │   ├── code_checker.js
│   │   │   │   ├── debug_tools.d.ts
│   │   │   │   ├── debug_tools.js
│   │   │   │   ├── focus_editor.d.ts
│   │   │   │   ├── focus_editor.js
│   │   │   │   ├── search_symbol.d.ts
│   │   │   │   └── search_symbol.js
│   │   │   └── utils
│   │   │       ├── port.d.ts
│   │   │       └── port.js
│   │   ├── package.json
│   │   ├── pnpm-lock.yaml
│   │   ├── prettier.config.cjs
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── extension.d.ts
│   │   │   ├── extension.ts
│   │   │   ├── test
│   │   │   │   ├── extension.test.d.ts
│   │   │   │   └── extension.test.ts
│   │   │   ├── tools
│   │   │   │   ├── code_checker.d.ts
│   │   │   │   ├── code_checker.ts
│   │   │   │   ├── debug_tools.d.ts
│   │   │   │   ├── debug_tools.ts
│   │   │   │   ├── focus_editor.d.ts
│   │   │   │   ├── focus_editor.ts
│   │   │   │   ├── search_symbol.d.ts
│   │   │   │   └── search_symbol.ts
│   │   │   └── utils
│   │   │       ├── port.d.ts
│   │   │       └── port.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.tsbuildinfo
│   │   ├── vsc-extension-quickstart.md
│   │   └── webpack.config.js
│   └── mcp-server-web-research
│       ├── .env.example
│       ├── .gitignore
│       ├── .vscode
│       │   ├── launch.json
│       │   └── settings.json
│       ├── Makefile
│       ├── mcp_server_web_research
│       │   ├── __init__.py
│       │   ├── azure_openai.py
│       │   ├── config.py
│       │   ├── logging.py
│       │   ├── sampling.py
│       │   ├── server.py
│       │   ├── start.py
│       │   ├── utils.py
│       │   └── web_research.py
│       ├── pyproject.toml
│       ├── README.md
│       ├── test
│       │   └── test_web_research.py
│       └── uv.lock
├── README.md
├── RESPONSIBLE_AI_FAQ.md
├── ruff.toml
├── SECURITY.md
├── semantic-workbench.code-workspace
├── SUPPORT.md
├── tools
│   ├── build_ai_context_files.py
│   ├── collect_files.py
│   ├── docker
│   │   ├── azure_website_sshd.conf
│   │   ├── docker-entrypoint.sh
│   │   ├── Dockerfile.assistant
│   │   └── Dockerfile.mcp-server
│   ├── makefiles
│   │   ├── docker-assistant.mk
│   │   ├── docker-mcp-server.mk
│   │   ├── docker.mk
│   │   ├── python.mk
│   │   ├── recursive.mk
│   │   └── shell.mk
│   ├── reset-service-data.ps1
│   ├── reset-service-data.sh
│   ├── run-app.ps1
│   ├── run-app.sh
│   ├── run-canonical-agent.ps1
│   ├── run-canonical-agent.sh
│   ├── run-dotnet-examples-with-aspire.sh
│   ├── run-python-example1.sh
│   ├── run-python-example2.ps1
│   ├── run-python-example2.sh
│   ├── run-service.ps1
│   ├── run-service.sh
│   ├── run-workbench-chatbot.ps1
│   └── run-workbench-chatbot.sh
├── workbench-app
│   ├── .dockerignore
│   ├── .env.example
│   ├── .eslintrc.cjs
│   ├── .gitignore
│   ├── .vscode
│   │   ├── launch.json
│   │   └── settings.json
│   ├── docker-entrypoint.sh
│   ├── Dockerfile
│   ├── docs
│   │   ├── APP_DEV_GUIDE.md
│   │   ├── MESSAGE_METADATA.md
│   │   ├── MESSAGE_TYPES.md
│   │   ├── README.md
│   │   └── STATE_INSPECTORS.md
│   ├── index.html
│   ├── Makefile
│   ├── nginx.conf
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── prettier.config.cjs
│   ├── public
│   │   └── assets
│   │       ├── background-1-upscaled.jpg
│   │       ├── background-1-upscaled.png
│   │       ├── background-1.jpg
│   │       ├── background-1.png
│   │       ├── background-2.jpg
│   │       ├── background-2.png
│   │       ├── experimental-feature.jpg
│   │       ├── favicon.svg
│   │       ├── workflow-designer-1.jpg
│   │       ├── workflow-designer-outlets.jpg
│   │       ├── workflow-designer-states.jpg
│   │       └── workflow-designer-transitions.jpg
│   ├── README.md
│   ├── run.sh
│   ├── src
│   │   ├── components
│   │   │   ├── App
│   │   │   │   ├── AppFooter.tsx
│   │   │   │   ├── AppHeader.tsx
│   │   │   │   ├── AppMenu.tsx
│   │   │   │   ├── AppView.tsx
│   │   │   │   ├── CodeLabel.tsx
│   │   │   │   ├── CommandButton.tsx
│   │   │   │   ├── ConfirmLeave.tsx
│   │   │   │   ├── ContentExport.tsx
│   │   │   │   ├── ContentImport.tsx
│   │   │   │   ├── CopyButton.tsx
│   │   │   │   ├── DialogControl.tsx
│   │   │   │   ├── DynamicIframe.tsx
│   │   │   │   ├── ErrorListFromAppState.tsx
│   │   │   │   ├── ErrorMessageBar.tsx
│   │   │   │   ├── ExperimentalNotice.tsx
│   │   │   │   ├── FormWidgets
│   │   │   │   │   ├── BaseModelEditorWidget.tsx
│   │   │   │   │   ├── CustomizedArrayFieldTemplate.tsx
│   │   │   │   │   ├── CustomizedFieldTemplate.tsx
│   │   │   │   │   ├── CustomizedObjectFieldTemplate.tsx
│   │   │   │   │   └── InspectableWidget.tsx
│   │   │   │   ├── LabelWithDescription.tsx
│   │   │   │   ├── Loading.tsx
│   │   │   │   ├── MenuItemControl.tsx
│   │   │   │   ├── MiniControl.tsx
│   │   │   │   ├── MyAssistantServiceRegistrations.tsx
│   │   │   │   ├── MyItemsManager.tsx
│   │   │   │   ├── OverflowMenu.tsx
│   │   │   │   ├── PresenceMotionList.tsx
│   │   │   │   ├── ProfileSettings.tsx
│   │   │   │   └── TooltipWrapper.tsx
│   │   │   ├── Assistants
│   │   │   │   ├── ApplyConfigButton.tsx
│   │   │   │   ├── AssistantAdd.tsx
│   │   │   │   ├── AssistantConfigExportButton.tsx
│   │   │   │   ├── AssistantConfigImportButton.tsx
│   │   │   │   ├── AssistantConfiguration.tsx
│   │   │   │   ├── AssistantConfigure.tsx
│   │   │   │   ├── AssistantCreate.tsx
│   │   │   │   ├── AssistantDelete.tsx
│   │   │   │   ├── AssistantDuplicate.tsx
│   │   │   │   ├── AssistantExport.tsx
│   │   │   │   ├── AssistantImport.tsx
│   │   │   │   ├── AssistantRemove.tsx
│   │   │   │   ├── AssistantRename.tsx
│   │   │   │   ├── AssistantServiceInfo.tsx
│   │   │   │   ├── AssistantServiceMetadata.tsx
│   │   │   │   └── MyAssistants.tsx
│   │   │   ├── AssistantServiceRegistrations
│   │   │   │   ├── AssistantServiceRegistrationApiKey.tsx
│   │   │   │   ├── AssistantServiceRegistrationApiKeyReset.tsx
│   │   │   │   ├── AssistantServiceRegistrationCreate.tsx
│   │   │   │   └── AssistantServiceRegistrationRemove.tsx
│   │   │   ├── Conversations
│   │   │   │   ├── Canvas
│   │   │   │   │   ├── AssistantCanvas.tsx
│   │   │   │   │   ├── AssistantCanvasList.tsx
│   │   │   │   │   ├── AssistantInspector.tsx
│   │   │   │   │   ├── AssistantInspectorList.tsx
│   │   │   │   │   └── ConversationCanvas.tsx
│   │   │   │   ├── ChatInputPlugins
│   │   │   │   │   ├── ClearEditorPlugin.tsx
│   │   │   │   │   ├── LexicalMenu.ts
│   │   │   │   │   ├── ParticipantMentionsPlugin.tsx
│   │   │   │   │   ├── TypeaheadMenuPlugin.css
│   │   │   │   │   └── TypeaheadMenuPlugin.tsx
│   │   │   │   ├── ContentRenderers
│   │   │   │   │   ├── CodeContentRenderer.tsx
│   │   │   │   │   ├── ContentListRenderer.tsx
│   │   │   │   │   ├── ContentRenderer.tsx
│   │   │   │   │   ├── DiffRenderer.tsx
│   │   │   │   │   ├── HtmlContentRenderer.tsx
│   │   │   │   │   ├── JsonSchemaContentRenderer.tsx
│   │   │   │   │   ├── MarkdownContentRenderer.tsx
│   │   │   │   │   ├── MarkdownEditorRenderer.tsx
│   │   │   │   │   ├── MermaidContentRenderer.tsx
│   │   │   │   │   ├── MusicABCContentRenderer.css
│   │   │   │   │   └── MusicABCContentRenderer.tsx
│   │   │   │   ├── ContextWindow.tsx
│   │   │   │   ├── ConversationCreate.tsx
│   │   │   │   ├── ConversationDuplicate.tsx
│   │   │   │   ├── ConversationExport.tsx
│   │   │   │   ├── ConversationFileIcon.tsx
│   │   │   │   ├── ConversationRemove.tsx
│   │   │   │   ├── ConversationRename.tsx
│   │   │   │   ├── ConversationShare.tsx
│   │   │   │   ├── ConversationShareCreate.tsx
│   │   │   │   ├── ConversationShareList.tsx
│   │   │   │   ├── ConversationShareView.tsx
│   │   │   │   ├── ConversationsImport.tsx
│   │   │   │   ├── ConversationTranscript.tsx
│   │   │   │   ├── DebugInspector.tsx
│   │   │   │   ├── FileItem.tsx
│   │   │   │   ├── FileList.tsx
│   │   │   │   ├── InputAttachmentList.tsx
│   │   │   │   ├── InputOptionsControl.tsx
│   │   │   │   ├── InteractHistory.tsx
│   │   │   │   ├── InteractInput.tsx
│   │   │   │   ├── Message
│   │   │   │   │   ├── AttachmentSection.tsx
│   │   │   │   │   ├── ContentRenderer.tsx
│   │   │   │   │   ├── ContentSafetyNotice.tsx
│   │   │   │   │   ├── InteractMessage.tsx
│   │   │   │   │   ├── MessageActions.tsx
│   │   │   │   │   ├── MessageBase.tsx
│   │   │   │   │   ├── MessageBody.tsx
│   │   │   │   │   ├── MessageContent.tsx
│   │   │   │   │   ├── MessageFooter.tsx
│   │   │   │   │   ├── MessageHeader.tsx
│   │   │   │   │   ├── NotificationAccordion.tsx
│   │   │   │   │   └── ToolResultMessage.tsx
│   │   │   │   ├── MessageDelete.tsx
│   │   │   │   ├── MessageLink.tsx
│   │   │   │   ├── MyConversations.tsx
│   │   │   │   ├── MyShares.tsx
│   │   │   │   ├── ParticipantAvatar.tsx
│   │   │   │   ├── ParticipantAvatarGroup.tsx
│   │   │   │   ├── ParticipantItem.tsx
│   │   │   │   ├── ParticipantList.tsx
│   │   │   │   ├── ParticipantStatus.tsx
│   │   │   │   ├── RewindConversation.tsx
│   │   │   │   ├── ShareRemove.tsx
│   │   │   │   ├── SpeechButton.tsx
│   │   │   │   └── ToolCalls.tsx
│   │   │   └── FrontDoor
│   │   │       ├── Chat
│   │   │       │   ├── AssistantDrawer.tsx
│   │   │       │   ├── CanvasDrawer.tsx
│   │   │       │   ├── Chat.tsx
│   │   │       │   ├── ChatCanvas.tsx
│   │   │       │   ├── ChatControls.tsx
│   │   │       │   └── ConversationDrawer.tsx
│   │   │       ├── Controls
│   │   │       │   ├── AssistantCard.tsx
│   │   │       │   ├── AssistantSelector.tsx
│   │   │       │   ├── AssistantServiceSelector.tsx
│   │   │       │   ├── ConversationItem.tsx
│   │   │       │   ├── ConversationList.tsx
│   │   │       │   ├── ConversationListOptions.tsx
│   │   │       │   ├── NewConversationButton.tsx
│   │   │       │   ├── NewConversationForm.tsx
│   │   │       │   └── SiteMenuButton.tsx
│   │   │       ├── GlobalContent.tsx
│   │   │       └── MainContent.tsx
│   │   ├── Constants.ts
│   │   ├── global.d.ts
│   │   ├── index.css
│   │   ├── libs
│   │   │   ├── AppStorage.ts
│   │   │   ├── AuthHelper.ts
│   │   │   ├── EventSubscriptionManager.ts
│   │   │   ├── Theme.ts
│   │   │   ├── useAssistantCapabilities.ts
│   │   │   ├── useChatCanvasController.ts
│   │   │   ├── useConversationEvents.ts
│   │   │   ├── useConversationUtility.ts
│   │   │   ├── useCreateConversation.ts
│   │   │   ├── useDebugComponentLifecycle.ts
│   │   │   ├── useDragAndDrop.ts
│   │   │   ├── useEnvironment.ts
│   │   │   ├── useExportUtility.ts
│   │   │   ├── useHistoryUtility.ts
│   │   │   ├── useKeySequence.ts
│   │   │   ├── useMediaQuery.ts
│   │   │   ├── useMicrosoftGraph.ts
│   │   │   ├── useNotify.tsx
│   │   │   ├── useParticipantUtility.tsx
│   │   │   ├── useSiteUtility.ts
│   │   │   ├── useWorkbenchEventSource.ts
│   │   │   ├── useWorkbenchService.ts
│   │   │   └── Utility.ts
│   │   ├── main.tsx
│   │   ├── models
│   │   │   ├── Assistant.ts
│   │   │   ├── AssistantCapability.ts
│   │   │   ├── AssistantServiceInfo.ts
│   │   │   ├── AssistantServiceRegistration.ts
│   │   │   ├── Config.ts
│   │   │   ├── Conversation.ts
│   │   │   ├── ConversationFile.ts
│   │   │   ├── ConversationMessage.ts
│   │   │   ├── ConversationMessageDebug.ts
│   │   │   ├── ConversationParticipant.ts
│   │   │   ├── ConversationShare.ts
│   │   │   ├── ConversationShareRedemption.ts
│   │   │   ├── ConversationState.ts
│   │   │   ├── ConversationStateDescription.ts
│   │   │   ├── ServiceEnvironment.ts
│   │   │   └── User.ts
│   │   ├── redux
│   │   │   ├── app
│   │   │   │   ├── hooks.ts
│   │   │   │   ├── rtkQueryErrorLogger.ts
│   │   │   │   └── store.ts
│   │   │   └── features
│   │   │       ├── app
│   │   │       │   ├── appSlice.ts
│   │   │       │   └── AppState.ts
│   │   │       ├── chatCanvas
│   │   │       │   ├── chatCanvasSlice.ts
│   │   │       │   └── ChatCanvasState.ts
│   │   │       ├── localUser
│   │   │       │   ├── localUserSlice.ts
│   │   │       │   └── LocalUserState.ts
│   │   │       └── settings
│   │   │           ├── settingsSlice.ts
│   │   │           └── SettingsState.ts
│   │   ├── Root.tsx
│   │   ├── routes
│   │   │   ├── AcceptTerms.tsx
│   │   │   ├── AssistantEditor.tsx
│   │   │   ├── AssistantServiceRegistrationEditor.tsx
│   │   │   ├── Dashboard.tsx
│   │   │   ├── ErrorPage.tsx
│   │   │   ├── FrontDoor.tsx
│   │   │   ├── Login.tsx
│   │   │   ├── Settings.tsx
│   │   │   ├── ShareRedeem.tsx
│   │   │   └── Shares.tsx
│   │   ├── services
│   │   │   └── workbench
│   │   │       ├── assistant.ts
│   │   │       ├── assistantService.ts
│   │   │       ├── conversation.ts
│   │   │       ├── file.ts
│   │   │       ├── index.ts
│   │   │       ├── participant.ts
│   │   │       ├── share.ts
│   │   │       ├── state.ts
│   │   │       └── workbench.ts
│   │   └── vite-env.d.ts
│   ├── tools
│   │   └── filtered-ts-prune.cjs
│   ├── tsconfig.json
│   └── vite.config.ts
└── workbench-service
    ├── .env.example
    ├── .vscode
    │   ├── extensions.json
    │   ├── launch.json
    │   └── settings.json
    ├── alembic.ini
    ├── devdb
    │   ├── docker-compose.yaml
    │   └── postgresql-init.sh
    ├── Dockerfile
    ├── Makefile
    ├── migrations
    │   ├── env.py
    │   ├── README
    │   ├── script.py.mako
    │   └── versions
    │       ├── 2024_09_19_000000_69dcda481c14_init.py
    │       ├── 2024_09_19_190029_dffb1d7e219a_file_version_filename.py
    │       ├── 2024_09_20_204130_b29524775484_share.py
    │       ├── 2024_10_30_231536_039bec8edc33_index_message_type.py
    │       ├── 2024_11_04_204029_5149c7fb5a32_conversationmessagedebug.py
    │       ├── 2024_11_05_015124_245baf258e11_double_check_debugs.py
    │       ├── 2024_11_25_191056_a106de176394_drop_workflow.py
    │       ├── 2025_03_19_140136_aaaf792d4d72_set_user_title_set.py
    │       ├── 2025_03_21_153250_3763629295ad_add_assistant_template_id.py
    │       ├── 2025_05_19_163613_b2f86e981885_delete_context_transfer_assistants.py
    │       └── 2025_06_18_174328_503c739152f3_delete_knowlege_transfer_assistants.py
    ├── pyproject.toml
    ├── README.md
    ├── semantic_workbench_service
    │   ├── __init__.py
    │   ├── api.py
    │   ├── assistant_api_key.py
    │   ├── auth.py
    │   ├── azure_speech.py
    │   ├── config.py
    │   ├── controller
    │   │   ├── __init__.py
    │   │   ├── assistant_service_client_pool.py
    │   │   ├── assistant_service_registration.py
    │   │   ├── assistant.py
    │   │   ├── conversation_share.py
    │   │   ├── conversation.py
    │   │   ├── convert.py
    │   │   ├── exceptions.py
    │   │   ├── export_import.py
    │   │   ├── file.py
    │   │   ├── participant.py
    │   │   └── user.py
    │   ├── db.py
    │   ├── event.py
    │   ├── files.py
    │   ├── logging_config.py
    │   ├── middleware.py
    │   ├── query.py
    │   ├── service_user_principals.py
    │   ├── service.py
    │   └── start.py
    ├── tests
    │   ├── __init__.py
    │   ├── conftest.py
    │   ├── docker-compose.yaml
    │   ├── test_assistant_api_key.py
    │   ├── test_files.py
    │   ├── test_integration.py
    │   ├── test_middleware.py
    │   ├── test_migrations.py
    │   ├── test_workbench_service.py
    │   └── types.py
    └── uv.lock
```

# Files

--------------------------------------------------------------------------------
/assistants/prospector-assistant/assistant/chat.py:
--------------------------------------------------------------------------------

```python
  1 | # Copyright (c) Microsoft. All rights reserved.
  2 | 
  3 | # Prospector Assistant
  4 | #
  5 | # This assistant helps you mine ideas from artifacts.
  6 | #
  7 | 
  8 | import asyncio
  9 | import logging
 10 | import re
 11 | import traceback
 12 | from contextlib import asynccontextmanager
 13 | from typing import Any, Awaitable, Callable
 14 | 
 15 | import deepmerge
 16 | import openai_client
 17 | from assistant_extensions.attachments import AttachmentsExtension
 18 | from content_safety.evaluators import CombinedContentSafetyEvaluator
 19 | from openai.types.chat import ChatCompletionMessageParam
 20 | from llm_client.model import CompletionMessageImageContent
 21 | from pydantic import BaseModel, ConfigDict
 22 | from semantic_workbench_api_model.workbench_model import (
 23 |     AssistantStateEvent,
 24 |     ConversationEvent,
 25 |     ConversationMessage,
 26 |     ConversationParticipant,
 27 |     MessageType,
 28 |     NewConversationMessage,
 29 | )
 30 | from semantic_workbench_assistant.assistant_app import (
 31 |     AssistantApp,
 32 |     BaseModelAssistantConfig,
 33 |     ContentSafety,
 34 |     ContentSafetyEvaluator,
 35 |     ConversationContext,
 36 | )
 37 | 
 38 | from . import legacy
 39 | from .agents.artifact_agent import Artifact, ArtifactAgent, ArtifactConversationInspectorStateProvider
 40 | from .agents.document_agent import DocumentAgent
 41 | from .artifact_creation_extension.extension import ArtifactCreationExtension
 42 | from .config import AssistantConfigModel
 43 | from .form_fill_extension import FormFillExtension, LLMConfig
 44 | 
 45 | logger = logging.getLogger(__name__)
 46 | 
 47 | #
 48 | # region Setup
 49 | #
 50 | 
 51 | # the service id to be registered in the workbench to identify the assistant
 52 | service_id = "prospector-assistant.made-exploration"
 53 | # the name of the assistant service, as it will appear in the workbench UI
 54 | service_name = "Prospector Assistant"
 55 | # a description of the assistant service, as it will appear in the workbench UI
 56 | service_description = "An assistant that helps you mine ideas from artifacts."
 57 | 
 58 | #
 59 | # create the configuration provider, using the extended configuration model
 60 | #
 61 | assistant_config = BaseModelAssistantConfig(AssistantConfigModel)
 62 | 
 63 | 
 64 | # define the content safety evaluator factory
 65 | async def content_evaluator_factory(context: ConversationContext) -> ContentSafetyEvaluator:
 66 |     config = await assistant_config.get(context.assistant)
 67 |     return CombinedContentSafetyEvaluator(config.content_safety_config)
 68 | 
 69 | 
 70 | content_safety = ContentSafety(content_evaluator_factory)
 71 | 
 72 | # create the AssistantApp instance
 73 | assistant = AssistantApp(
 74 |     assistant_service_id=service_id,
 75 |     assistant_service_name=service_name,
 76 |     assistant_service_description=service_description,
 77 |     config_provider=assistant_config.provider,
 78 |     content_interceptor=content_safety,
 79 |     inspector_state_providers={
 80 |         "artifacts": ArtifactConversationInspectorStateProvider(assistant_config),
 81 |     },
 82 | )
 83 | 
 84 | attachments_extension = AttachmentsExtension(assistant)
 85 | form_fill_extension = FormFillExtension(assistant)
 86 | artifact_creation_extension = ArtifactCreationExtension(assistant, assistant_config)
 87 | 
 88 | #
 89 | # create the FastAPI app instance
 90 | #
 91 | app = assistant.fastapi_app()
 92 | 
 93 | 
 94 | # endregion
 95 | 
 96 | 
 97 | #
 98 | # region Event Handlers
 99 | #
100 | # The AssistantApp class provides a set of decorators for adding event handlers to respond to conversation
101 | # events. In VS Code, typing "@assistant." (or the name of your AssistantApp instance) will show available
102 | # events and methods.
103 | #
104 | # See the semantic-workbench-assistant AssistantApp class for more information on available events and methods.
105 | # Examples:
106 | # - @assistant.events.conversation.on_created (event triggered when the assistant is added to a conversation)
107 | # - @assistant.events.conversation.participant.on_created (event triggered when a participant is added)
108 | # - @assistant.events.conversation.message.on_created (event triggered when a new message of any type is created)
109 | # - @assistant.events.conversation.message.chat.on_created (event triggered when a new chat message is created)
110 | #
111 | 
112 | 
113 | @assistant.events.conversation.message.on_created
114 | async def on_message_created(
115 |     context: ConversationContext, event: ConversationEvent, message: ConversationMessage
116 | ) -> None:
117 |     await legacy.provide_guidance_if_necessary(context)
118 | 
119 | 
120 | @assistant.events.conversation.message.chat.on_created
121 | async def on_chat_message_created(
122 |     context: ConversationContext, event: ConversationEvent, message: ConversationMessage
123 | ) -> None:
124 |     """
125 |     Handle the event triggered when a new chat message is created in the conversation.
126 | 
127 |     **Note**
128 |     - This event handler is specific to chat messages.
129 |     - To handle other message types, you can add additional event handlers for those message types.
130 |       - @assistant.events.conversation.message.log.on_created
131 |       - @assistant.events.conversation.message.command.on_created
132 |       - ...additional message types
133 |     - To handle all message types, you can use the root event handler for all message types:
134 |       - @assistant.events.conversation.message.on_created
135 |     """
136 | 
137 |     config = await assistant_config.get(context.assistant)
138 |     if config.guided_workflow == "Long Document Creation":
139 |         return
140 | 
141 |     # update the participant status to indicate the assistant is responding
142 |     async with send_error_message_on_exception(context), context.set_status("responding..."):
143 |         #
144 |         # NOTE: we're experimenting with agents, if they are enabled, use them to respond to the conversation
145 |         #
146 |         metadata: dict[str, Any] = {"debug": {"content_safety": event.data.get(content_safety.metadata_key, {})}}
147 | 
148 |         match config.guided_workflow:
149 |             case "Form Completion":
150 |                 await form_fill_execute(context, message)
151 |             case "Document Creation":
152 |                 await create_document_execute(config, context, message, metadata)
153 |             case _:
154 |                 logger.error("Guided workflow unknown or not supported.")
155 | 
156 | 
157 | background_tasks: set[asyncio.Task] = set()
158 | 
159 | 
160 | @assistant.events.conversation.on_created
161 | async def on_conversation_created(context: ConversationContext) -> None:
162 |     """
163 |     Handle the event triggered when the assistant is added to a conversation.
164 |     """
165 |     assistant_sent_messages = await context.get_messages(participant_ids=[context.assistant.id], limit=1)
166 |     welcome_sent_before = len(assistant_sent_messages.messages) > 0
167 |     if welcome_sent_before:
168 |         return
169 | 
170 |     #
171 |     # NOTE: we're experimenting with agents, if they are enabled, use them to respond to the conversation
172 |     #
173 |     config = await assistant_config.get(context.assistant)
174 |     metadata: dict[str, Any] = {"debug": {}}
175 | 
176 |     task: asyncio.Task | None = None
177 |     match config.guided_workflow:
178 |         case "Form Completion":
179 |             task = asyncio.create_task(welcome_message_form_fill(context))
180 |         case "Document Creation":
181 |             task = asyncio.create_task(
182 |                 welcome_message_create_document(config, context, message=None, metadata=metadata)
183 |             )
184 |         case "Long Document Creation":
185 |             pass
186 |         case _:
187 |             logger.error("Guided workflow unknown or not supported.")
188 |             return
189 | 
190 |     if task:
191 |         background_tasks.add(task)
192 |         task.add_done_callback(background_tasks.remove)
193 | 
194 | 
195 | async def welcome_message_form_fill(context: ConversationContext) -> None:
196 |     async with send_error_message_on_exception(context), context.set_status("responding..."):
197 |         await form_fill_execute(context, None)
198 | 
199 | 
200 | async def welcome_message_create_document(
201 |     config: AssistantConfigModel,
202 |     context: ConversationContext,
203 |     message: ConversationMessage | None,
204 |     metadata: dict[str, Any],
205 | ) -> None:
206 |     async with send_error_message_on_exception(context), context.set_status("responding..."):
207 |         await create_document_execute(config, context, message, metadata)
208 | 
209 | 
210 | @asynccontextmanager
211 | async def send_error_message_on_exception(context: ConversationContext):
212 |     try:
213 |         yield
214 |     except Exception as e:
215 |         await context.send_messages(
216 |             NewConversationMessage(
217 |                 content=f"An error occurred: {e}",
218 |                 message_type=MessageType.notice,
219 |                 metadata={"debug": {"stack_trace": traceback.format_exc()}},
220 |             )
221 |         )
222 | 
223 | 
224 | # endregion
225 | 
226 | #
227 | # region Form Fill Extension Helpers
228 | #
229 | 
230 | 
231 | async def form_fill_execute(context: ConversationContext, message: ConversationMessage | None) -> None:
232 |     """
233 |     Execute the form fill agent to respond to the conversation message.
234 |     """
235 |     config = await assistant_config.get(context.assistant)
236 |     participants = await context.get_participants(include_inactive=True)
237 |     await form_fill_extension.execute(
238 |         llm_config=LLMConfig(
239 |             openai_client_factory=lambda: openai_client.create_client(config.service_config),
240 |             openai_model=config.request_config.openai_model,
241 |             max_response_tokens=config.request_config.response_tokens,
242 |         ),
243 |         config=config.agents_config.form_fill_agent,
244 |         context=context,
245 |         latest_user_message=_format_message(message, participants.participants) if message else None,
246 |         latest_attachment_filenames=message.filenames if message else [],
247 |         get_attachment_content=form_fill_extension_get_attachment(context, config),
248 |     )
249 | 
250 | 
251 | def form_fill_extension_get_attachment(
252 |     context: ConversationContext, config: AssistantConfigModel
253 | ) -> Callable[[str], Awaitable[str]]:
254 |     """Helper function for the form_fill_extension to get the content of an attachment by filename."""
255 | 
256 |     async def get(filename: str) -> str:
257 |         messages = await attachments_extension.get_completion_messages_for_attachments(
258 |             context,
259 |             config.agents_config.attachment_agent,
260 |             include_filenames=[filename],
261 |         )
262 |         if not messages:
263 |             return ""
264 | 
265 |         # filter down to the message with the attachment
266 |         user_message = next(
267 |             (message for message in messages if "<ATTACHMENT>" in str(message)),
268 |             None,
269 |         )
270 |         if not user_message:
271 |             return ""
272 | 
273 |         content = user_message.content
274 |         match content:
275 |             case str():
276 |                 return content
277 | 
278 |             case list():
279 |                 for part in content:
280 |                     match part:
281 |                         case CompletionMessageImageContent():
282 |                             return part.data
283 | 
284 |         return ""
285 | 
286 |     return get
287 | 
288 | 
289 | # endregion
290 | 
291 | 
292 | #
293 | # region Document Extension Helpers
294 | #
295 | 
296 | 
297 | async def create_document_execute(
298 |     config: AssistantConfigModel,
299 |     context: ConversationContext,
300 |     message: ConversationMessage | None,
301 |     metadata: dict[str, Any] = {},
302 | ) -> None:
303 |     """
304 |     Respond to a conversation message using the document agent.
305 |     """
306 |     # create the document agent instance
307 |     document_agent = DocumentAgent(attachments_extension)
308 |     await document_agent.create_document(config, context, message, metadata)
309 | 
310 | 
311 | # demonstrates how to respond to a conversation message using the OpenAI API.
312 | async def respond_to_conversation(
313 |     context: ConversationContext,
314 |     config: AssistantConfigModel,
315 |     message: ConversationMessage,
316 |     metadata: dict[str, Any] = {},
317 | ) -> None:
318 |     """
319 |     Respond to a conversation message.
320 | 
321 |     This method uses the OpenAI API to generate a response to the message.
322 | 
323 |     It includes any attachments as individual system messages before the chat history, along with references
324 |     to the attachments in the point in the conversation where they were mentioned. This allows the model to
325 |     consider the full contents of the attachments separate from the conversation, but with the context of
326 |     where they were mentioned and any relevant surrounding context such as how to interpret the attachment
327 |     or why it was shared or what to do with it.
328 |     """
329 | 
330 |     # define the metadata key for any metadata created within this method
331 |     method_metadata_key = "respond_to_conversation"
332 | 
333 |     # get the list of conversation participants
334 |     participants_response = await context.get_participants(include_inactive=True)
335 | 
336 |     # establish a token to be used by the AI model to indicate no response
337 |     silence_token = "{{SILENCE}}"
338 | 
339 |     system_message_content = f'{config.instruction_prompt}\n\nYour name is "{context.assistant.name}".'
340 |     if len(participants_response.participants) > 2:
341 |         system_message_content += (
342 |             "\n\n"
343 |             f"There are {len(participants_response.participants)} participants in the conversation,"
344 |             " including you as the assistant and the following users:"
345 |             + ",".join([
346 |                 f' "{participant.name}"'
347 |                 for participant in participants_response.participants
348 |                 if participant.id != context.assistant.id
349 |             ])
350 |             + "\n\nYou do not need to respond to every message. Do not respond if the last thing said was a closing"
351 |             " statement such as 'bye' or 'goodbye', or just a general acknowledgement like 'ok' or 'thanks'. Do not"
352 |             f' respond as another user in the conversation, only as "{context.assistant.name}".'
353 |             " Sometimes the other users need to talk amongst themselves and that is ok. If the conversation seems to"
354 |             f' be directed at you or the general audience, go ahead and respond.\n\nSay "{silence_token}" to skip'
355 |             " your turn."
356 |         )
357 | 
358 |     # add the artifact agent instruction prompt to the system message content
359 |     if config.agents_config.artifact_agent.enabled:
360 |         system_message_content += f"\n\n{config.agents_config.artifact_agent.instruction_prompt}"
361 | 
362 |     # add the guardrails prompt to the system message content
363 |     system_message_content += f"\n\n{config.guardrails_prompt}"
364 | 
365 |     completion_messages: list[ChatCompletionMessageParam] = [
366 |         {
367 |             "role": "system",
368 |             "content": system_message_content,
369 |         }
370 |     ]
371 | 
372 |     # generate the attachment messages from the attachment agent
373 |     attachment_messages = await attachments_extension.get_completion_messages_for_attachments(
374 |         context, config=config.agents_config.attachment_agent
375 |     )
376 | 
377 |     # add the attachment messages to the completion messages
378 |     completion_messages.extend(openai_client.convert_from_completion_messages(attachment_messages))
379 | 
380 |     # get messages before the current message
381 |     messages_response = await context.get_messages(before=message.id)
382 |     messages = messages_response.messages + [message]
383 | 
384 |     # calculate the token count for the messages so far
385 |     token_count = openai_client.num_tokens_from_messages(
386 |         model=config.request_config.openai_model, messages=completion_messages
387 |     )
388 | 
389 |     # calculate the total available tokens for the response generation
390 |     available_tokens = config.request_config.max_tokens - config.request_config.response_tokens
391 | 
392 |     # build the completion messages from the conversation history
393 |     history_messages: list[ChatCompletionMessageParam] = []
394 | 
395 |     # add the messages in reverse order to get the most recent messages first
396 |     for message in reversed(messages):
397 |         messages_to_add: list[ChatCompletionMessageParam] = []
398 | 
399 |         # add the message to the completion messages, treating any message from a source other than the assistant
400 |         # as a user message
401 |         if message.sender.participant_id == context.assistant.id:
402 |             messages_to_add.append({
403 |                 "role": "assistant",
404 |                 "content": _format_message(message, participants_response.participants),
405 |             })
406 |         else:
407 |             # we are working with the messages in reverse order, so include any attachments before the message
408 |             if message.filenames and len(message.filenames) > 0:
409 |                 # add a system message to indicate the attachments
410 |                 messages_to_add.append({
411 |                     "role": "system",
412 |                     "content": f"Attachment(s): {', '.join(message.filenames)}",
413 |                 })
414 |             # add the user message to the completion messages
415 |             messages_to_add.append({
416 |                 "role": "user",
417 |                 "content": _format_message(message, participants_response.participants),
418 |             })
419 | 
420 |         # calculate the token count for the message and check if it exceeds the available tokens
421 |         messages_to_add_token_count = openai_client.num_tokens_from_messages(
422 |             model=config.request_config.openai_model, messages=messages_to_add
423 |         )
424 |         if (token_count + messages_to_add_token_count) > available_tokens:
425 |             # stop processing messages if the token count exceeds the available tokens
426 |             break
427 | 
428 |         token_count += messages_to_add_token_count
429 |         history_messages.extend(messages_to_add)
430 | 
431 |     # reverse the history messages to get them back in the correct order
432 |     history_messages.reverse()
433 | 
434 |     # add the history messages to the completion messages
435 |     completion_messages.extend(history_messages)
436 | 
437 |     # initialize variables for the response content and total tokens used
438 |     content: str | None = None
439 |     completion_total_tokens: int | None = None
440 | 
441 |     # set default response message type
442 |     message_type = MessageType.chat
443 | 
444 |     # TODO: DRY up this code by moving the OpenAI API call to a shared method and calling it from both branches
445 |     # use structured response support to create or update artifacts, if artifacts are enabled
446 |     if config.agents_config.artifact_agent.enabled:
447 |         # define the structured response format for the AI model
448 |         class StructuredResponseFormat(BaseModel):
449 |             model_config = ConfigDict(
450 |                 extra="forbid",
451 |                 json_schema_extra={
452 |                     "description": (
453 |                         "The response format for the assistant. Use the assistant_response field for the"
454 |                         " response content and the artifacts_to_create_or_update field for any artifacts"
455 |                         " to create or update."
456 |                     ),
457 |                     "required": ["assistant_response", "artifacts_to_create_or_update"],
458 |                 },
459 |             )
460 | 
461 |             assistant_response: str
462 |             artifacts_to_create_or_update: list[Artifact]
463 | 
464 |         # generate a response from the AI model
465 |         completion_total_tokens: int | None = None
466 |         async with openai_client.create_client(config.service_config) as client:
467 |             try:
468 |                 # call the OpenAI API to generate a completion
469 |                 completion = await client.beta.chat.completions.parse(
470 |                     messages=completion_messages,
471 |                     model=config.request_config.openai_model,
472 |                     max_tokens=config.request_config.response_tokens,
473 |                     response_format=StructuredResponseFormat,
474 |                 )
475 |                 content = completion.choices[0].message.content
476 | 
477 |                 # get the prospector response from the completion
478 |                 structured_response = completion.choices[0].message.parsed
479 |                 # get the assistant response from the prospector response
480 |                 content = structured_response.assistant_response if structured_response else content
481 |                 # get the artifacts to create or update from the prospector response
482 |                 if structured_response and structured_response.artifacts_to_create_or_update:
483 |                     for artifact in structured_response.artifacts_to_create_or_update:
484 |                         ArtifactAgent.create_or_update_artifact(
485 |                             context,
486 |                             artifact,
487 |                         )
488 |                     # send an event to notify the artifact state was updated
489 |                     await context.send_conversation_state_event(
490 |                         AssistantStateEvent(
491 |                             state_id="artifacts",
492 |                             event="updated",
493 |                             state=None,
494 |                         )
495 |                     )
496 | 
497 |                     # send a focus event to notify the assistant to focus on the artifacts
498 |                     await context.send_conversation_state_event(
499 |                         AssistantStateEvent(
500 |                             state_id="artifacts",
501 |                             event="focus",
502 |                             state=None,
503 |                         )
504 |                     )
505 | 
506 |                 # get the total tokens used for the completion
507 |                 completion_total_tokens = completion.usage.total_tokens if completion.usage else None
508 | 
509 |                 # add the completion to the metadata for debugging
510 |                 deepmerge.always_merger.merge(
511 |                     metadata,
512 |                     {
513 |                         "debug": {
514 |                             method_metadata_key: {
515 |                                 "request": {
516 |                                     "model": config.request_config.openai_model,
517 |                                     "messages": completion_messages,
518 |                                     "max_tokens": config.request_config.response_tokens,
519 |                                     "response_format": StructuredResponseFormat.model_json_schema(),
520 |                                 },
521 |                                 "response": completion.model_dump() if completion else "[no response from openai]",
522 |                             },
523 |                         }
524 |                     },
525 |                 )
526 |             except Exception as e:
527 |                 logger.exception(f"exception occurred calling openai chat completion: {e}")
528 |                 content = (
529 |                     "An error occurred while calling the OpenAI API. Is it configured correctly?"
530 |                     " View the debug inspector for more information."
531 |                 )
532 |                 message_type = MessageType.notice
533 |                 deepmerge.always_merger.merge(
534 |                     metadata,
535 |                     {
536 |                         "debug": {
537 |                             method_metadata_key: {
538 |                                 "request": {
539 |                                     "model": config.request_config.openai_model,
540 |                                     "messages": completion_messages,
541 |                                 },
542 |                                 "error": str(e),
543 |                             },
544 |                         }
545 |                     },
546 |                 )
547 | 
548 |     # fallback to prior approach to generate a response from the AI model when artifacts are not enabled
549 |     if not config.agents_config.artifact_agent.enabled:
550 |         # generate a response from the AI model
551 |         completion_total_tokens: int | None = None
552 |         async with openai_client.create_client(config.service_config) as client:
553 |             try:
554 |                 # call the OpenAI API to generate a completion
555 |                 completion = await client.chat.completions.create(
556 |                     messages=completion_messages,
557 |                     model=config.request_config.openai_model,
558 |                     max_tokens=config.request_config.response_tokens,
559 |                 )
560 |                 content = completion.choices[0].message.content
561 | 
562 |                 # get the total tokens used for the completion
563 |                 completion_total_tokens = completion.usage.total_tokens if completion.usage else None
564 | 
565 |                 # add the completion to the metadata for debugging
566 |                 deepmerge.always_merger.merge(
567 |                     metadata,
568 |                     {
569 |                         "debug": {
570 |                             method_metadata_key: {
571 |                                 "request": {
572 |                                     "model": config.request_config.openai_model,
573 |                                     "messages": completion_messages,
574 |                                     "max_tokens": config.request_config.response_tokens,
575 |                                 },
576 |                                 "response": completion.model_dump() if completion else "[no response from openai]",
577 |                             },
578 |                         }
579 |                     },
580 |                 )
581 | 
582 |             except Exception as e:
583 |                 logger.exception(f"exception occurred calling openai chat completion: {e}")
584 |                 content = (
585 |                     "An error occurred while calling the OpenAI API. Is it configured correctly?"
586 |                     " View the debug inspector for more information."
587 |                 )
588 |                 message_type = MessageType.notice
589 |                 deepmerge.always_merger.merge(
590 |                     metadata,
591 |                     {
592 |                         "debug": {
593 |                             method_metadata_key: {
594 |                                 "request": {
595 |                                     "model": config.request_config.openai_model,
596 |                                     "messages": completion_messages,
597 |                                 },
598 |                                 "error": str(e),
599 |                             },
600 |                         }
601 |                     },
602 |                 )
603 | 
604 |     if content:
605 |         # strip out the username from the response
606 |         if content.startswith("["):
607 |             content = re.sub(r"\[.*\]:\s", "", content)
608 | 
609 |         # model sometimes puts extra spaces in the response, so remove them
610 |         # when checking for the silence token
611 |         if content.replace(" ", "") == silence_token:
612 |             # if debug output is enabled, notify the conversation that the assistant chose to remain silent
613 |             if config.enable_debug_output:
614 |                 # add debug metadata to indicate the assistant chose to remain silent
615 |                 deepmerge.always_merger.merge(
616 |                     metadata,
617 |                     {
618 |                         "debug": {
619 |                             method_metadata_key: {
620 |                                 "silence_token": True,
621 |                             },
622 |                         },
623 |                         "attribution": "debug output",
624 |                         "generated_content": False,
625 |                     },
626 |                 )
627 |                 # send a notice message to the conversation
628 |                 await context.send_messages(
629 |                     NewConversationMessage(
630 |                         message_type=MessageType.notice,
631 |                         content="[assistant chose to remain silent]",
632 |                         metadata=metadata,
633 |                     )
634 |                 )
635 |             return
636 | 
637 |         # override message type if content starts with /
638 |         if content.startswith("/"):
639 |             message_type = MessageType.command_response
640 | 
641 |     # send the response to the conversation
642 |     await context.send_messages(
643 |         NewConversationMessage(
644 |             content=content or "[no response from openai]",
645 |             message_type=message_type,
646 |             metadata=metadata,
647 |         )
648 |     )
649 | 
650 |     # check the token usage and send a warning if it is high
651 |     if completion_total_tokens is not None and config.high_token_usage_warning.enabled:
652 |         # calculate the token count for the warning threshold
653 |         token_count_for_warning = config.request_config.max_tokens * (config.high_token_usage_warning.threshold / 100)
654 | 
655 |         # check if the completion total tokens exceed the warning threshold
656 |         if completion_total_tokens > token_count_for_warning:
657 |             content = f"{config.high_token_usage_warning.message}\n\nTotal tokens used: {completion_total_tokens}"
658 | 
659 |             # send a notice message to the conversation that the token usage is high
660 |             await context.send_messages(
661 |                 NewConversationMessage(
662 |                     content=content,
663 |                     message_type=MessageType.notice,
664 |                     metadata={
665 |                         "debug": {
666 |                             "high_token_usage_warning": {
667 |                                 "completion_total_tokens": completion_total_tokens,
668 |                                 "threshold": config.high_token_usage_warning.threshold,
669 |                                 "token_count_for_warning": token_count_for_warning,
670 |                             }
671 |                         },
672 |                         "attribution": "system",
673 |                     },
674 |                 )
675 |             )
676 | 
677 | 
678 | # endregion
679 | 
680 | 
681 | #
682 | # region Helpers
683 | #
684 | 
685 | 
686 | def _format_message(message: ConversationMessage, participants: list[ConversationParticipant]) -> str:
687 |     """
688 |     Format a conversation message for display.
689 |     """
690 |     conversation_participant = next(
691 |         (participant for participant in participants if participant.id == message.sender.participant_id),
692 |         None,
693 |     )
694 |     participant_name = conversation_participant.name if conversation_participant else "unknown"
695 |     message_datetime = message.timestamp.strftime("%Y-%m-%d %H:%M:%S")
696 |     return f"[{participant_name} - {message_datetime}]: {message.content}"
697 | 
698 | 
699 | # endregion
700 | 
```

--------------------------------------------------------------------------------
/libraries/python/skills/skill-library/skill_library/cli/run_routine.py:
--------------------------------------------------------------------------------

```python
  1 | #!/usr/bin/env python3
  2 | """
  3 | run-routine - Command-line utility to execute routines from the skill_library
  4 | 
  5 | Usage:
  6 |   run-routine ROUTINE_NAME [OPTIONS]
  7 |   run-routine --list
  8 |   run-routine --usage
  9 |   cat input.txt | run-routine ROUTINE_NAME [OPTIONS]
 10 | 
 11 | Arguments:
 12 |   ROUTINE_NAME    Name of the routine to run (e.g., "research2.research")
 13 | 
 14 | Options:
 15 |   --home PATH           Path to skills home directory (default: .skills in current or home dir)
 16 |   --engine ID           Engine ID to use (default: "cli")
 17 |   --param KEY=VALUE     Parameter to pass to the routine (can be used multiple times)
 18 |   --timeout SECONDS     Maximum seconds to allow the routine to run (default: 600)
 19 |   --non-interactive     Run in non-interactive mode, fail if user input is needed
 20 |   --list                List all available routines
 21 |   --usage               Show detailed usage information for all routines
 22 |   --quiet               Suppress log output to stderr in interactive mode
 23 | 
 24 | Environment Variables:
 25 |   SKILLS_HOME_DIR       Override skills home directory path
 26 |   SKILLS_ENGINE_ID      Override engine ID
 27 | 
 28 | Examples:
 29 |   # Run a research routine with a specific topic
 30 |   run-routine research2.research --param plan_name="AI-trends" --param topic="Latest AI trends"
 31 | 
 32 |   # Pipe content as input
 33 |   echo "What is quantum computing?" | run-routine research2.research
 34 | 
 35 |   # List all available routines
 36 |   run-routine --list
 37 | 
 38 |   # See detailed usage for all routines
 39 |   run-routine --usage
 40 | 
 41 |   # Run with a 5-minute timeout
 42 |   run-routine research2.research --param plan_name="climate" --param topic="Climate change" --timeout 300
 43 | 
 44 |   # Run in non-interactive mode (will fail if user input is needed)
 45 |   run-routine research2.research --param plan_name="ai-ethics" --param topic="AI ethics" --non-interactive
 46 | """
 47 | 
 48 | import asyncio
 49 | import datetime
 50 | import importlib
 51 | import json
 52 | import os
 53 | import sys
 54 | import time
 55 | import traceback
 56 | import uuid
 57 | from argparse import ArgumentParser, RawDescriptionHelpFormatter
 58 | from pathlib import Path
 59 | from typing import Any, Dict, Optional, Tuple
 60 | 
 61 | from skill_library.skills.meta.meta_skill import MetaSkill, MetaSkillConfig
 62 | 
 63 | # Import skill library dependencies
 64 | try:
 65 |     from assistant_drive import Drive, DriveConfig
 66 |     from events import events as skill_events
 67 |     from semantic_workbench_api_model.workbench_model import (
 68 |         ParticipantRole,
 69 |     )
 70 |     from skill_library import Engine
 71 |     from skill_library.cli.azure_openai import create_azure_openai_client
 72 |     from skill_library.cli.conversation_history import ConversationHistory
 73 |     from skill_library.cli.settings import Settings
 74 |     from skill_library.cli.skill_logger import SkillLogger
 75 | 
 76 |     # Import skill implementations
 77 |     from skill_library.skills.common import CommonSkill, CommonSkillConfig
 78 |     from skill_library.skills.posix import PosixSkill, PosixSkillConfig
 79 |     from skill_library.skills.research import ResearchSkill, ResearchSkillConfig
 80 |     from skill_library.skills.web_research import WebResearchSkill, WebResearchSkillConfig
 81 | except ImportError as e:
 82 |     print(f"Error: Required dependency not found - {e}", file=sys.stderr)
 83 |     print("Please ensure skill_library and its dependencies are installed.", file=sys.stderr)
 84 |     sys.exit(1)
 85 | 
 86 | 
 87 | class RoutineRunner:
 88 |     """Manages the execution of skill routines."""
 89 | 
 90 |     def __init__(
 91 |         self,
 92 |         routine_name: str,
 93 |         params: Dict[str, Any],
 94 |         input_text: Optional[str],
 95 |         skills_home_dir: Path,
 96 |         engine_id: str,
 97 |         history: ConversationHistory,
 98 |         logger: SkillLogger,
 99 |     ):
100 |         self.routine_name = routine_name
101 |         self.params = params.copy()
102 |         self.input_text = input_text
103 |         self.skills_home_dir = skills_home_dir
104 |         self.engine_id = engine_id
105 |         self.history = history
106 |         self.logger = logger
107 | 
108 |         # Extract special parameters
109 |         self.non_interactive = self.params.pop("__non_interactive", False)
110 |         self.timeout_seconds = self.params.pop("__timeout", 600)
111 | 
112 |         # Handle input text
113 |         if self.input_text:
114 |             try:
115 |                 if self.input_text:
116 |                     input_json = json.loads(self.input_text)
117 |                     if isinstance(input_json, dict):
118 |                         self.params.update(input_json)
119 |                     elif isinstance(input_json, list):
120 |                         self.params["input_list"] = input_json
121 |             except json.JSONDecodeError:
122 |                 self.params["input_text"] = self.input_text
123 | 
124 |             # Record input text as user message
125 |             self.history.add_message(self.input_text, ParticipantRole.user)
126 | 
127 |         # Runtime state
128 |         self.engine = None
129 |         self.user_interaction_queue = asyncio.Queue()
130 |         self.user_interaction_active = asyncio.Event()
131 |         self.start_time = 0
132 | 
133 |     def initialize_engine(self) -> Optional[Engine]:
134 |         """Initialize the engine with configured skills."""
135 |         # Create settings from the skills home directory
136 |         settings = Settings(self.skills_home_dir, self.logger)
137 | 
138 |         # Ensure data folder exists
139 |         data_folder = settings.data_folder
140 |         data_folder.mkdir(parents=True, exist_ok=True)
141 | 
142 |         drive = Drive(DriveConfig(root=data_folder))
143 | 
144 |         try:
145 |             language_model = create_azure_openai_client(
146 |                 settings.azure_openai_endpoint, settings.azure_openai_deployment
147 |             )
148 |             reasoning_language_model = create_azure_openai_client(
149 |                 settings.azure_openai_endpoint, settings.azure_openai_reasoning_deployment
150 |             )
151 |             self.logger.info("Created Azure OpenAI client")
152 |         except Exception as e:
153 |             self.logger.error(f"Failed to create Azure OpenAI client: {e}")
154 |             return None
155 | 
156 |         drive_root = data_folder / self.engine_id / "drive"
157 |         metadata_drive_root = data_folder / self.engine_id / "metadata"
158 | 
159 |         drive_root.mkdir(parents=True, exist_ok=True)
160 |         metadata_drive_root.mkdir(parents=True, exist_ok=True)
161 | 
162 |         self.logger.info(f"Initializing engine with ID: {self.engine_id}")
163 |         self.logger.debug(f"Drive root: {drive_root}", {"drive_root": str(drive_root)})
164 | 
165 |         try:
166 |             engine = Engine(
167 |                 engine_id=self.engine_id,
168 |                 message_history_provider=self.history.get_message_list,
169 |                 drive_root=drive_root,
170 |                 metadata_drive_root=metadata_drive_root,
171 |                 skills=[
172 |                     (
173 |                         MetaSkill,
174 |                         MetaSkillConfig(
175 |                             name="meta",
176 |                             drive=drive.subdrive("meta"),
177 |                             language_model=language_model,
178 |                         ),
179 |                     ),
180 |                     (
181 |                         CommonSkill,
182 |                         CommonSkillConfig(
183 |                             name="common",
184 |                             language_model=language_model,
185 |                             drive=drive.subdrive("common"),
186 |                             bing_subscription_key=settings.bing_subscription_key,
187 |                             bing_search_url=settings.bing_search_url,
188 |                         ),
189 |                     ),
190 |                     (
191 |                         PosixSkill,
192 |                         PosixSkillConfig(
193 |                             name="posix",
194 |                             sandbox_dir=data_folder / self.engine_id,
195 |                             mount_dir="/mnt/data",
196 |                         ),
197 |                     ),
198 |                     (
199 |                         ResearchSkill,
200 |                         ResearchSkillConfig(
201 |                             name="research",
202 |                             language_model=language_model,
203 |                             drive=drive.subdrive("research"),
204 |                         ),
205 |                     ),
206 |                     (
207 |                         WebResearchSkill,
208 |                         WebResearchSkillConfig(
209 |                             name="web_research",
210 |                             language_model=language_model,
211 |                             reasoning_language_model=reasoning_language_model,
212 |                             drive=drive.subdrive("web_research"),
213 |                         ),
214 |                     ),
215 |                     # Additional skills would be loaded based on config
216 |                 ],
217 |             )
218 |             self.logger.info("Engine initialized successfully with 4 skills")
219 |             return engine
220 |         except Exception as e:
221 |             self.logger.error(f"Failed to initialize engine: {e}")
222 |             return None
223 | 
224 |     async def monitor_events(self):
225 |         """Monitor and process engine events."""
226 |         if not self.engine:
227 |             self.logger.error("Engine not initialized before monitoring events")
228 |             return
229 | 
230 |         try:
231 |             self.logger.info("Starting event monitoring")
232 | 
233 |             async for event in self.engine.events:
234 |                 event_type = type(event).__name__.replace("Event", "")
235 |                 event_meta: dict[str, Any] = {"event_type": event_type}
236 |                 if event.message:
237 |                     # Check if this is a message event (ask_user prompt)
238 |                     if isinstance(event, skill_events.MessageEvent):
239 |                         # Put the message in the queue for handling
240 |                         await self.user_interaction_queue.put(event.message)
241 |                         # Record the message in conversation history
242 |                         self.history.add_message(event.message, ParticipantRole.assistant)
243 |                         self.user_interaction_active.set()
244 | 
245 |                         # Log the event for user interaction
246 |                         if event.metadata:
247 |                             event_meta.update({"event_metadata": event.metadata})
248 |                         self.logger.info(f"User interaction requested: {event.message}", event_meta)
249 |                     elif isinstance(event, skill_events.StatusUpdatedEvent):
250 |                         # Log status updates
251 |                         self.logger.info(f"Status updated: {event.message}", {"event_metadata": event.metadata})
252 |                     else:
253 |                         # Log other events at debug level
254 |                         if event.metadata:
255 |                             event_meta.update({"event_metadata": event.metadata})
256 |                         self.logger.debug(f"{event_type}: {event.message}", event_meta)
257 |         except Exception as e:
258 |             self.logger.error(f"Error monitoring events: {e}")
259 | 
260 |     async def handle_user_interactions(self):
261 |         """Handle interactive user prompts during routine execution."""
262 |         if not self.engine:
263 |             self.logger.error("Engine not initialized before handling user interactions")
264 |             return
265 | 
266 |         try:
267 |             self.logger.info("Starting user interaction handler")
268 |             while True:
269 |                 # Wait for a prompt from ask_user
270 |                 prompt = await self.user_interaction_queue.get()
271 | 
272 |                 if self.non_interactive:
273 |                     # In non-interactive mode, fail the routine
274 |                     self.logger.error("Routine requires user input but --non-interactive was specified")
275 |                     response = "ERROR: Non-interactive mode enabled but user input was requested"
276 | 
277 |                     # Check if engine is initialized before calling resume_routine
278 |                     if self.engine:
279 |                         await self.engine.resume_routine(response)
280 |                     else:
281 |                         self.logger.error("Cannot resume routine - engine not initialized")
282 | 
283 |                     # Record the error response
284 |                     self.history.add_message(response, ParticipantRole.user)
285 |                     self.user_interaction_queue.task_done()
286 |                     self.user_interaction_active.clear()
287 |                     continue
288 | 
289 |                 # Prompt the user for input via stderr - this bypasses quiet mode
290 |                 self.logger.prompt_user(prompt)
291 | 
292 |                 while True:
293 |                     # Read from stdin in a way that doesn't block the event loop
294 |                     response = await asyncio.to_thread(sys.stdin.readline)
295 |                     response = response.strip()
296 | 
297 |                     # Check for special commands
298 |                     if response.lower() == ":q":
299 |                         self.logger.info("User requested to quit")
300 |                         raise KeyboardInterrupt("User requested to quit")
301 |                     elif response.lower() == ":h":
302 |                         self._show_help()
303 |                         continue
304 |                     elif response.lower() == ":s":
305 |                         self._show_status()
306 |                         continue
307 |                     elif response.lower() == ":history":
308 |                         self.history.display_history()
309 |                         print("Enter your response: ", file=sys.stderr, end="", flush=True)
310 |                         continue
311 | 
312 |                     # Got a valid response
313 |                     break
314 | 
315 |                 # Record the user's response in conversation history
316 |                 self.history.add_message(response, ParticipantRole.user)
317 |                 self.logger.debug(f"User provided response: {response[:50]}...")
318 | 
319 |                 # Resume the routine with the user's input
320 |                 if self.engine:
321 |                     await self.engine.resume_routine(response)
322 |                 else:
323 |                     self.logger.error("Cannot resume routine - engine not initialized")
324 | 
325 |                 # Mark this task as done
326 |                 self.user_interaction_queue.task_done()
327 |                 self.user_interaction_active.clear()
328 |         except KeyboardInterrupt:
329 |             # Propagate the interrupt
330 |             raise
331 |         except asyncio.CancelledError:
332 |             # Task was cancelled, clean exit
333 |             self.logger.debug("User interaction handler cancelled")
334 |             pass
335 |         except Exception as e:
336 |             self.logger.error(f"Error handling user interaction: {e}")
337 | 
338 |     def _show_help(self):
339 |         """Display help for interactive commands."""
340 |         self.logger.info("\nHelp:")
341 |         self.logger.info("  :q - Quit the routine")
342 |         self.logger.info("  :h - Show this help message")
343 |         self.logger.info("  :s - Show current routine status")
344 |         self.logger.info("  :history - Show conversation history")
345 |         print("Enter your response: ", file=sys.stderr, end="", flush=True)
346 | 
347 |     def _show_status(self):
348 |         """Display current routine status."""
349 |         elapsed = int(time.time() - self.start_time)
350 |         self.logger.info("\nCurrent routine status:")
351 |         self.logger.info(f"  Routine: {self.routine_name}")
352 |         self.logger.info(f"  Parameters: {json.dumps(self.params, indent=2)}")
353 |         self.logger.info(f"  Elapsed time: {elapsed} seconds")
354 |         self.logger.info(f"  Timeout: {self.timeout_seconds} seconds")
355 |         print("Enter your response: ", file=sys.stderr, end="", flush=True)
356 | 
357 |     async def run(self) -> str:
358 |         """Run the routine with monitoring and user interaction handling."""
359 |         self.logger.info(f"Starting routine: {self.routine_name}")
360 | 
361 |         # Initialize engine
362 |         self.engine = self.initialize_engine()
363 |         if not self.engine:
364 |             self.logger.error("Failed to initialize engine")
365 |             return "ERROR: Failed to initialize engine"
366 | 
367 |         # Verify the routine exists
368 |         try:
369 |             available_routines = self.engine.list_routines()
370 |             if self.routine_name not in available_routines:
371 |                 self.logger.error(f"Routine '{self.routine_name}' not found")
372 |                 available = "\n  ".join(sorted(available_routines))
373 |                 return f"ERROR: Routine '{self.routine_name}' not found. Available routines:\n  {available}"
374 |         except AttributeError:
375 |             self.logger.error("Engine does not support listing routines")
376 |             return "ERROR: Engine does not support listing routines"
377 | 
378 |         # Start monitoring tasks
379 |         monitor_task = asyncio.create_task(self.monitor_events())
380 |         interaction_task = asyncio.create_task(self.handle_user_interactions())
381 | 
382 |         # Track start time for timeout reporting
383 |         self.start_time = time.time()
384 | 
385 |         try:
386 |             # Run the routine with timeout
387 |             self.logger.info(f"Running {self.routine_name} with params: {self.params}")
388 |             try:
389 |                 result = await asyncio.wait_for(
390 |                     self.engine.run_routine(self.routine_name, **self.params), timeout=self.timeout_seconds
391 |                 )
392 |                 elapsed = int(time.time() - self.start_time)
393 |                 self.logger.info(f"Routine completed successfully in {elapsed} seconds.")
394 | 
395 |                 # Record the final result in conversation history
396 |                 self.history.add_message(str(result), ParticipantRole.assistant)
397 | 
398 |                 return result
399 |             except asyncio.TimeoutError:
400 |                 elapsed = int(time.time() - self.start_time)
401 |                 error_msg = f"Routine timed out after {elapsed} seconds (limit: {self.timeout_seconds}s)"
402 |                 self.logger.error(error_msg)
403 | 
404 |                 # Record the timeout error in conversation history
405 |                 self.history.add_message(f"ERROR: {error_msg}", ParticipantRole.service)
406 | 
407 |                 return f"ERROR: Routine execution timed out after {self.timeout_seconds} seconds"
408 | 
409 |         except KeyboardInterrupt:
410 |             error_msg = "Operation cancelled by user"
411 |             self.logger.warning(error_msg)
412 | 
413 |             # Record the cancellation in conversation history
414 |             self.history.add_message(f"ERROR: {error_msg}", ParticipantRole.service)
415 | 
416 |             return f"ERROR: {error_msg}"
417 |         except Exception as e:
418 |             error_msg = f"Failed to run routine: {str(e)}"
419 |             self.logger.error(error_msg, {"exception": traceback.format_exc()})
420 | 
421 |             # Record the error in conversation history
422 |             self.history.add_message(f"ERROR: {error_msg}", ParticipantRole.service)
423 | 
424 |             return f"ERROR: {error_msg}"
425 |         finally:
426 |             # Clean up the tasks
427 |             for task in [monitor_task, interaction_task]:
428 |                 if not task.done():
429 |                     task.cancel()
430 |                     try:
431 |                         await asyncio.wait_for(task, timeout=2.0)
432 |                     except (asyncio.CancelledError, asyncio.TimeoutError):
433 |                         pass
434 | 
435 |             # If we're in the middle of a user interaction, print a message
436 |             if self.user_interaction_active.is_set():
437 |                 self.logger.warning("Routine execution ended while waiting for user input.")
438 | 
439 |             # Finalize logging
440 |             self.logger.finalize()
441 | 
442 | 
443 | def find_skills_home_dir() -> Path:
444 |     """Find the skills home directory based on environment or defaults."""
445 |     # Check environment variable first
446 |     if env_home_dir := os.environ.get("SKILLS_HOME_DIR"):
447 |         return Path(env_home_dir)
448 | 
449 |     # Check current directory
450 |     cwd_skills_home = Path.cwd() / ".skills"
451 |     if cwd_skills_home.exists() and cwd_skills_home.is_dir():
452 |         return cwd_skills_home
453 | 
454 |     # Fall back to home directory
455 |     home_skills_dir = Path.home() / ".skills"
456 |     # Create directory if it doesn't exist
457 |     home_skills_dir.mkdir(parents=True, exist_ok=True)
458 | 
459 |     # Ensure config and data subdirectories exist
460 |     (home_skills_dir / "config").mkdir(exist_ok=True)
461 |     (home_skills_dir / "data").mkdir(exist_ok=True)
462 | 
463 |     return home_skills_dir
464 | 
465 | 
466 | def parse_args() -> Tuple[str, Dict[str, Any], Path, str, bool, bool]:
467 |     """Parse command line arguments."""
468 |     parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter)
469 | 
470 |     # Allow routine name to be optional when using --list or --usage
471 |     parser.add_argument(
472 |         "routine_name", nargs="?", default="", help="Name of the routine to run (e.g., 'research2.research')"
473 |     )
474 | 
475 |     parser.add_argument("--list", action="store_true", help="List all available routines")
476 | 
477 |     parser.add_argument("--usage", action="store_true", help="Show detailed usage information for all routines")
478 | 
479 |     parser.add_argument(
480 |         "--home", help="Path to skills home directory (default: .skills in current or home dir)", type=Path
481 |     )
482 | 
483 |     parser.add_argument(
484 |         "--engine", help="Engine ID to use (default: 'cli')", default=os.environ.get("SKILLS_ENGINE_ID", "cli")
485 |     )
486 | 
487 |     parser.add_argument(
488 |         "--param", action="append", help="Parameter in KEY=VALUE format (can be used multiple times)", default=[]
489 |     )
490 | 
491 |     parser.add_argument(
492 |         "--non-interactive",
493 |         action="store_true",
494 |         help="Run in non-interactive mode. The routine will fail if it needs user input.",
495 |     )
496 | 
497 |     parser.add_argument(
498 |         "--timeout", type=int, default=600, help="Timeout in seconds for the routine execution (default: 600)"
499 |     )
500 | 
501 |     parser.add_argument("--quiet", action="store_true", help="Suppress log output to stderr in interactive mode")
502 | 
503 |     args = parser.parse_args()
504 | 
505 |     # Process skills home directory
506 |     skills_home_dir = args.home if args.home else find_skills_home_dir()
507 | 
508 |     # We have special commands like --list and --usage
509 |     if args.list:
510 |         return "__list__", {}, skills_home_dir, args.engine, args.non_interactive, args.quiet
511 | 
512 |     if args.usage:
513 |         return "__usage__", {}, skills_home_dir, args.engine, args.non_interactive, args.quiet
514 | 
515 |     # No routine specified and no special command
516 |     if not args.routine_name:
517 |         parser.print_help()
518 |         sys.exit(1)
519 | 
520 |     # Process parameters
521 |     params = {}
522 |     for param in args.param:
523 |         try:
524 |             key, value = param.split("=", 1)
525 |             # Try to parse as JSON for complex types
526 |             try:
527 |                 value = json.loads(value)
528 |             except json.JSONDecodeError:
529 |                 pass  # Keep as string if not valid JSON
530 |             params[key] = value
531 |         except ValueError:
532 |             print(f"Warning: Ignoring invalid parameter format: {param}", file=sys.stderr)
533 | 
534 |     # Store non-interactive mode and timeout in params so they can be accessed by run-routine
535 |     params["__non_interactive"] = args.non_interactive
536 |     params["__timeout"] = args.timeout
537 | 
538 |     return args.routine_name, params, skills_home_dir, args.engine, args.non_interactive, args.quiet
539 | 
540 | 
541 | def setup_console_input():
542 |     """
543 |     Configure input handling for interactive use even when stdin is redirected.
544 |     Returns the original stdin if modified.
545 |     """
546 |     # If stdin is already a TTY, no need to change anything
547 |     if sys.stdin.isatty():
548 |         return None
549 | 
550 |     # Save the original stdin for later restoration
551 |     original_stdin = sys.stdin
552 | 
553 |     # Try to open a direct connection to the terminal
554 |     try:
555 |         # This works on Unix-like systems
556 |         tty_stdin = open("/dev/tty", "r")
557 |         sys.stdin = tty_stdin
558 |         return original_stdin
559 |     except Exception:
560 |         # For Windows, we need a different approach
561 |         if os.name == "nt":
562 |             try:
563 |                 # Try to use msvcrt for Windows
564 |                 if importlib.util.find_spec("msvcrt"):
565 |                     # We can't actually replace stdin on Windows easily,
566 |                     # but we'll set a flag to use a custom input method
567 |                     print("Warning: Using Windows console input handling", file=sys.stderr)
568 |                     return original_stdin
569 |             except ImportError:
570 |                 pass
571 | 
572 | 
573 | async def main() -> None:
574 |     """Main entry point for the command."""
575 |     # Parse arguments
576 |     routine_name, params, skills_home_dir, engine_id, non_interactive, quiet = parse_args()
577 | 
578 |     # Generate run ID
579 |     timestamp: str = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
580 |     run_id = f"{timestamp}_{uuid.uuid4().hex[:8]}"
581 | 
582 |     # Create the logger
583 |     logger = SkillLogger(skills_home_dir=skills_home_dir, run_id=run_id, interactive=not non_interactive, quiet=quiet)
584 | 
585 |     # Log startup information
586 |     logger.info(f"Run ID: {run_id}")
587 |     logger.info(f"Skills home directory: {skills_home_dir}")
588 | 
589 |     # Create history object for all paths
590 |     history = ConversationHistory(logger)
591 | 
592 |     # Check if there's input on stdin
593 |     input_text = None
594 |     # Read from the original stdin for the initial input if stdin was redirected
595 |     if "original_stdin" in globals() and globals()["original_stdin"] is not None:
596 |         input_text = globals()["original_stdin"].read().strip()
597 |     elif not sys.stdin.isatty():
598 |         # This case should generally not happen since we handle stdin redirection
599 |         # in the __main__ block, but just in case
600 |         input_text = sys.stdin.read().strip()
601 | 
602 |     # Create a runner for initializing the engine
603 |     runner = RoutineRunner(
604 |         routine_name=routine_name,
605 |         params=params,
606 |         input_text=input_text,
607 |         skills_home_dir=skills_home_dir,
608 |         engine_id=engine_id,
609 |         history=history,
610 |         logger=logger,
611 |     )
612 | 
613 |     engine = runner.initialize_engine()
614 |     if not engine:
615 |         logger.error("Failed to initialize engine")
616 |         return
617 | 
618 |     # Special commands
619 |     if routine_name == "__list__":
620 |         try:
621 |             logger.info("Listing available routines")
622 |             available_routines = sorted(engine.list_routines())
623 |             if available_routines:
624 |                 print("Available routines:")
625 |                 for routine in available_routines:
626 |                     print(f"  {routine}")
627 |             else:
628 |                 print("No routines available.")
629 |         except AttributeError:
630 |             logger.error("Engine does not support listing routines")
631 |             print("ERROR: Engine does not support listing routines", file=sys.stderr)
632 |         finally:
633 |             logger.finalize()
634 |         return
635 | 
636 |     if routine_name == "__usage__":
637 |         try:
638 |             logger.info("Retrieving routine usage information")
639 |             usage_text = engine.routines_usage()
640 |             if usage_text:
641 |                 print(usage_text)
642 |             else:
643 |                 print("No routine usage information available.")
644 |         except AttributeError:
645 |             logger.error("Engine does not support retrieving routine usage")
646 |             print("ERROR: Engine does not support retrieving routine usage", file=sys.stderr)
647 |         finally:
648 |             logger.finalize()
649 |         return
650 | 
651 |     # Announce the start of execution
652 |     logger.info(f"Executing routine: {routine_name}")
653 |     if input_text:
654 |         input_preview = input_text[:100] + "..." if len(input_text) > 100 else input_text
655 |         logger.info(f"Input text: {input_preview}")
656 | 
657 |     # Run the routine
658 |     result = await runner.run()
659 | 
660 |     # Output result to stdout
661 |     print(result)
662 | 
663 | 
664 | def entry_point():
665 |     """Entry point for the command-line interface when installed as a package."""
666 | 
667 |     # Need to import for dynamic import checking on Windows
668 |     import importlib.util  # noqa: F401
669 | 
670 |     # Save the program start time
671 |     program_start_time = time.time()
672 | 
673 |     # Set up console input handling
674 |     original_stdin = None
675 | 
676 |     try:
677 |         # Configure input handling for interactive use
678 |         original_stdin = setup_console_input()
679 | 
680 |         # Make the original stdin available to the main function
681 |         if original_stdin:
682 |             globals()["original_stdin"] = original_stdin
683 | 
684 |         # Run the main async function
685 |         asyncio.run(main())
686 | 
687 |         # Show execution time
688 |         execution_time = time.time() - program_start_time
689 |         print(f"Total execution time: {execution_time:.2f} seconds", file=sys.stderr)
690 | 
691 |     except KeyboardInterrupt:
692 |         print("\nOperation cancelled by user", file=sys.stderr)
693 |         sys.exit(130)
694 |     except Exception as e:
695 |         print(f"Error: {e}", file=sys.stderr)
696 |         # Print traceback for debugging
697 |         traceback.print_exc(file=sys.stderr)
698 |         sys.exit(1)
699 |     finally:
700 |         # Restore original stdin if we modified it
701 |         if original_stdin:
702 |             try:
703 |                 original_stdin.close()
704 |             except Exception:
705 |                 pass
706 |             sys.stdin = original_stdin
707 | 
708 | 
709 | if __name__ == "__main__":
710 |     # Need to import for dynamic import checking on Windows
711 |     import importlib.util
712 | 
713 |     # Save the program start time
714 |     program_start_time = time.time()
715 | 
716 |     # Set up console input handling
717 |     original_stdin = None
718 | 
719 |     try:
720 |         # Configure input handling for interactive use
721 |         original_stdin = setup_console_input()
722 | 
723 |         # Make the original stdin available to the main function
724 |         if original_stdin:
725 |             globals()["original_stdin"] = original_stdin
726 | 
727 |         # Run the main async function
728 |         asyncio.run(main())
729 | 
730 |         # Show execution time
731 |         execution_time = time.time() - program_start_time
732 |         print(f"Total execution time: {execution_time:.2f} seconds", file=sys.stderr)
733 | 
734 |     except KeyboardInterrupt:
735 |         print("\nOperation cancelled by user", file=sys.stderr)
736 |         sys.exit(130)
737 |     except Exception as e:
738 |         print(f"Error: {e}", file=sys.stderr)
739 |         # Print traceback for debugging
740 |         traceback.print_exc(file=sys.stderr)
741 |         sys.exit(1)
742 |     finally:
743 |         # Restore original stdin if we modified it
744 |         if original_stdin:
745 |             try:
746 |                 original_stdin.close()
747 |             except Exception:
748 |                 pass
749 |             sys.stdin = original_stdin
750 | 
```
Page 110/145FirstPrevNextLast