#
tokens: 49041/50000 3/1784 files (page 97/145)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 97 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

--------------------------------------------------------------------------------
/mcp-servers/mcp-server-filesystem-edit/mcp_server_filesystem_edit/tools/edit.py:
--------------------------------------------------------------------------------

```python
  1 | # Copyright (c) Microsoft. All rights reserved.
  2 | 
  3 | import json
  4 | import logging
  5 | import re
  6 | 
  7 | from mcp.server.fastmcp import Context
  8 | from mcp_extensions.llm.chat_completion import chat_completion
  9 | from mcp_extensions.llm.helpers import compile_messages
 10 | from mcp_extensions.llm.llm_types import ChatCompletionRequest, ChatCompletionResponse, MessageT, UserMessage
 11 | 
 12 | from mcp_server_filesystem_edit import settings
 13 | from mcp_server_filesystem_edit.prompts.latex_edit import LATEX_EDIT_REASONING_MESSAGES
 14 | from mcp_server_filesystem_edit.prompts.markdown_draft import MD_DRAFT_REASONING_MESSAGES
 15 | from mcp_server_filesystem_edit.prompts.markdown_edit import (
 16 |     MARKDOWN_EDIT_FORMAT_INSTRUCTIONS,
 17 |     MD_EDIT_CHANGES_MESSAGES,
 18 |     MD_EDIT_CONVERT_MESSAGES,
 19 |     MD_EDIT_REASONING_MESSAGES,
 20 |     MD_EDIT_TOOL_DEF,
 21 |     MD_EDIT_TOOL_NAME,
 22 |     SEND_MESSAGE_TOOL_DEF,
 23 |     SEND_MESSAGE_TOOL_NAME,
 24 |     WORD_EDIT_FORMAT_INSTRUCTIONS,
 25 | )
 26 | from mcp_server_filesystem_edit.prompts.powerpoint_edit import PPT_EDIT_REASONING_MESSAGES, PPT_EDIT_TOOL_DEF
 27 | from mcp_server_filesystem_edit.tools.edit_adapters.common import execute_tools, format_blocks_for_llm
 28 | from mcp_server_filesystem_edit.tools.edit_adapters.latex import blockify as latex_blockify
 29 | from mcp_server_filesystem_edit.tools.edit_adapters.latex import unblockify as latex_unblockify
 30 | from mcp_server_filesystem_edit.tools.edit_adapters.markdown import blockify as markdown_blockify
 31 | from mcp_server_filesystem_edit.tools.edit_adapters.markdown import unblockify as markdown_unblockify
 32 | from mcp_server_filesystem_edit.tools.helpers import TokenizerOpenAI, format_chat_history
 33 | from mcp_server_filesystem_edit.types import Block, CustomContext, EditOutput, FileOpRequest, FileOpTelemetry
 34 | 
 35 | logger = logging.getLogger(__name__)
 36 | 
 37 | # region CommonEdit
 38 | 
 39 | 
 40 | class CommonEdit:
 41 |     def __init__(self) -> None:
 42 |         self.telemetry = FileOpTelemetry()
 43 |         self.tokenizer = TokenizerOpenAI(model="gpt-4o")
 44 | 
 45 |     async def blockify(self, request: FileOpRequest) -> list[Block]:
 46 |         if request.file_type == "latex":
 47 |             blocks = latex_blockify(request.file_content)
 48 |         else:
 49 |             blocks = markdown_blockify(request.file_content)
 50 |         return blocks
 51 | 
 52 |     async def unblockify(self, request: FileOpRequest, blocks: list[Block]) -> str:
 53 |         if request.file_type == "latex":
 54 |             unblockified_doc = latex_unblockify(blocks)
 55 |         else:
 56 |             unblockified_doc = markdown_unblockify(blocks)
 57 |         return unblockified_doc
 58 | 
 59 |     async def take_draft_path(self, request: FileOpRequest) -> bool:
 60 |         """
 61 |         Decides if we should take a separate path that will simply use a single prompt
 62 |         that rewrites the document in a single step rather than using editing logic.
 63 | 
 64 |         Returns True if we should take the draft path, False otherwise.
 65 |         """
 66 |         if request.file_type == "latex":
 67 |             return False
 68 |         else:
 69 |             # If the document is over the rewrite threshold tokens, we do not take the draft path.
 70 |             num_tokens = self.tokenizer.num_tokens_in_str(request.file_content)
 71 |             if num_tokens > settings.rewrite_threshold:
 72 |                 return False
 73 |         return True
 74 | 
 75 |     async def get_draft_response(self, request: FileOpRequest) -> str:
 76 |         """
 77 |         Get the rewritten document
 78 |         """
 79 |         chat_history = ""
 80 |         if request.request_type == "dev" and isinstance(request.context, CustomContext):
 81 |             chat_history = format_chat_history(request.context.chat_history)
 82 |         context = ""
 83 |         if request.request_type == "dev" and isinstance(request.context, CustomContext):
 84 |             context = request.context.additional_context
 85 |         messages = compile_messages(
 86 |             messages=MD_DRAFT_REASONING_MESSAGES,
 87 |             variables={
 88 |                 "knowledge_cutoff": settings.knowledge_cutoff,
 89 |                 "current_date": settings.current_date_func(),
 90 |                 "task": request.task,
 91 |                 "context": context,
 92 |                 "document": request.file_content,
 93 |                 "chat_history": chat_history,
 94 |                 "format_instructions": (
 95 |                     WORD_EDIT_FORMAT_INSTRUCTIONS if request.file_type == "word" else MARKDOWN_EDIT_FORMAT_INSTRUCTIONS
 96 |                 ),
 97 |             },
 98 |         )
 99 |         mcp_messages = messages
100 |         if request.request_type == "mcp" and isinstance(request.context, Context):
101 |             mcp_messages = [messages[0]]  # Developer message
102 |             mcp_messages.append(UserMessage(content=json.dumps({"variable": "history_messages"})))
103 |             mcp_messages.append(messages[3])  # Document message
104 | 
105 |         reasoning_response = await chat_completion(
106 |             request=ChatCompletionRequest(
107 |                 messages=mcp_messages,
108 |                 model=settings.draft_path_model,
109 |                 max_completion_tokens=20000,
110 |                 temperature=1,
111 |             ),
112 |             provider=request.request_type,
113 |             client=request.context if request.request_type == "mcp" else request.chat_completion_client,  # type: ignore
114 |         )
115 |         self.telemetry.reasoning_latency = reasoning_response.response_duration
116 |         draft = reasoning_response.choices[0].message.content
117 |         # Look for content between <new_document> tags, otherwise return the entire response as the doc.
118 |         pattern = r"<new_document>(.*?)</new_document>"
119 |         match = re.search(pattern, draft, re.DOTALL)
120 |         if match:
121 |             draft = match.group(1).strip()
122 |         return draft
123 | 
124 |     async def construct_reasoning_prompt(self, request: FileOpRequest, blockified_doc: list[Block]) -> list[MessageT]:
125 |         doc_for_llm = await format_blocks_for_llm(blockified_doc)
126 | 
127 |         chat_history = ""
128 |         if request.request_type == "dev" and isinstance(request.context, CustomContext):
129 |             chat_history = format_chat_history(request.context.chat_history)
130 | 
131 |         context = ""
132 |         if request.request_type == "dev" and isinstance(request.context, CustomContext):
133 |             context = request.context.additional_context
134 | 
135 |         reasoning_messages = compile_messages(
136 |             messages=LATEX_EDIT_REASONING_MESSAGES if request.file_type == "latex" else MD_EDIT_REASONING_MESSAGES,
137 |             variables={
138 |                 "knowledge_cutoff": settings.knowledge_cutoff,
139 |                 "current_date": settings.current_date_func(),
140 |                 "task": request.task,
141 |                 "context": context,
142 |                 "document": doc_for_llm,
143 |                 "chat_history": chat_history,
144 |                 "format_instructions": (
145 |                     WORD_EDIT_FORMAT_INSTRUCTIONS if request.file_type == "word" else MARKDOWN_EDIT_FORMAT_INSTRUCTIONS
146 |                 ),
147 |             },
148 |         )
149 |         return reasoning_messages
150 | 
151 |     async def get_reasoning_response(self, request: FileOpRequest, messages: list[MessageT]) -> str:
152 |         mcp_messages = messages
153 |         if request.request_type == "mcp" and isinstance(request.context, Context):
154 |             mcp_messages = [messages[0]]  # Developer message
155 |             mcp_messages.append(UserMessage(content=json.dumps({"variable": "history_messages"})))
156 |             mcp_messages.append(messages[3])  # Document message
157 |         reasoning_response = await chat_completion(
158 |             request=ChatCompletionRequest(
159 |                 messages=mcp_messages,
160 |                 model=settings.edit_model,
161 |                 max_completion_tokens=20000,
162 |                 reasoning_effort="high",
163 |             ),
164 |             provider=request.request_type,
165 |             client=request.context if request.request_type == "mcp" else request.chat_completion_client,  # type: ignore
166 |         )
167 |         self.telemetry.reasoning_latency = reasoning_response.response_duration
168 |         reasoning = reasoning_response.choices[0].message.content
169 |         return reasoning
170 | 
171 |     async def construct_convert_prompt(self, reasoning: str) -> list[MessageT]:
172 |         convert_messages = compile_messages(
173 |             messages=MD_EDIT_CONVERT_MESSAGES,
174 |             variables={"reasoning": reasoning},
175 |         )
176 |         return convert_messages
177 | 
178 |     async def get_convert_response(self, request: FileOpRequest, messages: list[MessageT]) -> ChatCompletionResponse:
179 |         chat_completion_request = ChatCompletionRequest(
180 |             messages=messages,
181 |             model=settings.convert_tool_calls_model,
182 |             temperature=0,
183 |             max_completion_tokens=8000,
184 |             tools=[MD_EDIT_TOOL_DEF, SEND_MESSAGE_TOOL_DEF],
185 |             tool_choice="required",
186 |             parallel_tool_calls=False,
187 |         )
188 |         convert_response = await chat_completion(
189 |             request=chat_completion_request,
190 |             provider=request.request_type,
191 |             client=request.context if request.request_type == "mcp" else request.chat_completion_client,  # type: ignore
192 |         )
193 |         self.telemetry.convert_latency = convert_response.response_duration
194 |         return convert_response
195 | 
196 |     async def execute_tool_calls(
197 |         self, request: FileOpRequest, convert_response: ChatCompletionResponse
198 |     ) -> tuple[str, str]:
199 |         updated_doc_markdown = request.file_content
200 |         output_message = ""
201 |         if convert_response.choices[0].message.tool_calls:
202 |             tool_call = convert_response.choices[0].message.tool_calls[0].function
203 |             logger.info(f"Tool call:\n{tool_call}")
204 |             # If the the model called the send_message, don't update the doc and return the message
205 |             if tool_call.name == SEND_MESSAGE_TOOL_NAME:
206 |                 output_message = settings.doc_editor_prefix + convert_response.choices[0].message.content
207 |             elif tool_call.name == MD_EDIT_TOOL_NAME:
208 |                 tool_args = tool_call.arguments
209 |                 blocks = await self.blockify(request)
210 |                 blocks = execute_tools(blocks=blocks, edit_tool_call={"name": tool_call.name, "arguments": tool_args})
211 |                 updated_doc_markdown = await self.unblockify(request, blocks)
212 |         else:
213 |             output_message = (
214 |                 settings.doc_editor_prefix + "Something went wrong when editing the document and no changes were made."
215 |             )
216 |         return updated_doc_markdown, output_message
217 | 
218 |     async def run_change_summary(self, before_doc: str, after_doc: str, edit_request: FileOpRequest) -> str:
219 |         change_summary_messages = compile_messages(
220 |             messages=MD_EDIT_CHANGES_MESSAGES,
221 |             variables={
222 |                 "before_doc": before_doc,
223 |                 "after_doc": after_doc,
224 |             },
225 |         )
226 |         change_summary_response = await chat_completion(
227 |             request=ChatCompletionRequest(
228 |                 messages=change_summary_messages,
229 |                 model=settings.summarization_model,
230 |                 max_completion_tokens=1000,
231 |             ),
232 |             provider=edit_request.request_type,
233 |             client=edit_request.context if edit_request.request_type == "mcp" else edit_request.chat_completion_client,  # type: ignore
234 |         )
235 |         self.telemetry.change_summary_latency = change_summary_response.response_duration
236 | 
237 |         change_summary = change_summary_response.choices[0].message.content
238 |         change_summary = settings.doc_editor_prefix + change_summary
239 |         return change_summary
240 | 
241 |     async def run(self, request: FileOpRequest) -> EditOutput:
242 |         """
243 |         Run the edit request and return the result.
244 |         """
245 |         self.telemetry.reset()
246 | 
247 |         if await self.take_draft_path(request):
248 |             logger.info("Taking draft path instead of editing.")
249 |             updated_doc_markdown = await self.get_draft_response(request)
250 |             output_message = ""
251 |             reasoning = ""
252 |             tool_calls = []
253 |         else:
254 |             blockified_doc = await self.blockify(request)
255 |             reasoning_messages = await self.construct_reasoning_prompt(request, blockified_doc)
256 |             reasoning = await self.get_reasoning_response(request, reasoning_messages)
257 |             logger.info(f"Reasoning:\n{reasoning}")
258 |             convert_messages = await self.construct_convert_prompt(reasoning)
259 |             convert_response = await self.get_convert_response(request, convert_messages)
260 |             tool_calls = convert_response.choices[0].message.tool_calls or []
261 |             updated_doc_markdown, output_message = await self.execute_tool_calls(request, convert_response)
262 | 
263 |         output = EditOutput(
264 |             change_summary="",
265 |             output_message=output_message,
266 |             new_content=updated_doc_markdown,
267 |             reasoning=reasoning,
268 |             tool_calls=tool_calls,
269 |             llm_latency=self.telemetry.reasoning_latency
270 |             + self.telemetry.convert_latency
271 |             + self.telemetry.change_summary_latency,
272 |         )
273 |         return output
274 | 
275 | 
276 | # endregion
277 | 
278 | # region PowerpointEdit
279 | 
280 | 
281 | class PowerpointEdit:
282 |     def __init__(self) -> None:
283 |         self.telemetry = FileOpTelemetry()
284 | 
285 |     async def blockify(self, request: FileOpRequest) -> list[Block]:
286 |         blocks = []
287 | 
288 |         slide_pattern = r'<slide\s+index=(?:"?(\d+)"?).*?</slide>'
289 | 
290 |         slide_matches = re.finditer(slide_pattern, request.file_content, re.DOTALL)
291 |         for match in slide_matches:
292 |             slide_content = match.group(0)
293 |             slide_index = match.group(1)
294 | 
295 |             try:
296 |                 slide_index = int(slide_index)
297 |             except ValueError:
298 |                 logger.error(f"Invalid slide number: {slide_index}")
299 |                 continue
300 | 
301 |             block = Block(
302 |                 id=slide_index,
303 |                 content=slide_content,
304 |             )
305 |             blocks.append(block)
306 |         return blocks
307 | 
308 |     async def unblockify(self, blocks: list[Block]) -> str:
309 |         return "".join(block.content for block in blocks)
310 | 
311 |     async def construct_reasoning_prompt(self, request: FileOpRequest, blockified_doc: list[Block]) -> list[MessageT]:
312 |         doc_for_llm = await format_blocks_for_llm(blockified_doc)
313 | 
314 |         chat_history = ""
315 |         if request.request_type == "dev" and isinstance(request.context, CustomContext):
316 |             chat_history = format_chat_history(request.context.chat_history)
317 | 
318 |         context = ""
319 |         if request.request_type == "dev" and isinstance(request.context, CustomContext):
320 |             context = request.context.additional_context
321 | 
322 |         reasoning_messages = compile_messages(
323 |             messages=PPT_EDIT_REASONING_MESSAGES,
324 |             variables={
325 |                 "knowledge_cutoff": settings.knowledge_cutoff,
326 |                 "current_date": settings.current_date_func(),
327 |                 "task": request.task,
328 |                 "context": context,
329 |                 "document": doc_for_llm,
330 |                 "chat_history": chat_history,
331 |             },
332 |         )
333 |         return reasoning_messages
334 | 
335 |     async def get_reasoning_response(self, request: FileOpRequest, messages: list[MessageT]) -> str:
336 |         mcp_messages = messages
337 |         if request.request_type == "mcp" and isinstance(request.context, Context):
338 |             mcp_messages = [messages[0]]  # Developer message
339 |             mcp_messages.append(UserMessage(content=json.dumps({"variable": "history_messages"})))
340 |             mcp_messages.append(messages[3])  # Document message
341 |         reasoning_response = await chat_completion(
342 |             request=ChatCompletionRequest(
343 |                 messages=mcp_messages,
344 |                 model=settings.edit_model,
345 |                 max_completion_tokens=20000,
346 |                 reasoning_effort="high",
347 |             ),
348 |             provider=request.request_type,
349 |             client=request.context if request.request_type == "mcp" else request.chat_completion_client,  # type: ignore
350 |         )
351 |         self.telemetry.reasoning_latency = reasoning_response.response_duration
352 |         reasoning = reasoning_response.choices[0].message.content
353 |         return reasoning
354 | 
355 |     async def construct_convert_prompt(self, reasoning: str) -> list[MessageT]:
356 |         convert_messages = compile_messages(
357 |             messages=MD_EDIT_CONVERT_MESSAGES,
358 |             variables={"reasoning": reasoning},
359 |         )
360 |         return convert_messages
361 | 
362 |     async def get_convert_response(self, request: FileOpRequest, messages: list[MessageT]) -> ChatCompletionResponse:
363 |         chat_completion_request = ChatCompletionRequest(
364 |             messages=messages,
365 |             model=settings.convert_tool_calls_model,
366 |             temperature=0,
367 |             max_completion_tokens=8000,
368 |             tools=[PPT_EDIT_TOOL_DEF, SEND_MESSAGE_TOOL_DEF],
369 |             tool_choice="required",
370 |             parallel_tool_calls=False,
371 |         )
372 |         convert_response = await chat_completion(
373 |             request=chat_completion_request,
374 |             provider=request.request_type,
375 |             client=request.context if request.request_type == "mcp" else request.chat_completion_client,  # type: ignore
376 |         )
377 |         self.telemetry.convert_latency = convert_response.response_duration
378 |         return convert_response
379 | 
380 |     async def execute_tool_calls(
381 |         self, request: FileOpRequest, convert_response: ChatCompletionResponse
382 |     ) -> tuple[str, str]:
383 |         updated_doc_markdown = request.file_content
384 |         output_message = ""
385 |         if convert_response.choices[0].message.tool_calls:
386 |             tool_call = convert_response.choices[0].message.tool_calls[0].function
387 |             logger.info(f"Tool call:\n{tool_call}")
388 |             # If the the model called the send_message, don't update the doc and return the message
389 |             if tool_call.name == SEND_MESSAGE_TOOL_NAME:
390 |                 output_message = settings.doc_editor_prefix + convert_response.choices[0].message.content
391 |             elif tool_call.name == MD_EDIT_TOOL_NAME:
392 |                 tool_args = tool_call.arguments
393 |                 blocks = await self.blockify(request)
394 |                 blocks = execute_tools(blocks=blocks, edit_tool_call={"name": tool_call.name, "arguments": tool_args})
395 |                 updated_doc_markdown = await self.unblockify(blocks)
396 |         else:
397 |             output_message = (
398 |                 settings.doc_editor_prefix + "Something went wrong when editing the document and no changes were made."
399 |             )
400 |         return updated_doc_markdown, output_message
401 | 
402 |     async def run_change_summary(self, before_doc: str, after_doc: str, edit_request: FileOpRequest) -> str:
403 |         change_summary_messages = compile_messages(
404 |             messages=MD_EDIT_CHANGES_MESSAGES,
405 |             variables={
406 |                 "before_doc": before_doc,
407 |                 "after_doc": after_doc,
408 |             },
409 |         )
410 |         change_summary_response = await chat_completion(
411 |             request=ChatCompletionRequest(
412 |                 messages=change_summary_messages,
413 |                 model=settings.summarization_model,
414 |                 max_completion_tokens=1000,
415 |             ),
416 |             provider=edit_request.request_type,
417 |             client=edit_request.context if edit_request.request_type == "mcp" else edit_request.chat_completion_client,  # type: ignore
418 |         )
419 |         self.telemetry.change_summary_latency = change_summary_response.response_duration
420 |         change_summary = change_summary_response.choices[0].message.content
421 |         change_summary = settings.doc_editor_prefix + change_summary
422 |         return change_summary
423 | 
424 |     async def run(self, request: FileOpRequest) -> EditOutput:
425 |         self.telemetry.reset()
426 |         blockified_doc = await self.blockify(request)
427 |         reasoning_messages = await self.construct_reasoning_prompt(request, blockified_doc)
428 |         reasoning = await self.get_reasoning_response(request, reasoning_messages)
429 |         logger.info(f"Reasoning:\n{reasoning}")
430 |         convert_messages = await self.construct_convert_prompt(reasoning)
431 |         convert_response = await self.get_convert_response(request, convert_messages)
432 |         tool_calls = convert_response.choices[0].message.tool_calls or []
433 |         updated_doc_markdown, output_message = await self.execute_tool_calls(request, convert_response)
434 |         change_summary = await self.run_change_summary(
435 |             before_doc=request.file_content,
436 |             after_doc=updated_doc_markdown,
437 |             edit_request=request,
438 |         )
439 |         output = EditOutput(
440 |             change_summary=change_summary,
441 |             output_message=output_message,
442 |             new_content=updated_doc_markdown,
443 |             reasoning=reasoning,
444 |             tool_calls=tool_calls,
445 |             llm_latency=self.telemetry.reasoning_latency
446 |             + self.telemetry.convert_latency
447 |             + self.telemetry.change_summary_latency,
448 |         )
449 |         return output
450 | 
451 | 
452 | # endregion
453 | 
```

