667ccd70cd
Backend security & correctness: - Add rate_limit.py: sliding-window rate limiter (asyncio) applied to login, register, forgot/reset password endpoints (10/60s or 5/300s per IP) - app.py: add security headers in after_request (X-Frame-Options, CSP, X-Content-Type-Options, Referrer-Policy) using setdefault to preserve SSE headers - auth.py: refactor duplicate login_required/admin_required into shared _check_auth() - config.py: add TRUST_PROXY_HEADERS for proxy-aware client IP resolution - routes/auth.py: rate limiting, _client_ip() helper, cleaned-up reset_password route - routes/chat.py, notes.py, tasks.py: int() DoS fix on last_event_id; limit capped at 500; date.fromisoformat() wrapped in try/except → 400 on invalid dates - services/auth.py: fix Setting.user_id update bug (filter on NULL not user.id); reset_password_with_token returns int|None (user_id) instead of bool - services/backup.py: add _security_notice to full backup JSON export - services/assist.py: system prompt explicitly preserves markdown list structure and nested indented sub-items Infrastructure: - docker-compose.yml: add healthcheck on app service (/api/health, 10s interval) - .dockerignore: prevent secrets/node_modules/__pycache__/.env.* leaking into build Frontend bug fixes: - TaskCard.vue, TaskViewerView.vue: fix isOverdue() timezone bug (ISO string compare) - useAssist.ts: accept() now resets state to idle when document changed since proposal - stores/chat.ts: fix memory leak in _pollUntilLoaded() (try/catch around fetchStatus) - TiptapEditor.vue: selection offset uses closest-match strategy (not first-match) - utils/markdown.ts: explicit DOMPurify config with FORCE_BODY; remove as const (DOMPurify expects mutable string[]) New features: - Auto-save (5-minute interval) in NoteEditorView and TaskEditorView — only when editing an existing dirty record; silent on error, shows "Auto-saved" toast - sectionParser.ts: top-level bullet/numbered list items are now individual sections in the AI Assist panel (previously treated as one undifferentiated block) - editor-shared.css: extracted ~500 lines of CSS duplicated between both editors; includes .inline-assist-btn at global scope (required for teleported elements) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
42 lines
1.9 KiB
Python
42 lines
1.9 KiB
Python
MAX_BODY_CHARS = 8000
|
|
|
|
|
|
def build_assist_messages(
|
|
body: str, target_section: str, instruction: str
|
|
) -> list[dict]:
|
|
"""Build Ollama messages for section-level assist.
|
|
|
|
The full note body (truncated) is provided as read-only context in the
|
|
system prompt. The target section + user instruction go in the user
|
|
message. The model outputs only the replacement for the target section.
|
|
"""
|
|
truncated_body = body[:MAX_BODY_CHARS]
|
|
if len(body) > MAX_BODY_CHARS:
|
|
truncated_body += "\n... (truncated)"
|
|
|
|
system_content = (
|
|
"You are an AI writing assistant integrated into a note-taking app. "
|
|
"The user is editing a document. The full document is shown below for context.\n\n"
|
|
f"--- Full Document ---\n{truncated_body}\n--- End Document ---\n\n"
|
|
"The user will give you a specific section of the document and an instruction. "
|
|
"Output ONLY the replacement text for that section. "
|
|
"If the target section starts with a markdown heading (e.g. ## Heading), "
|
|
"your output MUST also start with a heading at the same level. "
|
|
"You may revise the heading text but do not remove it. "
|
|
"Do not include other sections, explanatory text, or markdown code fences around the output. "
|
|
"Match the document's existing tone and style. "
|
|
"IMPORTANT: Preserve all markdown formatting exactly — including bullet lists (- item), "
|
|
"numbered lists (1. item), nested/indented sub-items ( - sub), bold (**text**), "
|
|
"italic (_text_), and code blocks. Never flatten nested lists into plain text."
|
|
)
|
|
|
|
user_content = (
|
|
f"--- Target Section ---\n{target_section}\n--- End Target Section ---\n\n"
|
|
f"Instruction: {instruction}"
|
|
)
|
|
|
|
return [
|
|
{"role": "system", "content": system_content},
|
|
{"role": "user", "content": user_content},
|
|
]
|