Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.250.201"
VERSION = "0.250.202"
IS_DEVELOPMENT = is_development_env_enabled()

SESSION_COOKIE_SAMESITE = os.getenv('SESSION_COOKIE_SAMESITE', 'Lax')
Expand Down
37 changes: 37 additions & 0 deletions application/single_app/functions_chat_stream_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# functions_chat_stream_events.py

import json
from typing import Any, Dict


USER_MESSAGE_PERSISTED_EVENT_TYPE = "user_message_persisted"


def build_user_message_persisted_stream_payload(
conversation_id: str,

Check warning on line 11 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
user_message_id: str,
) -> Dict[str, Any]:
"""Build the SSE payload that acknowledges durable user-message storage."""

Check warning on line 14 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
normalized_conversation_id = str(conversation_id or "").strip()

Check warning on line 15 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
normalized_user_message_id = str(user_message_id or "").strip()
if not normalized_conversation_id or not normalized_user_message_id:

Check warning on line 17 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
raise ValueError("conversation_id and user_message_id are required")

Check warning on line 18 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.

return {
"type": USER_MESSAGE_PERSISTED_EVENT_TYPE,
"conversation_id": normalized_conversation_id,

Check warning on line 22 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
"user_message_id": normalized_user_message_id,
"message_persisted": True,
}


def build_user_message_persisted_stream_event(
conversation_id: str,

Check warning on line 29 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
user_message_id: str,
) -> str:
"""Serialize a user-message persistence acknowledgement as an SSE event."""
payload = build_user_message_persisted_stream_payload(
conversation_id,

Check warning on line 34 in application/single_app/functions_chat_stream_events.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
user_message_id,
)
return f"data: {json.dumps(payload)}\n\n"
27 changes: 26 additions & 1 deletion application/single_app/route_backend_chats.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
from functions_global_agents import get_global_agents
from functions_group_agents import get_group_agents
from functions_personal_agents import get_personal_agents
from functions_chat_stream_events import build_user_message_persisted_stream_event
from functions_source_review import (
build_deep_research_ledger,
build_deep_research_ledger_markdown,
Expand Down Expand Up @@ -15020,6 +15021,13 @@ def execute_document_action_chat_request(
'metadata': user_metadata,
})
cosmos_messages_container.upsert_item(user_message_doc)
if callable(publish_background_event):
publish_background_event(
build_user_message_persisted_stream_event(
conversation_id,

Check warning on line 15027 in application/single_app/route_backend_chats.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
user_message_id,
)
)

try:
document_action_activity_context = {
Expand Down Expand Up @@ -15880,6 +15888,11 @@ def generate_image_from_proposal():
@login_required
@user_required
def chat_api():
publish_background_event = getattr(

Check warning on line 15891 in application/single_app/route_backend_chats.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Moderate - Changed line contains obfuscation, dynamic loading, or hidden payload marker. Recommendation%3A Confirm the changed code is not hiding behavior, decoding payloads, or bypassing normal review.
g,
'chat_publish_background_event',
None,
)
try:
request_start_time = time.time()
settings = get_settings()
Expand Down Expand Up @@ -16932,6 +16945,13 @@ def result_requires_message_reload(result: Any) -> bool:
# Note: Message-level chat_type will be updated after document search

cosmos_messages_container.upsert_item(user_message_doc)
if callable(publish_background_event):
publish_background_event(
build_user_message_persisted_stream_event(
conversation_id,
user_message_id,
)
)

# Log chat activity for real-time tracking
try:
Expand Down Expand Up @@ -20099,7 +20119,7 @@ def normalize_legacy_chat_payload(payload):
'blocked': payload.get('blocked', False),
})

def generate_compatibility_response():
def generate_compatibility_response(publish_background_event=None):
"""Bridge legacy JSON chat handling into a terminal SSE event for parity cases."""
try:
g.conversation_id = finalized_conversation_id
Expand All @@ -20122,6 +20142,7 @@ def generate_compatibility_response():
}
yield f"data: {json.dumps(image_request_event)}\n\n"

g.chat_publish_background_event = publish_background_event
legacy_result = chat_api()
legacy_response = legacy_result
status_code = 200
Expand Down Expand Up @@ -21205,6 +21226,10 @@ def build_streaming_capability_usage():
}

cosmos_messages_container.upsert_item(user_message_doc)
yield build_user_message_persisted_stream_event(
conversation_id,
user_message_id,
)
debug_print(
f"[STREAMING] Saved user message {user_message_id} | thread_id={current_user_thread_id} | previous_thread_id={previous_thread_id}"
)
Expand Down
11 changes: 11 additions & 0 deletions application/single_app/route_backend_collaboration.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
update_personal_collaboration_title,
)
from functions_conversation_cache import bump_conversation_cache_version
from functions_chat_stream_events import (
USER_MESSAGE_PERSISTED_EVENT_TYPE,
build_user_message_persisted_stream_event,
)
from functions_group import assert_group_role, check_group_status_allows_operation, find_group_by_id, require_active_group
from functions_image_messages import decode_image_content, get_complete_image_content, is_blob_backed_image_message, is_external_image_url
from functions_message_masking import (
Expand Down Expand Up @@ -1449,6 +1453,10 @@ def stream_collaboration_message_api(conversation_id):

def generate_stream():
try:
yield build_user_message_persisted_stream_event(
conversation_id,
serialized_user_message.get('id'),
)
internal_stream_view = current_app.view_functions.get('chat_stream_api')
if not callable(internal_stream_view):
yield _serialize_stream_error(
Expand Down Expand Up @@ -1508,6 +1516,9 @@ def transform_event_block(event_block):
conversation_id=conversation_id,
)

if stream_payload.get('type') == USER_MESSAGE_PERSISTED_EVENT_TYPE:
return None

if not stream_payload.get('done'):
return normalized_event_block + '\n\n'

Expand Down
8 changes: 8 additions & 0 deletions application/single_app/static/js/chat/chat-collaboration.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getCollaborativeTagSuggestions,
getGeneratedImageProposalSourceMessageId,
groupGeneratedImageProposalMessages,
setUserMessageStreamingActionsDisabled,
updateSendButtonVisibility,
updateUserMessageId,
userInput,
Expand Down Expand Up @@ -1074,6 +1075,12 @@ function handleConversationEvent(eventEnvelope = {}) {
const decoratedMessage = decorateReplyMessage(payload.message);
cacheCollaborationMessage(payload.message);
if (reconcilePendingCollaborativeUserMessage(payload.message)) {
const messageKind = String(
payload.message.message_kind || payload.message.metadata?.message_kind || ''
).trim();
if (senderUserId === getCurrentUserId() && messageKind !== 'ai_request') {
setUserMessageStreamingActionsDisabled(payload.message.id, false);
}
if (shouldClearNotifications) {
void markCollaborationConversationRead(eventEnvelope.conversation_id || payload.message.conversation_id, {
suppressErrorToast: true,
Expand Down Expand Up @@ -1308,6 +1315,7 @@ async function sendCollaborativeMessage(messageText, tempMessageId = null) {
if (!reconcilePendingCollaborativeUserMessage(payload.message, tempMessageId)) {
renderCollaborationMessage(decorateReplyMessage(payload.message), { isNewMessage: true });
}
setUserMessageStreamingActionsDisabled(payload.message.id, false);
}

setTypingState(false, { force: true });
Expand Down
Loading
Loading