--------------------------------------------------------------------------------
/workbench-service/semantic_workbench_service/db.py:
--------------------------------------------------------------------------------

```python
  1 | import datetime
  2 | import logging
  3 | import pathlib
  4 | import uuid
  5 | from contextlib import asynccontextmanager
  6 | from typing import Annotated, Any, AsyncIterator
  7 | from urllib.parse import urlparse
  8 | 
  9 | import sqlalchemy
 10 | import sqlalchemy.event
 11 | import sqlalchemy.orm
 12 | import sqlalchemy.orm.attributes
 13 | from sqlalchemy.dialects import postgresql
 14 | from sqlalchemy.ext.asyncio import AsyncEngine, async_sessionmaker, create_async_engine
 15 | from sqlmodel import Field, Relationship, Session, SQLModel, select
 16 | from sqlmodel.ext.asyncio.session import AsyncSession
 17 | 
 18 | from . import service_user_principals
 19 | from .config import DBSettings
 20 | 
 21 | # Download DB Browser for SQLite to view the database
 22 | # https://sqlitebrowser.org/dl/
 23 | 
 24 | logger = logging.getLogger(__name__)
 25 | 
 26 | 
 27 | def _date_time_nullable() -> Any:  # noqa: ANN401
 28 |     return Field(sa_column=sqlalchemy.Column(sqlalchemy.DateTime(timezone=True), nullable=True))
 29 | 
 30 | 
 31 | def date_time_default_to_now(index: bool | None = None) -> Any:  # noqa: ANN401
 32 |     return Field(
 33 |         sa_column=sqlalchemy.Column(
 34 |             sqlalchemy.DateTime(timezone=True),
 35 |             nullable=False,
 36 |             index=index,
 37 |             default=lambda: datetime.datetime.now(datetime.UTC),
 38 |         ),
 39 |         default_factory=lambda: datetime.datetime.now(datetime.UTC),
 40 |     )
 41 | 
 42 | 
 43 | class User(SQLModel, table=True):
 44 |     user_id: str = Field(primary_key=True)
 45 |     created_datetime: datetime.datetime = date_time_default_to_now()
 46 |     name: str
 47 |     image: str | None = None
 48 |     service_user: bool = False
 49 | 
 50 |     def on_update(self, session: Session) -> None:
 51 |         # update UserParticipants for this user
 52 |         participants = session.exec(select(UserParticipant).where(UserParticipant.user_id == self.user_id))
 53 |         for participant in participants:
 54 |             participant.name = self.name
 55 |             participant.image = self.image
 56 |             participant.service_user = self.service_user
 57 |             session.add(participant)
 58 | 
 59 | 
 60 | class AssistantServiceRegistration(SQLModel, table=True):
 61 |     assistant_service_id: str = Field(primary_key=True)
 62 |     created_by_user_id: str = Field(foreign_key="user.user_id")
 63 |     created_datetime: datetime.datetime = date_time_default_to_now()
 64 |     name: str
 65 |     description: str
 66 |     include_in_listing: bool = True
 67 |     api_key_name: str
 68 | 
 69 |     assistant_service_url: str = ""
 70 |     assistant_service_online_expiration_datetime: Annotated[datetime.datetime | None, _date_time_nullable()] = None
 71 |     assistant_service_online: bool = False
 72 | 
 73 |     related_created_by_user: User = Relationship(sa_relationship_kwargs={"lazy": "selectin"})
 74 | 
 75 | 
 76 | class Assistant(SQLModel, table=True):
 77 |     assistant_id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
 78 |     owner_id: str = Field(foreign_key="user.user_id", index=True)
 79 |     assistant_service_id: str = Field(
 80 |         sa_column=sqlalchemy.Column(
 81 |             sqlalchemy.ForeignKey(
 82 |                 "assistantserviceregistration.assistant_service_id",
 83 |                 name="fk_assistant_assistant_service_id_assistantserviceregistration",
 84 |                 ondelete="CASCADE",
 85 |             ),
 86 |             nullable=False,
 87 |         ),
 88 |     )
 89 |     template_id: str
 90 |     created_datetime: datetime.datetime = date_time_default_to_now()
 91 |     imported_from_assistant_id: uuid.UUID | None
 92 |     name: str
 93 |     image: str | None = None
 94 |     meta_data: dict[str, Any] = Field(sa_column=sqlalchemy.Column("metadata", sqlalchemy.JSON), default={})
 95 | 
 96 |     # this relationship is needed to enforce correct INSERT order by SQLModel
 97 |     related_owner: User = Relationship()
 98 |     related_assistant_service_registration: sqlalchemy.orm.Mapped[AssistantServiceRegistration] = Relationship(
 99 |         sa_relationship_kwargs={"lazy": "selectin"},
100 |     )
101 | 
102 |     def on_update(self, session: Session) -> None:
103 |         # update AssistantParticipants for this assistant
104 |         participants = session.exec(
105 |             select(AssistantParticipant).where(AssistantParticipant.assistant_id == self.assistant_id),
106 |         )
107 |         for participant in participants:
108 |             participant.name = self.name
109 |             participant.image = self.image
110 |             session.add(participant)
111 | 
112 | 
113 | class Conversation(SQLModel, table=True):
114 |     conversation_id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
115 |     created_datetime: datetime.datetime = date_time_default_to_now()
116 |     owner_id: str = Field(foreign_key="user.user_id")
117 |     title: str
118 |     meta_data: dict[str, Any] = Field(sa_column=sqlalchemy.Column("metadata", sqlalchemy.JSON), default={})
119 |     imported_from_conversation_id: uuid.UUID | None
120 | 
121 |     # this relationship is needed to enforce correct INSERT order by SQLModel
122 |     related_owner: sqlalchemy.orm.Mapped[User] = Relationship()
123 | 
124 | 
125 | class ConversationShare(SQLModel, table=True):
126 |     conversation_share_id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
127 |     conversation_id: uuid.UUID = Field(
128 |         sa_column=sqlalchemy.Column(
129 |             sqlalchemy.ForeignKey(
130 |                 "conversation.conversation_id",
131 |                 name="fk_file_conversation_id_conversation",
132 |                 ondelete="CASCADE",
133 |             ),
134 |             nullable=False,
135 |         ),
136 |     )
137 |     created_datetime: datetime.datetime = date_time_default_to_now()
138 |     owner_id: str = Field(foreign_key="user.user_id")
139 |     label: str
140 |     meta_data: dict[str, Any] = Field(sa_column=sqlalchemy.Column("metadata", sqlalchemy.JSON), default={})
141 | 
142 |     conversation_permission: str
143 | 
144 |     is_redeemable: bool = True
145 | 
146 |     # these relationships are needed to enforce correct INSERT order by SQLModel
147 |     related_owner: sqlalchemy.orm.Mapped[User] = Relationship(
148 |         sa_relationship_kwargs={"lazy": "selectin"},
149 |     )
150 |     related_conversation: sqlalchemy.orm.Mapped[Conversation] = Relationship(
151 |         sa_relationship_kwargs={"lazy": "selectin"},
152 |     )
153 | 
154 | 
155 | class ConversationShareRedemption(SQLModel, table=True):
156 |     conversation_share_redemption_id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
157 |     conversation_share_id: uuid.UUID = Field(
158 |         sa_column=sqlalchemy.Column(
159 |             sqlalchemy.ForeignKey(
160 |                 "conversationshare.conversation_share_id",
161 |                 name="fk_conversationshareredemption_conversation_share_id",
162 |                 ondelete="CASCADE",
163 |             ),
164 |             nullable=False,
165 |         ),
166 |     )
167 |     conversation_id: uuid.UUID
168 |     conversation_permission: str
169 |     new_participant: bool
170 |     redeemed_by_user_id: str = Field(
171 |         sa_column=sqlalchemy.Column(
172 |             sqlalchemy.ForeignKey(
173 |                 "user.user_id",
174 |                 name="fk_conversationshareredemption_user_id_user",
175 |                 ondelete="CASCADE",
176 |             ),
177 |             nullable=False,
178 |         ),
179 |     )
180 |     created_datetime: datetime.datetime = date_time_default_to_now()
181 | 
182 |     # these relationships are needed to enforce correct INSERT order by SQLModel
183 |     related_conversation_share: sqlalchemy.orm.Mapped[ConversationShare] = Relationship()
184 |     related_redeemed_by_user: sqlalchemy.orm.Mapped[User] = Relationship(
185 |         sa_relationship_kwargs={"lazy": "selectin"},
186 |     )
187 | 
188 | 
189 | class AssistantParticipant(SQLModel, table=True):
190 |     conversation_id: uuid.UUID = Field(
191 |         sa_column=sqlalchemy.Column(
192 |             sqlalchemy.ForeignKey(
193 |                 "conversation.conversation_id",
194 |                 name="fk_assistantparticipant_conversation_id_conversation",
195 |                 ondelete="CASCADE",
196 |             ),
197 |             primary_key=True,
198 |             nullable=False,
199 |         ),
200 |     )
201 |     assistant_id: uuid.UUID = Field(primary_key=True)
202 |     name: str = ""
203 |     image: str | None = None
204 |     joined_datetime: datetime.datetime = date_time_default_to_now()
205 |     status: str | None = None
206 |     status_updated_datetime: datetime.datetime = date_time_default_to_now()
207 |     active_participant: bool = True
208 |     meta_data: dict[str, Any] = Field(
209 |         sa_column=sqlalchemy.Column("metadata", sqlalchemy.JSON, server_default="{}", nullable=False), default={}
210 |     )
211 | 
212 |     # this relationship is needed to enforce correct INSERT order by SQLModel
213 |     related_conversation: Conversation = Relationship()
214 | 
215 |     def on_update(self, session: Session) -> None:
216 |         # update this participant to match the related assistant, if one exists
217 |         assistant = session.exec(select(Assistant).where(Assistant.assistant_id == self.assistant_id)).one_or_none()
218 |         if assistant is None:
219 |             return
220 | 
221 |         sqlalchemy.orm.attributes.set_attribute(self, "name", assistant.name)
222 |         sqlalchemy.orm.attributes.set_attribute(self, "image", assistant.image)
223 | 
224 |     def on_insert(self, session: Session) -> None:
225 |         # update this participant to match the related assistant, requiring one to exist
226 |         assistant = session.exec(select(Assistant).where(Assistant.assistant_id == self.assistant_id)).one()
227 |         sqlalchemy.orm.attributes.set_attribute(self, "name", assistant.name)
228 |         sqlalchemy.orm.attributes.set_attribute(self, "image", assistant.image)
229 | 
230 | 
231 | class UserParticipant(SQLModel, table=True):
232 |     conversation_id: uuid.UUID = Field(
233 |         sa_column=sqlalchemy.Column(
234 |             sqlalchemy.ForeignKey(
235 |                 "conversation.conversation_id",
236 |                 name="fk_userparticipant_conversation_id_conversation",
237 |                 ondelete="CASCADE",
238 |             ),
239 |             primary_key=True,
240 |             nullable=False,
241 |         ),
242 |     )
243 |     user_id: str = Field(primary_key=True)
244 |     name: str = ""
245 |     image: str | None = None
246 |     service_user: bool = False
247 |     joined_datetime: datetime.datetime = date_time_default_to_now()
248 |     status: str | None = None
249 |     status_updated_datetime: datetime.datetime = date_time_default_to_now()
250 |     active_participant: bool = True
251 |     meta_data: dict[str, Any] = Field(
252 |         sa_column=sqlalchemy.Column("metadata", sqlalchemy.JSON, server_default="{}", nullable=False), default={}
253 |     )
254 |     conversation_permission: str
255 | 
256 |     # this relationship is needed to enforce correct INSERT order by SQLModel
257 |     related_conversation: Conversation = Relationship()
258 | 
259 |     def on_update(self, session: Session) -> None:
260 |         # update this participant to match the related user, if one exists
261 |         user = session.exec(select(User).where(User.user_id == self.user_id)).one_or_none()
262 |         if user is None:
263 |             return
264 | 
265 |         sqlalchemy.orm.attributes.set_attribute(self, "name", user.name)
266 |         sqlalchemy.orm.attributes.set_attribute(self, "image", user.image)
267 |         sqlalchemy.orm.attributes.set_attribute(self, "service_user", user.service_user)
268 | 
269 |     def on_insert(self, session: Session) -> None:
270 |         # update this participant to match the related user, requiring one to exist
271 |         user = session.exec(select(User).where(User.user_id == self.user_id)).one()
272 | 
273 |         sqlalchemy.orm.attributes.set_attribute(self, "name", user.name)
274 |         sqlalchemy.orm.attributes.set_attribute(self, "image", user.image)
275 |         sqlalchemy.orm.attributes.set_attribute(self, "service_user", user.service_user)
276 | 
277 | 
278 | class ConversationMessage(SQLModel, table=True):
279 |     sequence: int = Field(default=None, nullable=False, primary_key=True)
280 |     message_id: uuid.UUID = Field(default_factory=uuid.uuid4, unique=True)
281 |     conversation_id: uuid.UUID = Field(
282 |         sa_column=sqlalchemy.Column(
283 |             sqlalchemy.ForeignKey(
284 |                 "conversation.conversation_id",
285 |                 name="fk_conversationmessage_conversation_id_conversation",
286 |                 ondelete="CASCADE",
287 |             ),
288 |             nullable=False,
289 |         ),
290 |     )
291 |     created_datetime: datetime.datetime = date_time_default_to_now()
292 |     sender_participant_id: str
293 |     sender_participant_role: str
294 |     message_type: str = Field(index=True)
295 |     content: str
296 |     content_type: str
297 |     meta_data: dict[str, Any] = Field(sa_column=sqlalchemy.Column("metadata", sqlalchemy.JSON), default={})
298 |     filenames: list[str] = Field(sa_column=sqlalchemy.Column(sqlalchemy.JSON), default=[])
299 | 
300 |     # this relationship is needed to enforce correct INSERT order by SQLModel
301 |     related_conversation: Conversation = Relationship()
302 | 
303 | 
304 | class ConversationMessageDebug(SQLModel, table=True):
305 |     message_id: uuid.UUID = Field(
306 |         sa_column=sqlalchemy.Column(
307 |             sqlalchemy.ForeignKey(
308 |                 "conversationmessage.message_id",
309 |                 name="fk_conversationmessagedebug_message_id_conversationmessage",
310 |                 ondelete="CASCADE",
311 |             ),
312 |             nullable=False,
313 |             primary_key=True,
314 |         ),
315 |     )
316 |     data: dict[str, Any] = Field(sa_column=sqlalchemy.Column(sqlalchemy.JSON, nullable=False), default={})
317 | 
318 |     # this relationship is needed to enforce correct INSERT order by SQLModel
319 |     related_messag: ConversationMessage = Relationship()
320 | 
321 | 
322 | class File(SQLModel, table=True):
323 |     file_id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
324 |     conversation_id: uuid.UUID = Field(
325 |         sa_column=sqlalchemy.Column(
326 |             sqlalchemy.ForeignKey(
327 |                 "conversation.conversation_id",
328 |                 name="fk_file_conversation_id_conversation",
329 |                 ondelete="CASCADE",
330 |             ),
331 |             nullable=False,
332 |         ),
333 |     )
334 | 
335 |     filename: str
336 |     current_version: int
337 |     created_datetime: datetime.datetime = date_time_default_to_now(index=True)
338 | 
339 |     # this relationship is needed to enforce correct INSERT order by SQLModel
340 |     related_conversation: Conversation = Relationship()
341 | 
342 |     __table_args__ = (
343 |         sqlalchemy.UniqueConstraint("conversation_id", "filename", name="uq_file_conversation_id_filename"),
344 |     )
345 | 
346 | 
347 | class FileVersion(SQLModel, table=True):
348 |     file_id: uuid.UUID = Field(
349 |         sa_column=sqlalchemy.Column(
350 |             sqlalchemy.ForeignKey(
351 |                 "file.file_id",
352 |                 name="fk_fileversion_file_id_file",
353 |                 ondelete="CASCADE",
354 |             ),
355 |             primary_key=True,
356 |             nullable=False,
357 |         ),
358 |     )
359 |     version: int = Field(primary_key=True)
360 |     participant_id: str
361 |     participant_role: str
362 |     created_datetime: datetime.datetime = date_time_default_to_now(index=True)
363 |     meta_data: dict[str, Any] = Field(sa_column=sqlalchemy.Column("metadata", sqlalchemy.JSON), default={})
364 |     content_type: str
365 |     file_size: int
366 |     storage_filename: str
367 | 
368 |     # this relationship is needed to enforce correct INSERT order by SQLModel
369 |     related_file: File = Relationship()
370 | 
371 | 
372 | NAMING_CONVENTION = {
373 |     "ix": "ix_%(column_0_label)s",
374 |     "uq": "uq_%(table_name)s_%(column_0_N_name)s",
375 |     "ck": "ck_%(table_name)s_%(constraint_name)s",
376 |     "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
377 |     "pk": "pk_%(table_name)s",
378 | }
379 | SQLModel.metadata.naming_convention = NAMING_CONVENTION
380 | 
381 | 
382 | def ensure_async_driver_scheme(url: str) -> str:
383 |     return url.replace("sqlite://", "sqlite+aiosqlite://").replace("postgresql://", "postgresql+asyncpg://")
384 | 
385 | 
386 | @sqlalchemy.event.listens_for(sqlalchemy.Pool, "connect")
387 | def set_sqlite_pragma(
388 |     dbapi_connection: sqlalchemy.engine.interfaces.DBAPIConnection,
389 |     _: sqlalchemy.pool.ConnectionPoolEntry,
390 | ) -> None:
391 |     if hasattr(sqlalchemy.dialects, "sqlite"):
392 |         cursor = dbapi_connection.cursor()
393 |         cursor.execute("PRAGMA journal_mode=WAL")
394 |         cursor.close()
395 | 
396 | 
397 | @asynccontextmanager
398 | async def create_engine(settings: DBSettings) -> AsyncIterator[AsyncEngine]:
399 |     # ensure that the database url is using the async driver
400 |     db_url = ensure_async_driver_scheme(settings.url)
401 |     parsed_url = urlparse(db_url)
402 |     is_sqlite = parsed_url.scheme.startswith("sqlite")
403 |     is_postgres = parsed_url.scheme.startswith("postgresql")
404 | 
405 |     url_for_log = db_url
406 |     if parsed_url.password:
407 |         url_for_log = url_for_log.replace(parsed_url.password, "****")
408 |     logger.info("creating database engine for %s", url_for_log)
409 | 
410 |     if is_sqlite and "/" in parsed_url.path:
411 |         # create parent directory for sqlite db file as a convenience
412 |         file_path = parsed_url.path[1:]
413 |         pathlib.Path(file_path).parent.mkdir(parents=True, exist_ok=True)
414 | 
415 |     kw_args: dict = {"echo": settings.echosql, "future": True}
416 |     if is_postgres:
417 |         kw_args.update({
418 |             "connect_args": {
419 |                 "ssl": settings.postgresql_ssl_mode,
420 |             },
421 |             "pool_pre_ping": True,
422 |             "pool_size": settings.postgresql_pool_size,
423 |         })
424 | 
425 |     engine = create_async_engine(db_url, **kw_args)
426 | 
427 |     try:
428 |         yield engine
429 |     finally:
430 |         await engine.dispose()
431 | 
432 | 
433 | @sqlalchemy.event.listens_for(Session, "before_flush")
434 | def _session_before_flush(session: Session, flush_context, instances) -> None:  # noqa: ANN001, ARG001
435 |     for obj in session.dirty:
436 |         if not hasattr(obj, "on_update"):
437 |             continue
438 |         obj.on_update(session)
439 | 
440 |     for obj in session.new:
441 |         if not hasattr(obj, "on_insert"):
442 |             continue
443 |         obj.on_insert(session)
444 | 
445 | 
446 | async def bootstrap_db(engine: AsyncEngine, settings: DBSettings) -> None:
447 |     logger.info("bootstrapping database")
448 |     await _ensure_schema(engine=engine, settings=settings)
449 |     await _create_default_data(engine=engine)
450 | 
451 | 
452 | async def _ensure_schema(engine: AsyncEngine, settings: DBSettings) -> None:
453 |     def execute_ensure_version(connection: sqlalchemy.Connection) -> None:
454 |         from alembic import command, config
455 | 
456 |         cfg = config.Config(settings.alembic_config_path)
457 |         cfg.attributes["connection"] = connection
458 |         command.ensure_version(cfg)
459 | 
460 |     async with engine.begin() as conn:
461 |         await conn.run_sync(execute_ensure_version)
462 | 
463 |     alembic_version_exists = False
464 |     async with engine.begin() as conn:
465 |         row = (await conn.exec_driver_sql("SELECT count(version_num) FROM alembic_version")).one()
466 |         alembic_version_exists = row[0] > 0
467 | 
468 |     if not alembic_version_exists:
469 |         return await _create_schema(engine=engine, alembic_config_path=settings.alembic_config_path)
470 | 
471 |     return await _migrate_schema(engine=engine, alembic_config_path=settings.alembic_config_path)
472 | 
473 | 
474 | async def _migrate_schema(engine: AsyncEngine, alembic_config_path: str) -> None:
475 |     from alembic import command, config
476 | 
477 |     logger.info("migrating database schema; alembic_config_path=%s", alembic_config_path)
478 | 
479 |     def execute_upgrade(connection: sqlalchemy.Connection) -> None:
480 |         logger.info("running alembic upgrade to head")
481 |         cfg = config.Config(alembic_config_path)
482 |         cfg.attributes["connection"] = connection
483 |         command.upgrade(cfg, "head")
484 | 
485 |     def execute_check(connection: sqlalchemy.Connection) -> None:
486 |         logger.info("running alembic check")
487 |         cfg = config.Config(alembic_config_path)
488 |         cfg.attributes["connection"] = connection
489 |         command.check(cfg)
490 | 
491 |     async with engine.begin() as conn:
492 |         await conn.run_sync(execute_upgrade)
493 |         await conn.run_sync(execute_check)
494 | 
495 |     return None
496 | 
497 | 
498 | async def _create_schema(engine: AsyncEngine, alembic_config_path: str) -> None:
499 |     logger.info("creating database schema; alembic_config_path=%s", alembic_config_path)
500 | 
501 |     def execute_stamp_head(connection: sqlalchemy.Connection) -> None:
502 |         from alembic import command, config
503 | 
504 |         cfg = config.Config(alembic_config_path)
505 |         cfg.attributes["connection"] = connection
506 |         command.stamp(cfg, "head")
507 | 
508 |     async with engine.begin() as conn:
509 |         await conn.run_sync(SQLModel.metadata.create_all)
510 |         await conn.run_sync(execute_stamp_head)
511 | 
512 | 
513 | async def _create_default_data(engine: AsyncEngine) -> None:
514 |     async with create_session(engine) as session:
515 |         workbench_user = User(
516 |             user_id=service_user_principals.semantic_workbench.user_id,
517 |             name=service_user_principals.semantic_workbench.name,
518 |             service_user=True,
519 |         )
520 |         await insert_if_not_exists(session, workbench_user)
521 |         await session.commit()
522 | 
523 | 
524 | @asynccontextmanager
525 | async def create_session(engine: AsyncEngine) -> AsyncIterator[AsyncSession]:
526 |     session_maker = async_sessionmaker(
527 |         bind=engine,
528 |         class_=AsyncSession,
529 |         expire_on_commit=False,
530 |         autocommit=False,
531 |         autoflush=False,
532 |     )
533 |     async with session_maker() as async_session:
534 |         yield async_session
535 | 
536 | 
537 | async def insert_if_not_exists(session: AsyncSession, model: SQLModel) -> bool:
538 |     """
539 |     Inserts the provided record if a row with the same primary key(s) does already exist in the table.
540 |     Returns True if the record was inserted, False if it already existed.
541 |     """
542 | 
543 |     # the postgresql.insert function is used to generate an INSERT statement with an ON CONFLICT DO NOTHING clause.
544 |     # note that sqlite also supports ON CONFLICT DO NOTHING, so this works with both database types.
545 |     statement = (
546 |         postgresql.insert(model.__class__).values(**model.model_dump(exclude_unset=True)).on_conflict_do_nothing()
547 |     )
548 |     conn = await session.connection()
549 |     result = await conn.execute(statement)
550 |     return result.rowcount > 0
551 | 
```

