From aadea133e5ce877bd5afe4b66e3ae09311371224 Mon Sep 17 00:00:00 2001 From: ajosh0504 Date: Sun, 11 Jan 2026 16:40:58 -0800 Subject: [PATCH 1/2] Minor changes --- apps/project-assistant/backend/app/routers/helpers.py | 9 ++++++++- apps/project-assistant/backend/app/routers/routes.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/project-assistant/backend/app/routers/helpers.py b/apps/project-assistant/backend/app/routers/helpers.py index 7e7167b..9a22113 100644 --- a/apps/project-assistant/backend/app/routers/helpers.py +++ b/apps/project-assistant/backend/app/routers/helpers.py @@ -155,14 +155,21 @@ def image_to_base64(image_path: Path) -> dict: def save_assistant_message( - db, project_id: str, project_title: str, content: str, msg_date: datetime + db, + project_id: str, + project_title: str, + content: str, + version: int, + msg_date: datetime, ) -> None: """Save an assistant response message.""" db.messages.insert_one( { "project_id": project_id, "project_title": project_title, + "user_id": USER_ID, "role": "assistant", + "version": version, "content": content, "created_at": msg_date, } diff --git a/apps/project-assistant/backend/app/routers/routes.py b/apps/project-assistant/backend/app/routers/routes.py index a2faf42..7934cd1 100644 --- a/apps/project-assistant/backend/app/routers/routes.py +++ b/apps/project-assistant/backend/app/routers/routes.py @@ -70,7 +70,7 @@ def stream_and_save(): for path in image_paths: save_user_message(db, project_id, project_title, path, version, msg_date) save_assistant_message( - db, project_id, project_title, response_content, msg_date + db, project_id, project_title, response_content, version, msg_date ) return StreamingResponse(stream_and_save(), media_type="application/x-ndjson") From e0bffe941edb80d6ebbf7cde3aefe2e1aeb758b3 Mon Sep 17 00:00:00 2001 From: ajosh0504 Date: Sun, 11 Jan 2026 17:33:02 -0800 Subject: [PATCH 2/2] Changing LLM temp settings --- .../backend/app/routers/routes.py | 10 ++-- .../backend/app/services/anthropic.py | 19 ++----- .../backend/app/services/prompts.py | 22 ++++---- apps/project-assistant/frontend/src/App.css | 55 ------------------- apps/project-assistant/frontend/src/App.jsx | 36 +++--------- .../frontend/src/components/Entry.jsx | 28 ---------- 6 files changed, 28 insertions(+), 142 deletions(-) diff --git a/apps/project-assistant/backend/app/routers/routes.py b/apps/project-assistant/backend/app/routers/routes.py index 7934cd1..ba8321e 100644 --- a/apps/project-assistant/backend/app/routers/routes.py +++ b/apps/project-assistant/backend/app/routers/routes.py @@ -1,4 +1,3 @@ -import json import logging from datetime import datetime from typing import Optional @@ -59,10 +58,9 @@ def send_message( def stream_and_save(): response_content = "" - for chunk in generate_response(conversation, memories=memories): - yield json.dumps(chunk) + "\n" - if chunk["type"] == "response": - response_content += chunk["content"] + for text in generate_response(conversation, memories=memories): + yield text + response_content += text # Save messages to DB after streaming completes if content: @@ -73,7 +71,7 @@ def stream_and_save(): db, project_id, project_title, response_content, version, msg_date ) - return StreamingResponse(stream_and_save(), media_type="application/x-ndjson") + return StreamingResponse(stream_and_save(), media_type="text/plain") @router.get("/search") diff --git a/apps/project-assistant/backend/app/services/anthropic.py b/apps/project-assistant/backend/app/services/anthropic.py index 642fab7..2055ebc 100644 --- a/apps/project-assistant/backend/app/services/anthropic.py +++ b/apps/project-assistant/backend/app/services/anthropic.py @@ -32,7 +32,7 @@ def extract_memories(user_message: str) -> list[dict]: response = client.beta.messages.parse( model=ANTHROPIC_MODEL, max_tokens=2000, - temperature=1, + temperature=0, betas=["structured-outputs-2025-11-13"], system=MEMORY_EXTRACTION_PROMPT, messages=[{"role": "user", "content": user_message}], @@ -50,7 +50,7 @@ def extract_memories(user_message: str) -> list[dict]: def generate_response(messages: list[dict], memories: Optional[list[str]] = None): - """Generate a response with extended thinking.""" + """Generate a streaming response.""" logger.info( f"Generating response using {ANTHROPIC_MODEL} with {len(memories) if memories else 0} memories" ) @@ -62,18 +62,9 @@ def generate_response(messages: list[dict], memories: Optional[list[str]] = None with client.messages.stream( model=ANTHROPIC_MODEL, - max_tokens=16000, - temperature=1, - thinking={ - "type": "enabled", - "budget_tokens": 8000, - }, + max_tokens=4096, + temperature=0, system=system_prompt, messages=messages, ) as stream: - for event in stream: - if event.type == "content_block_delta": - if hasattr(event.delta, "thinking"): - yield {"type": "thinking", "content": event.delta.thinking} - elif hasattr(event.delta, "text"): - yield {"type": "response", "content": event.delta.text} + yield from stream.text_stream diff --git a/apps/project-assistant/backend/app/services/prompts.py b/apps/project-assistant/backend/app/services/prompts.py index f4267ef..0f2b6e7 100644 --- a/apps/project-assistant/backend/app/services/prompts.py +++ b/apps/project-assistant/backend/app/services/prompts.py @@ -23,22 +23,24 @@ ]""" -SYSTEM_PROMPT = """You are an AI-powered developer productivity assistant. +SYSTEM_PROMPT = """You are an AI-powered project-planning assistant. Your role is to help developers plan and break down projects into actionable steps. -IMPORTANT: When context about the user's preferences or past decisions is provided, reference them naturally to maintain consistency. +IMPORTANT: When context about the user's preferences or past decisions is provided, actively reference them in your response. Guidelines: -- Help break down projects into smaller, manageable tasks +- Break down projects into smaller, manageable tasks - Ask clarifying questions about requirements, tech stack, and constraints - Suggest best practices and potential approaches -- Identify dependencies and potential blockers early -- Reference past preferences (e.g., "You typically prefer TypeScript - should we use that here?") +- Actively reference past preferences - Keep responses concise and actionable -Formatting: -- Use plain text and bullet points only - no headers or titles -- Keep it conversational and direct -- Use numbered lists for sequential steps +STRICT Formatting Rules: +- NO headers, titles, or section labels +- NO markdown formatting (no **, #, etc.) +- Use simple bullet points with dashes (-) +- Use numbered lists (1. 2. 3.) only for sequential steps +- Write in plain conversational text +- Keep paragraphs short -Remember: You're a planning assistant. Help developers think through their projects systematically.""" +Remember, your goal is to assist developers in planning their projects effectively while respecting their established preferences and decisions.""" diff --git a/apps/project-assistant/frontend/src/App.css b/apps/project-assistant/frontend/src/App.css index 3d66664..057941b 100644 --- a/apps/project-assistant/frontend/src/App.css +++ b/apps/project-assistant/frontend/src/App.css @@ -821,61 +821,6 @@ display: block; } -/* Thinking section */ -.thinking-section { - margin-bottom: 12px; -} - -.thinking-toggle { - display: flex; - align-items: center; - gap: 6px; - padding: 8px 12px; - background: var(--mongodb-off-white); - border: 1px solid var(--mongodb-gray-light); - border-radius: 4px; - font-family: inherit; - font-size: 13px; - color: var(--mongodb-slate); - cursor: pointer; - transition: all 0.15s ease; -} - -.thinking-toggle:hover { - background: var(--mongodb-white); - border-color: var(--mongodb-dark-green); - color: var(--mongodb-slate); -} - -.thinking-toggle.expanded { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - border-bottom-color: transparent; -} - -.thinking-icon { - font-size: 10px; - transition: transform 0.15s ease; -} - -.thinking-label { - font-weight: 500; -} - -.thinking-content { - padding: 12px 16px; - background: var(--mongodb-off-white); - border: 1px solid var(--mongodb-gray-light); - border-top: none; - border-radius: 0 0 4px 4px; - font-size: 13px; - line-height: 1.6; - color: var(--mongodb-slate); - white-space: pre-wrap; - max-height: 300px; - overflow-y: auto; -} - /* Date picker modal */ .date-picker-overlay { position: fixed; diff --git a/apps/project-assistant/frontend/src/App.jsx b/apps/project-assistant/frontend/src/App.jsx index eb16e6f..ccaacc2 100644 --- a/apps/project-assistant/frontend/src/App.jsx +++ b/apps/project-assistant/frontend/src/App.jsx @@ -118,43 +118,21 @@ function App() { body: formData }) - // Read newline-delimited JSON stream + // Read text stream const reader = res.body.getReader() const decoder = new TextDecoder() - let buffer = '' - let thinkingContent = '' let responseContent = '' while (true) { const { done, value } = await reader.read() if (done) break - buffer += decoder.decode(value, { stream: true }) - - // Process complete JSON lines - const lines = buffer.split('\n') - buffer = lines.pop() // Keep incomplete line in buffer - - for (const line of lines) { - if (!line.trim()) continue - try { - const chunk = JSON.parse(line) - if (chunk.type === 'thinking') { - thinkingContent += chunk.content - } else if (chunk.type === 'response') { - responseContent += chunk.content - } - - // Update message with current state - setMessages(prev => prev.map(msg => - msg._id === aiMessageId - ? { ...msg, thinking: thinkingContent, content: responseContent } - : msg - )) - } catch (e) { - console.error('Failed to parse chunk:', e) - } - } + responseContent += decoder.decode(value, { stream: true }) + setMessages(prev => prev.map(msg => + msg._id === aiMessageId + ? { ...msg, content: responseContent } + : msg + )) } } diff --git a/apps/project-assistant/frontend/src/components/Entry.jsx b/apps/project-assistant/frontend/src/components/Entry.jsx index 464f826..37ed5e0 100644 --- a/apps/project-assistant/frontend/src/components/Entry.jsx +++ b/apps/project-assistant/frontend/src/components/Entry.jsx @@ -8,17 +8,9 @@ function Entry({ messages, onSendMessage, hasActiveProject, activeProject, proje const [searchResults, setSearchResults] = useState(null) const [isSearching, setIsSearching] = useState(false) const [saveStatus, setSaveStatus] = useState(null) - const [expandedThinking, setExpandedThinking] = useState({}) const messagesEndRef = useRef(null) const fileInputRef = useRef(null) - const toggleThinking = (msgId) => { - setExpandedThinking(prev => ({ - ...prev, - [msgId]: !prev[msgId] - })) - } - const handleSaveProject = async () => { setSaveStatus('saving') try { @@ -179,26 +171,6 @@ function Entry({ messages, onSendMessage, hasActiveProject, activeProject, proje
{msg.role === 'user' ? 'You' : 'Assistant'}
- {msg.thinking && ( -
- - {expandedThinking[msg._id] && ( -
- {msg.thinking} -
- )} -
- )} {msg.content && (
{msg.content}