From d030897520f97bd2052674f7c0854e6a5e8fa1d7 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 25 Feb 2026 23:34:46 -0500 Subject: [PATCH] chore(conductor): Archive track 'Add support for the deepseek api as a provider.' --- .../deepseek_support_20260225/index.md | 5 + .../deepseek_support_20260225/metadata.json | 8 ++ .../archive/deepseek_support_20260225/plan.md | 27 +++++ .../archive/deepseek_support_20260225/spec.md | 31 ++++++ conductor/tracks.md | 5 - config.toml | 4 +- fix_task.toml | 17 +++ manualslop_layout.ini | 16 +-- mcp_client.py | 105 +++++++++++++++++- sanity_task.toml | 3 + task.toml | 17 +++ tests/temp_project_history.toml | 16 ++- 12 files changed, 235 insertions(+), 19 deletions(-) create mode 100644 conductor/archive/deepseek_support_20260225/index.md create mode 100644 conductor/archive/deepseek_support_20260225/metadata.json create mode 100644 conductor/archive/deepseek_support_20260225/plan.md create mode 100644 conductor/archive/deepseek_support_20260225/spec.md create mode 100644 fix_task.toml create mode 100644 sanity_task.toml create mode 100644 task.toml diff --git a/conductor/archive/deepseek_support_20260225/index.md b/conductor/archive/deepseek_support_20260225/index.md new file mode 100644 index 0000000..480c58d --- /dev/null +++ b/conductor/archive/deepseek_support_20260225/index.md @@ -0,0 +1,5 @@ +# Track deepseek_support_20260225 Context + +- [Specification](./spec.md) +- [Implementation Plan](./plan.md) +- [Metadata](./metadata.json) diff --git a/conductor/archive/deepseek_support_20260225/metadata.json b/conductor/archive/deepseek_support_20260225/metadata.json new file mode 100644 index 0000000..cc8ba0b --- /dev/null +++ b/conductor/archive/deepseek_support_20260225/metadata.json @@ -0,0 +1,8 @@ +{ + "track_id": "deepseek_support_20260225", + "type": "feature", + "status": "new", + "created_at": "2026-02-25T00:00:00Z", + "updated_at": "2026-02-25T00:00:00Z", + "description": "Add support for the deepseek api as a provider." +} \ No newline at end of file diff --git a/conductor/archive/deepseek_support_20260225/plan.md b/conductor/archive/deepseek_support_20260225/plan.md new file mode 100644 index 0000000..39a2a9c --- /dev/null +++ b/conductor/archive/deepseek_support_20260225/plan.md @@ -0,0 +1,27 @@ +# Implementation Plan: DeepSeek API Provider Support + +## Phase 1: Infrastructure & Common Logic [checkpoint: 0ec3720] +- [x] Task: Initialize MMA Environment `activate_skill mma-orchestrator` 1b3ff23 +- [x] Task: Update `credentials.toml` schema and configuration logic in `project_manager.py` to support `deepseek` 1b3ff23 +- [x] Task: Define the `DeepSeekProvider` interface in `ai_client.py` and align with existing provider patterns 1b3ff23 +- [x] Task: Conductor - User Manual Verification 'Infrastructure & Common Logic' (Protocol in workflow.md) 1b3ff23 + +## Phase 2: DeepSeek API Client Implementation +- [x] Task: Write failing tests for `DeepSeekProvider` model selection and basic completion +- [x] Task: Implement `DeepSeekProvider` using the dedicated SDK +- [x] Task: Write failing tests for streaming and tool calling parity in `DeepSeekProvider` +- [x] Task: Implement streaming and tool calling logic for DeepSeek models +- [x] Task: Conductor - User Manual Verification 'DeepSeek API Client Implementation' (Protocol in workflow.md) + +## Phase 3: Reasoning Traces & Advanced Capabilities +- [x] Task: Write failing tests for reasoning trace capture in `DeepSeekProvider` (DeepSeek-R1) +- [x] Task: Implement reasoning trace processing and integration with discussion history +- [x] Task: Write failing tests for token estimation and cost tracking for DeepSeek models +- [x] Task: Implement token usage tracking according to DeepSeek pricing +- [x] Task: Conductor - User Manual Verification 'Reasoning Traces & Advanced Capabilities' (Protocol in workflow.md) + +## Phase 4: GUI Integration & Final Verification +- [x] Task: Update `gui_2.py` and `theme_2.py` (if necessary) to include DeepSeek in the provider selection UI +- [x] Task: Implement automated regression tests for the full DeepSeek lifecycle (prompt, streaming, tool call, reasoning) +- [x] Task: Verify overall performance and UI responsiveness with the new provider +- [x] Task: Conductor - User Manual Verification 'GUI Integration & Final Verification' (Protocol in workflow.md) diff --git a/conductor/archive/deepseek_support_20260225/spec.md b/conductor/archive/deepseek_support_20260225/spec.md new file mode 100644 index 0000000..6dc47da --- /dev/null +++ b/conductor/archive/deepseek_support_20260225/spec.md @@ -0,0 +1,31 @@ +# Specification: DeepSeek API Provider Support + +## Overview +Implement a new AI provider module to support the DeepSeek API within the Manual Slop application. This integration will leverage a dedicated SDK to provide access to high-performance models (DeepSeek-V3 and DeepSeek-R1) with support for streaming, tool calling, and detailed reasoning traces. + +## Functional Requirements +- **Dedicated SDK Integration:** Utilize a DeepSeek-specific Python client for API interactions. +- **Model Support:** Initial support for `deepseek-v3` (general performance) and `deepseek-r1` (reasoning). +- **Core Features:** + - **Streaming:** Support real-time response generation for a better user experience. + - **Tool Calling:** Integrate with Manual Slop's existing tool/function execution framework. + - **Reasoning Traces:** Capture and display reasoning paths if provided by the model (e.g., DeepSeek-R1). +- **Configuration Management:** + - Add `[deepseek]` section to `credentials.toml` for `api_key`. + - Update `config.toml` to allow selecting DeepSeek as the active provider. + +## Non-Functional Requirements +- **Parity:** Maintain consistency with existing Gemini and Anthropic provider implementations in `ai_client.py`. +- **Error Handling:** Robust handling of API rate limits and connection issues specific to DeepSeek. +- **Observability:** Track token usage and costs according to DeepSeek's pricing model. + +## Acceptance Criteria +- [ ] User can select "DeepSeek" as a provider in the GUI. +- [ ] Successful completion of prompts using both DeepSeek-V3 and DeepSeek-R1 models. +- [ ] Tool calling works correctly for standard operations (e.g., `read_file`). +- [ ] Reasoning traces from R1 are captured and visible in the discussion history. +- [ ] Streaming responses function correctly without blocking the GUI. + +## Out of Scope +- Support for OpenAI-compatible proxies for DeepSeek in this initial track. +- Automated fine-tuning or custom model endpoints. diff --git a/conductor/tracks.md b/conductor/tracks.md index b22e7fe..cd7ac15 100644 --- a/conductor/tracks.md +++ b/conductor/tracks.md @@ -40,8 +40,3 @@ This file tracks all major tracks for the project. Each track has its own detail --- -- [x] **Track: Add support for the deepseek api as a provider.** -*Link: [./tracks/deepseek_support_20260225/](./tracks/deepseek_support_20260225/)* - ---- - diff --git a/config.toml b/config.toml index 7b841b5..9cbf71e 100644 --- a/config.toml +++ b/config.toml @@ -1,6 +1,6 @@ [ai] -provider = "gemini" -model = "gemini-2.5-flash-lite" +provider = "deepseek" +model = "deepseek-chat" temperature = 0.0 max_tokens = 8192 history_trunc_limit = 8000 diff --git a/fix_task.toml b/fix_task.toml new file mode 100644 index 0000000..3c7685c --- /dev/null +++ b/fix_task.toml @@ -0,0 +1,17 @@ +role = "tier3-worker" +prompt = """FIX DeepSeek implementation in ai_client.py. + +CONTEXT: +Several tests in @tests/test_deepseek_provider.py are failing (returning '(No text returned by the model)') because the current implementation of '_send_deepseek' in @ai_client.py forces 'stream=True' and expects SSE format, but the test mocks provide standard JSON responses. + +TASK: +1. Modify '_send_deepseek' in @ai_client.py to handle the response correctly whether it is a stream or a standard JSON response. + - You should probably determine this based on the 'stream' value in the payload (which is currently hardcoded to True, but the implementation should be flexible). + - If 'stream' is True, use the iter_lines() logic to aggregate chunks. + - If 'stream' is False, use resp.json() to get the content. +2. Fix the 'NameError: name 'data' is not defined' and ensure 'usage' is correctly extracted. +3. Ensure 'full_content', 'full_reasoning' (thinking tags), and 'tool_calls' are correctly captured and added to the conversation history in both modes. +4. Ensure all tests in @tests/test_deepseek_provider.py pass. + +OUTPUT: Provide the raw Python code for the modified '_send_deepseek' function.""" +docs = ["ai_client.py", "tests/test_deepseek_provider.py"] diff --git a/manualslop_layout.ini b/manualslop_layout.ini index c6d5f17..051c0c5 100644 --- a/manualslop_layout.ini +++ b/manualslop_layout.ini @@ -79,7 +79,7 @@ DockId=0x0000000F,2 [Window][Theme] Pos=0,17 -Size=588,400 +Size=588,545 Collapsed=0 DockId=0x00000005,1 @@ -96,7 +96,7 @@ DockId=0x0000000E,0 [Window][Context Hub] Pos=0,17 -Size=588,400 +Size=588,545 Collapsed=0 DockId=0x00000005,0 @@ -119,14 +119,14 @@ Collapsed=0 DockId=0x0000000E,1 [Window][Files & Media] -Pos=0,419 -Size=588,781 +Pos=0,564 +Size=588,636 Collapsed=0 DockId=0x00000006,1 [Window][AI Settings] -Pos=0,419 -Size=588,781 +Pos=0,564 +Size=588,636 Collapsed=0 DockId=0x00000006,0 @@ -140,8 +140,8 @@ DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,17 Size=1680,1183 Sp DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=Y Selected=0xF4139CA2 DockNode ID=0x00000002 Parent=0x0000000B SizeRef=1029,1119 Split=X Selected=0xF4139CA2 DockNode ID=0x00000007 Parent=0x00000002 SizeRef=588,858 Split=Y Selected=0x8CA2375C - DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,400 Selected=0xF4139CA2 - DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,781 CentralNode=1 Selected=0x7BD57D6A + DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,545 Selected=0xF4139CA2 + DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,636 CentralNode=1 Selected=0x7BD57D6A DockNode ID=0x0000000E Parent=0x00000002 SizeRef=530,858 Selected=0x418C7449 DockNode ID=0x00000001 Parent=0x0000000B SizeRef=1029,775 Selected=0x8B4EBFA6 DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6 diff --git a/mcp_client.py b/mcp_client.py index 63c9c48..5a06214 100644 --- a/mcp_client.py +++ b/mcp_client.py @@ -229,6 +229,74 @@ def get_file_summary(path: str) -> str: return f"ERROR summarising '{path}': {e}" +def get_python_skeleton(path: str) -> str: + """ + Returns a skeleton of a Python file (preserving docstrings, stripping function bodies). + """ + p, err = _resolve_and_check(path) + if err: + return err + if not p.exists(): + return f"ERROR: file not found: {path}" + if not p.is_file() or p.suffix != ".py": + return f"ERROR: not a python file: {path}" + + try: + # Use mma_exec's generator if possible, or a local simplified version + # For now, we will use a dedicated script or just inline logic here. + # Given we have tree-sitter already installed in the env... + import tree_sitter + import tree_sitter_python + + code = p.read_text(encoding="utf-8") + PY_LANGUAGE = tree_sitter.Language(tree_sitter_python.language()) + parser = tree_sitter.Parser(PY_LANGUAGE) + tree = parser.parse(bytes(code, "utf8")) + + edits = [] + + def is_docstring(node): + if node.type == "expression_statement" and node.child_count > 0: + if node.children[0].type == "string": + return True + return False + + def walk(node): + if node.type == "function_definition": + body = node.child_by_field_name("body") + if body and body.type == "block": + indent = " " * body.start_point.column + first_stmt = None + for child in body.children: + if child.type != "comment": + first_stmt = child + break + + if first_stmt and is_docstring(first_stmt): + start_byte = first_stmt.end_byte + end_byte = body.end_byte + if end_byte > start_byte: + edits.append((start_byte, end_byte, f"\\n{indent}...")) + else: + start_byte = body.start_byte + end_byte = body.end_byte + edits.append((start_byte, end_byte, "...")) + + for child in node.children: + walk(child) + + walk(tree.root_node) + + edits.sort(key=lambda x: x[0], reverse=True) + code_bytes = bytearray(code, "utf8") + for start, end, replacement in edits: + code_bytes[start:end] = bytes(replacement, "utf8") + + return code_bytes.decode("utf8") + except Exception as e: + return f"ERROR generating skeleton for '{path}': {e}" + + # ------------------------------------------------------------------ web tools @@ -355,7 +423,7 @@ def get_ui_performance() -> str: # ------------------------------------------------------------------ tool dispatch -TOOL_NAMES = {"read_file", "list_directory", "search_files", "get_file_summary", "web_search", "fetch_url", "get_ui_performance"} +TOOL_NAMES = {"read_file", "list_directory", "search_files", "get_file_summary", "get_python_skeleton", "web_search", "fetch_url", "get_ui_performance"} def dispatch(tool_name: str, tool_input: dict) -> str: @@ -370,6 +438,8 @@ def dispatch(tool_name: str, tool_input: dict) -> str: return search_files(tool_input.get("path", ""), tool_input.get("pattern", "*")) if tool_name == "get_file_summary": return get_file_summary(tool_input.get("path", "")) + if tool_name == "get_python_skeleton": + return get_python_skeleton(tool_input.get("path", "")) if tool_name == "web_search": return web_search(tool_input.get("query", "")) if tool_name == "fetch_url": @@ -458,6 +528,25 @@ MCP_TOOL_SPECS = [ "required": ["path"], }, }, + { + "name": "get_python_skeleton", + "description": ( + "Get a skeleton view of a Python file. " + "This returns all classes and function signatures with their docstrings, " + "but replaces function bodies with '...'. " + "Use this to understand module interfaces without reading the full implementation." + ), + "parameters": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Path to the .py file.", + } + }, + "required": ["path"], + }, + }, { "name": "web_search", "description": "Search the web using DuckDuckGo. Returns the top 5 search results with titles, URLs, and snippets. Chain this with fetch_url to read specific pages.", @@ -472,6 +561,20 @@ MCP_TOOL_SPECS = [ "required": ["query"] } }, + { + "name": "fetch_url", + "description": "Fetch the full text content of a URL (stripped of HTML tags). Use this after web_search to read relevant information from the web.", + "parameters": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The full URL to fetch." + } + }, + "required": ["url"] + } + }, { "name": "get_ui_performance", "description": "Get a snapshot of the current UI performance metrics, including FPS, Frame Time (ms), CPU usage (%), and Input Lag (ms). Use this to diagnose UI slowness or verify that your changes haven't degraded the user experience.", diff --git a/sanity_task.toml b/sanity_task.toml new file mode 100644 index 0000000..fb63870 --- /dev/null +++ b/sanity_task.toml @@ -0,0 +1,3 @@ +role = "tier3-worker" +prompt = "Read @ai_client.py and describe the current placeholder implementation of _send_deepseek. Just a one-sentence summary." +docs = ["ai_client.py"] diff --git a/task.toml b/task.toml new file mode 100644 index 0000000..a1026d8 --- /dev/null +++ b/task.toml @@ -0,0 +1,17 @@ +role = "tier3-worker" +prompt = """TASK: Implement streaming support for the DeepSeek provider in ai_client.py and add failing tests. + +INSTRUCTIONS: +1. In @tests/test_deepseek_provider.py: + - Add a test function 'test_deepseek_streaming' that mocks a streaming API response using 'requests.post(..., stream=True)'. + - Use 'mock_response.iter_lines()' to simulate chunks of data. + - Assert that 'ai_client.send()' correctly aggregates these chunks into a single string. + +2. In @ai_client.py: + - Modify the '_send_deepseek' function to use 'requests.post(..., stream=True)'. + - Implement a loop to iterate over the response lines using 'iter_lines()'. + - Aggregate the content from each chunk. + - Ensure the aggregated content is added to the history and returned by the function. + +OUTPUT: Provide the raw Python code for the modified sections or the full files. No pleasantries.""" +docs = ["conductor/workflow.md", "ai_client.py", "tests/test_deepseek_provider.py", "mcp_client.py"] diff --git a/tests/temp_project_history.toml b/tests/temp_project_history.toml index 62111b9..c3214c6 100644 --- a/tests/temp_project_history.toml +++ b/tests/temp_project_history.toml @@ -4,10 +4,20 @@ roles = [ "Vendor API", "System", ] -active = "main" +active = "testing deepseek" auto_add = true [discussions.main] git_commit = "" -last_updated = "2026-02-25T21:55:15" -history = [] +last_updated = "2026-02-25T23:33:11" +history = [ + "@2026-02-25T22:34:11\nSystem:\n[PERFORMANCE ALERT] CPU usage high: 92.2%. Please consider optimizing recent changes or reducing load.", +] + +[discussions."testing deepseek"] +git_commit = "" +last_updated = "2026-02-25T23:33:45" +history = [ + "@2026-02-25T23:33:21\nUser:\ntesting testing 123?", + "@2026-02-25T23:33:25\nAI:\nI see you're testing with \"testing testing 123\". I'm here and ready to help! I'm a helpful coding assistant with access to PowerShell and various tools for file operations and web access.\n\nWhat would you like me to help you with today? I can assist with:\n- Writing or editing code files\n- Searching for information\n- Reading or analyzing files\n- Running commands\n- Web searches\n- And much more!\n\nJust let me know what you need help with.", +]