--------------------------------------------------------------------------------
/libraries/python/openai-client/openai_client/tools.py:
--------------------------------------------------------------------------------

```python
  1 | import ast
  2 | import inspect
  3 | import json
  4 | from collections.abc import Callable, Iterable
  5 | from dataclasses import dataclass
  6 | from typing import Any
  7 | 
  8 | from openai import (
  9 |     NOT_GIVEN,
 10 |     AsyncOpenAI,
 11 |     NotGiven,
 12 | )
 13 | from openai.types.chat import (
 14 |     ChatCompletionMessageParam,
 15 |     ChatCompletionToolParam,
 16 |     ParsedChatCompletion,
 17 |     ParsedFunctionToolCall,
 18 | )
 19 | from openai.types.shared_params.function_definition import FunctionDefinition
 20 | from pydantic import BaseModel, create_model
 21 | from pydantic.fields import FieldInfo
 22 | 
 23 | from . import logger
 24 | from .completion import assistant_message_from_completion
 25 | from .errors import CompletionError, validate_completion
 26 | from .logging import (
 27 |     add_serializable_data,
 28 |     make_completion_args_serializable,
 29 |     serializable,
 30 | )
 31 | 
 32 | 
 33 | def to_string(value: Any) -> str:
 34 |     """
 35 |     Convert a value to a string. This is a helper function to get the response
 36 |     of a tool function call into a message.
 37 |     """
 38 |     if value is None:
 39 |         return "Function executed successfully."
 40 |     elif isinstance(value, str):
 41 |         return value
 42 |     elif isinstance(value, int | float):
 43 |         return str(value)
 44 |     elif isinstance(value, dict):
 45 |         return json.dumps(value)
 46 |     elif isinstance(value, list):
 47 |         return json.dumps(value, indent=2)
 48 |     elif isinstance(value, tuple):
 49 |         return json.dumps(value)
 50 |     elif isinstance(value, BaseModel):
 51 |         return value.model_dump_json(indent=2)
 52 |     else:
 53 |         return str(value)
 54 | 
 55 | 
 56 | def function_list_to_tool_choice(
 57 |     functions: list[str] | None,
 58 | ) -> Iterable[ChatCompletionToolParam] | None:
 59 |     """
 60 |     Convert a list of function names to a list of ChatCompletionToolParam
 61 |     objects. This is used in the Chat Completions API if you want to tell the
 62 |     completion it MUST use a specific set of tool functions.
 63 |     """
 64 |     if not functions:
 65 |         return None
 66 |     return [
 67 |         ChatCompletionToolParam(type="function", function={"name": name})
 68 |         for name in functions
 69 |     ] or None
 70 | 
 71 | 
 72 | @dataclass
 73 | class Parameter:
 74 |     """
 75 |     Tool functions are described by their parameters. This dataclass
 76 |     describes a single parameter of a tool function.
 77 |     """
 78 | 
 79 |     name: str
 80 |     type: Any
 81 |     description: str | None
 82 |     default_value: Any | None = None
 83 | 
 84 | 
 85 | class ToolFunction:
 86 |     """
 87 |     A tool function is a Python function that can be called as a tool from the
 88 |     chat completion API. This class wraps a function so you can generate it's
 89 |     JSON schema for the chat completion API, execute it with arguments, and
 90 |     generate a usage string (for help messages)
 91 |     """
 92 | 
 93 |     def __init__(
 94 |         self, fn: Callable, name: str | None = None, description: str | None = None
 95 |     ) -> None:
 96 |         self.fn = fn
 97 |         self.name = name or fn.__name__
 98 |         self.description = (
 99 |             description or inspect.getdoc(fn) or self.name.replace("_", " ").title()
100 |         )
101 | 
102 |     def parameters(self, exclude: list[str] | None = None) -> list[Parameter]:
103 |         """
104 |         This function's parameters and their default values.
105 |         """
106 |         if exclude is None:
107 |             exclude = []
108 |         parameters = dict(inspect.signature(self.fn).parameters)
109 |         for param_name in exclude:
110 |             del parameters[param_name]
111 |         return [
112 |             Parameter(
113 |                 name=param_name,
114 |                 type=param.annotation,
115 |                 description=None,  # param.annotation.description,
116 |                 default_value=param.default,
117 |             )
118 |             for param_name, param in parameters.items()
119 |         ]
120 | 
121 |     def usage(self) -> str:
122 |         """
123 |         A usage string for this function. This can be used in help messages.
124 |         """
125 |         name = self.name
126 |         param_usages = []
127 |         for param in self.parameters():
128 |             param_type = param.type
129 |             try:
130 |                 param_type = param.type.__name__
131 |             except AttributeError:
132 |                 param_type = param.type
133 |             usage = f"{param.name}: {param_type}"
134 |             if param.default_value is not inspect.Parameter.empty:
135 |                 if isinstance(param.default_value, str):
136 |                     usage += f' = "{param.default_value}"'
137 |                 else:
138 |                     usage += f" = {param.default_value}"
139 |             param_usages.append(usage)
140 | 
141 |         description = self.description
142 |         return f"{name}({', '.join(param_usages)}): {description}"
143 | 
144 |     def schema(self, strict: bool = True) -> dict[str, Any]:
145 |         """
146 |         Generate a JSON schema for this function that is suitable for the OpenAI
147 |         completion API.
148 |         """
149 | 
150 |         # Create the Pydantic model using create_model.
151 |         model_name = self.fn.__name__.title().replace("_", "")
152 |         fields = {}
153 |         for parameter in self.parameters():
154 |             field_info = FieldInfo(description=parameter.description)
155 |             if parameter.default_value is not inspect.Parameter.empty:
156 |                 field_info.default = parameter.default_value
157 |             fields[parameter.name] = (
158 |                 parameter.type,
159 |                 field_info,
160 |             )
161 |         pydantic_model = create_model(model_name, **fields)
162 | 
163 |         # Generate the JSON schema from the Pydantic model.
164 |         parameters_schema = pydantic_model.model_json_schema(mode="serialization")
165 | 
166 |         # Remove title attribute from all properties (not allowed by the Chat
167 |         # Completions API).
168 |         properties = parameters_schema["properties"]
169 |         for property_key in properties:
170 |             if "title" in properties[property_key]:
171 |                 del properties[property_key]["title"]
172 | 
173 |         # And from the top-level object.
174 |         if "title" in parameters_schema:
175 |             del parameters_schema["title"]
176 | 
177 |         # Output a schema that matches OpenAI's "tool" format.
178 |         # e.g., https://platform.openai.com/docs/guides/function-calling
179 |         # We use this because they trained GPT on it.
180 |         schema = {
181 |             # "$schema": "http://json-schema.org/draft-07/schema#",
182 |             # "$id": f"urn:jsonschema:{name}",
183 |             "name": self.name,
184 |             "description": self.description,
185 |             "strict": strict,
186 |             "parameters": {
187 |                 "type": "object",
188 |                 "properties": parameters_schema["properties"],
189 |             },
190 |         }
191 | 
192 |         # If this is a strict schema, OpenAI requires additionalProperties to be
193 |         # False. "strict mode" is required for JSON or structured output from
194 |         # the API.
195 |         if strict:
196 |             schema["parameters"]["additionalProperties"] = False
197 | 
198 |         # Add required fields (another Chat Completions API requirement).
199 |         if "required" in parameters_schema:
200 |             schema["parameters"]["required"] = parameters_schema["required"]
201 | 
202 |         # Add type definitions (another Chat Completions API requirement).
203 |         if "$defs" in parameters_schema:
204 |             schema["parameters"]["$defs"] = parameters_schema["$defs"]
205 |             for key in schema["parameters"]["$defs"]:
206 |                 schema["parameters"]["$defs"][key]["additionalProperties"] = False
207 | 
208 |         return schema
209 | 
210 |     async def execute(self, *args, **kwargs) -> Any:
211 |         """
212 |         Run this function, and return its value. If the function is a coroutine,
213 |         it will be awaited. If string_response is True, the response will be
214 |         converted to a string.
215 |         """
216 |         result = self.fn(*args, **kwargs)
217 |         if inspect.iscoroutine(result):
218 |             result = await result
219 |         return result
220 | 
221 | 
222 | class FunctionHandler:
223 |     def __init__(self, tool_functions: "ToolFunctions") -> None:
224 |         self.tool_functions = tool_functions
225 | 
226 |     def __getattr__(self, name: str) -> Callable:
227 |         """Makes registered functions accessible as attributes of the functions object."""
228 |         if name not in self.tool_functions.function_map:
229 |             raise AttributeError(f"'FunctionHandler' object has no attribute '{name}'")
230 | 
231 |         async def wrapper(*args, **kwargs) -> Any:
232 |             return await self.tool_functions.execute_function(name, args, kwargs)
233 | 
234 |         return wrapper
235 | 
236 | 
237 | class ToolFunctions:
238 |     """
239 |     A set of tool functions that can be called from the Chat Completions API.
240 |     Pass this into the `complete_with_tool_calls` helper function to run a full
241 |     tool-call completion against the API.
242 |     """
243 | 
244 |     def __init__(
245 |         self, functions: list[ToolFunction] | None = None, with_help: bool = False
246 |     ) -> None:
247 |         # Set up function map.
248 |         self.function_map: dict[str, ToolFunction] = {}
249 |         if functions:
250 |             for function in functions:
251 |                 self.function_map[function.name] = function
252 | 
253 |         # A help message can be generated for the function map.
254 |         if with_help:
255 |             self.function_map["help"] = ToolFunction(self.help)
256 | 
257 |         # This allows actions to be called as attributes.
258 |         self.functions = FunctionHandler(self)
259 | 
260 |     def help(self) -> str:
261 |         """Return this help message."""
262 | 
263 |         usage = [f"{command.usage()}" for command in self.function_map.values()]
264 |         usage.sort()
265 |         return "```text\nCommands:\n" + "\n".join(usage) + "\n```"
266 | 
267 |     def add_function(
268 |         self,
269 |         function: Callable,
270 |         name: str | None = None,
271 |         description: str | None = None,
272 |     ) -> None:
273 |         """Register a function with the tool functions."""
274 |         if not name:
275 |             name = function.__name__
276 |         self.function_map[name] = ToolFunction(function, name, description)
277 | 
278 |     def has_function(self, name: str) -> bool:
279 |         return name in self.function_map
280 | 
281 |     def get_function(self, name: str) -> ToolFunction | None:
282 |         return self.function_map.get(name)
283 | 
284 |     def get_functions(self) -> list[ToolFunction]:
285 |         return list(self.function_map.values())
286 | 
287 |     async def execute_function(
288 |         self,
289 |         name: str,
290 |         args: tuple = (),
291 |         kwargs: dict[str, Any] | None = None,
292 |         string_response: bool = False,
293 |     ) -> Any:
294 |         """
295 |         Run a function from the ToolFunctions list by name. If string_response
296 |         is True, the function return value will be converted to a string.
297 |         """
298 |         if kwargs is None:
299 |             kwargs = {}
300 |         function = self.get_function(name)
301 |         if not function:
302 |             raise ValueError(f"Function {name} not found in registry.")
303 |         response = await function.execute(*args, **kwargs)
304 |         if string_response:
305 |             return to_string(response)
306 | 
307 |     async def execute_function_string(
308 |         self, function_string: str, string_response: bool = False
309 |     ) -> Any:
310 |         """Parse a function string and execute the function."""
311 |         try:
312 |             function, args, kwargs = self.parse_function_string(function_string)
313 |         except ValueError as e:
314 |             raise ValueError(f"{e} Type: `/help` for more information.") from e
315 |         if not function:
316 |             raise ValueError(
317 |                 "Function not found in registry. Type: `/help` for more information."
318 |             )
319 |         result = await function.execute(*args, **kwargs)
320 |         if string_response:
321 |             return to_string(result)
322 | 
323 |     @staticmethod
324 |     def parse_fn_string(
325 |         function_string: str,
326 |     ) -> tuple[str | None, list[Any], dict[str, Any]]:
327 |         """
328 |         Parse a string representing a function call into its name, positional
329 |         arguments, and keyword arguments.
330 |         """
331 | 
332 |         # As a convenience, remove any leading slashes.
333 |         function_string = function_string.lstrip("/")
334 | 
335 |         # As a convenience, add parentheses if they are missing.
336 |         if " " not in function_string and "(" not in function_string:
337 |             function_string += "()"
338 | 
339 |         # Parse the string into an AST (Abstract Syntax Tree)
340 |         try:
341 |             tree = ast.parse(function_string)
342 |         except SyntaxError as err:
343 |             raise ValueError(
344 |                 "Invalid function call. Please check your syntax."
345 |             ) from err
346 | 
347 |         # Ensure the tree contains exactly one expression (the function call)
348 |         if not (
349 |             isinstance(tree, ast.Module)
350 |             and len(tree.body) == 1
351 |             and isinstance(tree.body[0], ast.Expr)
352 |         ):
353 |             raise ValueError("Expected a single function call.")
354 | 
355 |         # The function call is stored as a `Call` node within the expression
356 |         call_node = tree.body[0].value
357 |         if not isinstance(call_node, ast.Call):
358 |             raise ValueError("Invalid function call. Please check your syntax.")
359 | 
360 |         # Extract the function name
361 |         if isinstance(call_node.func, ast.Name):
362 |             function_name = call_node.func.id
363 |         else:
364 |             raise ValueError("Unsupported function format. Please check your syntax.")
365 | 
366 |         # Helper function to evaluate AST nodes to their Python equivalent
367 |         def eval_node(node):
368 |             if isinstance(node, ast.Constant):
369 |                 return node.value
370 |             elif isinstance(node, ast.List):
371 |                 return [eval_node(elem) for elem in node.elts]
372 |             elif isinstance(node, ast.Tuple):
373 |                 return tuple(eval_node(elem) for elem in node.elts)
374 |             elif isinstance(node, ast.Dict):
375 |                 return {
376 |                     eval_node(key): eval_node(value)
377 |                     for key, value in zip(node.keys, node.values, strict=False)
378 |                 }
379 |             elif isinstance(node, ast.Name):
380 |                 return (
381 |                     node.id
382 |                 )  # This can return variable names, but we assume they're constants
383 |             elif isinstance(node, ast.BinOp):  # Handling arithmetic expressions
384 |                 return eval(compile(ast.Expression(node), filename="", mode="eval"))
385 |             elif isinstance(node, ast.Call):
386 |                 raise ValueError("Nested function calls are not supported.")
387 |             else:
388 |                 raise ValueError(f"Unsupported AST node type: {type(node).__name__}")
389 | 
390 |         # Extract positional arguments
391 |         args = [eval_node(arg) for arg in call_node.args]
392 | 
393 |         # Extract keyword arguments
394 |         kwargs = {}
395 |         for kw in call_node.keywords:
396 |             kwargs[kw.arg] = eval_node(kw.value)
397 | 
398 |         return function_name, args, kwargs
399 | 
400 |     def parse_function_string(
401 |         self, function_string: str
402 |     ) -> tuple[ToolFunction | None, list[Any], dict[str, Any]]:
403 |         """Parse a function call string into a function and its arguments."""
404 | 
405 |         function_name, args, kwargs = ToolFunctions.parse_fn_string(function_string)
406 |         if not function_name:
407 |             return None, [], {}
408 | 
409 |         function = self.get_function(function_name)
410 |         if not function:
411 |             return None, [], {}
412 | 
413 |         return function, args, kwargs
414 | 
415 |     def chat_completion_tools(self) -> list[ChatCompletionToolParam] | NotGiven:
416 |         """
417 |         Return a list of ChatCompletionToolParam objects that describe the tool
418 |         functions in this ToolFunctions object. These can be passed to the Chat
419 |         Completions API (in the "tools" parameter) to enable tool function
420 |         calls.
421 |         """
422 |         tools = [
423 |             ChatCompletionToolParam(
424 |                 type="function", function=FunctionDefinition(**func.schema())
425 |             )
426 |             for func in self.function_map.values()
427 |         ]
428 |         return tools or NOT_GIVEN
429 | 
430 |     async def execute_tool_call(
431 |         self, tool_call: ParsedFunctionToolCall
432 |     ) -> ChatCompletionMessageParam | None:
433 |         """
434 |         Execute a function as requested by a ParsedFunctionToolCall (generated
435 |         by the Chat Completions API) and return the response as a
436 |         ChatCompletionMessageParam message (as required by the Chat Completions
437 |         API)
438 |         """
439 |         function = tool_call.function
440 |         if self.has_function(function.name):
441 |             logger.debug(
442 |                 "Function call.",
443 |                 extra=add_serializable_data(
444 |                     {"name": function.name, "arguments": function.arguments}
445 |                 ),
446 |             )
447 |             value: Any = None
448 |             try:
449 |                 kwargs: dict[str, Any] = json.loads(function.arguments)
450 |                 value = await self.execute_function(
451 |                     function.name, (), kwargs, string_response=True
452 |                 )
453 |             except Exception as e:
454 |                 logger.error("Error.", extra=add_serializable_data({"error": e}))
455 |                 value = f"Error: {e}"
456 |             finally:
457 |                 logger.debug(
458 |                     "Function response.",
459 |                     extra=add_serializable_data(
460 |                         {"tool_call_id": tool_call.id, "content": value}
461 |                     ),
462 |                 )
463 |             return {
464 |                 "role": "tool",
465 |                 "content": value,
466 |                 "tool_call_id": tool_call.id,
467 |             }
468 |         else:
469 |             logger.error(f"Function not found: {function.name}")
470 |             return None
471 | 
472 | 
473 | async def complete_with_tool_calls(
474 |     async_client: AsyncOpenAI,
475 |     completion_args: dict[str, Any],
476 |     tool_functions: ToolFunctions,
477 |     metadata: dict[str, Any] | None = None,
478 |     max_tool_call_rounds: int = 5,  # Adding a parameter to limit the maximum number of rounds
479 | ) -> tuple[ParsedChatCompletion | None, list[ChatCompletionMessageParam]]:
480 |     """
481 |     Complete a chat response with tool calls handled by the supplied tool
482 |     functions. This function supports multiple rounds of tool calls, continuing
483 |     until the model no longer requests tool calls or the maximum number of rounds is reached.
484 | 
485 |     Parameters:
486 | 
487 |     - async_client: The OpenAI client.
488 |     - completion_args: The completion arguments passed onto the OpenAI `parse`
489 |       call. See the OpenAI API docs for more information.
490 |     - tool_functions: A ToolFunctions object that contains the tool functions to
491 |       be available to be called.
492 |     - metadata: Metadata to be added to the completion response.
493 |     - max_tool_call_rounds: Maximum number of tool call rounds to prevent infinite loops (default: 5)
494 |     """
495 |     if metadata is None:
496 |         metadata = {}
497 |     messages: list[ChatCompletionMessageParam] = completion_args.get("messages", [])
498 |     all_new_messages: list[ChatCompletionMessageParam] = []
499 |     current_completion = None
500 |     rounds = 0
501 | 
502 |     # Set up the tools if tool_functions exists.
503 |     if tool_functions:
504 |         # Note: this overwrites any existing tools.
505 |         completion_args["tools"] = tool_functions.chat_completion_tools()
506 | 
507 |     # Keep making completions until no more tool calls are requested
508 |     # or we hit the maximum number of rounds
509 |     while rounds < max_tool_call_rounds:
510 |         rounds += 1
511 |         round_description = f"round {rounds}"
512 | 
513 |         current_args = {**completion_args, "messages": [*messages, *all_new_messages]}
514 |         logger.debug(
515 |             f"Completion call ({round_description}).",
516 |             extra=add_serializable_data(
517 |                 make_completion_args_serializable(current_args)
518 |             ),
519 |         )
520 |         metadata[f"completion_request ({round_description})"] = serializable(
521 |             current_args
522 |         )
523 | 
524 |         # Make the completion call
525 |         try:
526 |             current_completion = await async_client.beta.chat.completions.parse(
527 |                 **current_args,
528 |             )
529 |             validate_completion(current_completion)
530 |             logger.debug(
531 |                 f"Completion response ({round_description}).",
532 |                 extra=add_serializable_data(
533 |                     {"completion": current_completion.model_dump()}
534 |                 ),
535 |             )
536 |             metadata[f"completion_response ({round_description})"] = (
537 |                 current_completion.model_dump()
538 |             )
539 |         except Exception as e:
540 |             completion_error = CompletionError(e)
541 |             metadata[f"completion_error ({round_description})"] = (
542 |                 completion_error.message
543 |             )
544 |             logger.error(
545 |                 completion_error.message,
546 |                 extra=add_serializable_data(
547 |                     {"completion_error": completion_error.body, "metadata": metadata}
548 |                 ),
549 |             )
550 |             raise completion_error from e
551 | 
552 |         # Extract assistant message from completion and add to new messages
553 |         assistant_message = assistant_message_from_completion(current_completion)
554 |         if assistant_message:
555 |             all_new_messages.append(assistant_message)
556 | 
557 |         # Check for tool calls
558 |         completion_message = current_completion.choices[0].message
559 |         if not completion_message.tool_calls:
560 |             # No more tool calls, we're done
561 |             break
562 | 
563 |         # Call all tool functions and generate return messages
564 |         round_tool_messages: list[ChatCompletionMessageParam] = []
565 |         for tool_call in completion_message.tool_calls:
566 |             function_call_result_message = await tool_functions.execute_tool_call(
567 |                 tool_call
568 |             )
569 |             if function_call_result_message:
570 |                 round_tool_messages.append(function_call_result_message)
571 |                 all_new_messages.append(function_call_result_message)
572 | 
573 |     return current_completion, all_new_messages
574 | 
```
Page 97/145FirstPrevNextLast