Download app/core/session/session_content.py from bg5/zai: direct link, hf CLI and curl.
- Browser
- Download file 8.18 kB
-
https://huggingface.co/spaces/bg5/zai/resolve/main/app/core/session/session_content.py
- Command line
-
hf download hf://spaces/bg5/zai/app/core/session/session_content.py
-
curl -L -o session_content.py https://huggingface.co/spaces/bg5/zai/resolve/main/app/core/session/session_content.py
8.18 kB
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| """Message content preparation helpers. | |
| Provides functions to flatten message content, concatenate conversation | |
| history, choose the correct turn content, inject system prompts, and | |
| build the final messages list used in session / direct modes. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any, Dict, List | |
| # --------------------------------------------------------------------------- | |
| # Low-level content helpers | |
| # --------------------------------------------------------------------------- | |
| def content_to_text(content: Any) -> str: | |
| """Best-effort flatten message content into plain text.""" | |
| if isinstance(content, str): | |
| return content | |
| if isinstance(content, list): | |
| parts: List[str] = [] | |
| for item in content: | |
| if isinstance(item, str) and item: | |
| parts.append(item) | |
| continue | |
| if isinstance(item, dict) and item.get("type") == "text": | |
| text = item.get("text") | |
| if isinstance(text, str) and text: | |
| parts.append(text) | |
| return " ".join(parts) | |
| if content is None: | |
| return "" | |
| return str(content) | |
| def concat_history(messages: List[Dict[str, Any]]) -> str: | |
| """Concatenate non-system messages into a single text block. | |
| Used when a session is lost / new and we need to replay history into | |
| a single upstream user message. System messages are skipped because | |
| the upstream model configuration handles them separately. | |
| """ | |
| parts: List[str] = [] | |
| for msg in messages: | |
| role = msg.get("role", "user") | |
| if role == "system": | |
| continue | |
| content = msg.get("content", "") | |
| if isinstance(content, list): | |
| content = " ".join( | |
| item.get("text", "") | |
| for item in content | |
| if isinstance(item, dict) and item.get("type") == "text" | |
| ) | |
| if content: | |
| parts.append(f"[{role}]: {content}") | |
| return "\n\n".join(parts) | |
| def extract_turn_content( | |
| raw_messages: List[Dict[str, Any]], | |
| normalized_messages: List[Dict[str, Any]], | |
| fallback_user_text: str, | |
| ) -> str: | |
| """Choose the appropriate content for the current turn. | |
| - last raw role == user -> send that user text | |
| - last raw role == tool -> send the last user text from normalized messages | |
| - otherwise -> fallback to *fallback_user_text* | |
| """ | |
| if raw_messages: | |
| last_raw = raw_messages[-1] | |
| if isinstance(last_raw, dict): | |
| last_role = str(last_raw.get("role") or "") | |
| if last_role == "user": | |
| text = content_to_text(last_raw.get("content")) | |
| if text.strip(): | |
| return text | |
| elif last_role == "tool": | |
| # tool messages are converted to plain user messages during normalization | |
| for msg in reversed(normalized_messages): | |
| if not isinstance(msg, dict) or msg.get("role") != "user": | |
| continue | |
| content = content_to_text(msg.get("content")) | |
| if content.strip(): | |
| return content | |
| return fallback_user_text | |
| # --------------------------------------------------------------------------- | |
| # System prompt injection (works for both session and direct modes) | |
| # --------------------------------------------------------------------------- | |
| def inject_system_prompt( | |
| messages: List[Dict[str, Any]], | |
| ) -> List[Dict[str, Any]]: | |
| """Merge all system messages into the first user message. | |
| Extracts every ``role=system`` entry, concatenates their text, and | |
| prepends it to the first ``role=user`` message's content. The | |
| system entries are removed from the returned list. | |
| If there are no system messages or no user messages, the list is | |
| returned unchanged (shallow copy). | |
| This is used in **both** session mode and direct mode when | |
| ``SESSION_SYSTEM_INJECT`` is enabled. | |
| """ | |
| # Collect system text | |
| system_parts: List[str] = [] | |
| for msg in messages: | |
| if msg.get("role") == "system": | |
| text = content_to_text(msg.get("content")) | |
| if text.strip(): | |
| system_parts.append(text.strip()) | |
| if not system_parts: | |
| return list(messages) | |
| system_text = "\n\n".join(system_parts) | |
| # Build new list: skip system, inject into first user message | |
| result: List[Dict[str, Any]] = [] | |
| injected = False | |
| for msg in messages: | |
| if msg.get("role") == "system": | |
| continue | |
| if not injected and msg.get("role") == "user": | |
| user_content = content_to_text(msg.get("content")) | |
| result.append({ | |
| **msg, | |
| "content": system_text + "\n\n" + user_content, | |
| }) | |
| injected = True | |
| else: | |
| result.append(msg) | |
| return result | |
| # --------------------------------------------------------------------------- | |
| # High-level session body builders | |
| # --------------------------------------------------------------------------- | |
| def build_session_body_messages( | |
| normalized_messages: List[Dict[str, Any]], | |
| session_turn_content: str, | |
| is_new_session: bool, | |
| inject_system: bool = True, | |
| ) -> List[Dict[str, Any]]: | |
| """Build the messages list for session mode body. | |
| Args: | |
| normalized_messages: Full preprocessed message list (for extracting | |
| system prompts and history). | |
| session_turn_content: The current turn's content (from | |
| ``extract_turn_content``). | |
| is_new_session: ``True`` if no existing session was found. | |
| inject_system: If ``True``, concatenate the system prompt into the | |
| user message content. If ``False``, pass the system prompt as | |
| a separate ``system`` message. | |
| Returns: | |
| Messages list for the upstream body. In session mode this is | |
| typically 1 message (inject) or 2 messages (pass-through with | |
| system). | |
| """ | |
| if not is_new_session: | |
| # Reuse session: upstream already has the system prompt from turn 1 | |
| return [{"role": "user", "content": session_turn_content}] | |
| # ---- New session: handle system prompt ---- | |
| system_parts: List[str] = [] | |
| for msg in normalized_messages: | |
| if msg.get("role") != "system": | |
| continue | |
| system_text_part = content_to_text(msg.get("content")).strip() | |
| if system_text_part: | |
| system_parts.append(system_text_part) | |
| system_text = "\n\n".join(system_parts) | |
| # Build history content (for multi-message recovery) | |
| raw_msg_count = sum(1 for m in normalized_messages if m.get("role") != "system") | |
| if raw_msg_count > 1: | |
| # Multiple non-system messages: concatenate history | |
| history_text = concat_history(normalized_messages) | |
| else: | |
| history_text = session_turn_content | |
| if not system_text: | |
| # No system prompt: just send user content | |
| return [{"role": "user", "content": history_text}] | |
| if inject_system: | |
| # Inject mode: concatenate system + content into single user message | |
| return [{"role": "user", "content": system_text + "\n\n" + history_text}] | |
| else: | |
| # Pass-through mode: system as separate message | |
| return [ | |
| {"role": "system", "content": system_text}, | |
| {"role": "user", "content": history_text}, | |
| ] | |
| def get_precreate_content( | |
| session_body_messages: List[Dict[str, Any]], | |
| ) -> str: | |
| """Extract the text content to pass to ``_precreate_chat`` from session body messages. | |
| Simply concatenates all message contents into a single string. | |
| """ | |
| parts: List[str] = [] | |
| for msg in session_body_messages: | |
| text = content_to_text(msg.get("content")).strip() | |
| if text: | |
| parts.append(text) | |
| return "\n\n".join(parts) | |