@@ -3067,6 +3067,10 @@ async def outlet_filter_handler(ctx):
30673067 Replaces the separate POST /api/chat/completed round-trip.
30683068 Persists outlet-modified content to DB and emits a chat:outlet event
30693069 so the frontend can sync its in-memory state.
3070+
3071+ For temp chats (local: prefix), messages are built from form_data
3072+ plus the assistant response message stored in ctx['assistant_message'],
3073+ since temp chats have no DB-persisted history.
30703074 """
30713075 request = ctx ['request' ]
30723076 user = ctx ['user' ]
@@ -3078,17 +3082,43 @@ async def outlet_filter_handler(ctx):
30783082 chat_id = metadata .get ('chat_id' , '' )
30793083 message_id = metadata .get ('message_id' )
30803084
3081- if not chat_id or chat_id . startswith ( 'local:' ) or not message_id :
3085+ if not chat_id or not message_id :
30823086 return
30833087
3088+ is_temp_chat = chat_id .startswith ('local:' )
3089+
30843090 try :
3085- messages_map = await Chats .get_messages_map_by_chat_id (chat_id )
3086- if not messages_map :
3087- return
3091+ messages_map = None
30883092
3089- message_list = get_message_list (messages_map , message_id )
3090- if not message_list :
3091- return
3093+ if is_temp_chat :
3094+ # Temp chats have no DB record — build message list from
3095+ # the in-memory form_data plus the assistant response.
3096+ form_messages = ctx .get ('form_data' , {}).get ('messages' , [])
3097+ assistant_message = ctx .get ('assistant_message' , {})
3098+
3099+ message_list = [
3100+ {
3101+ 'role' : m .get ('role' ),
3102+ 'content' : m .get ('content' , '' ),
3103+ }
3104+ for m in form_messages
3105+ ]
3106+
3107+ # Append the full assistant message (content, output, usage, etc.)
3108+ if assistant_message :
3109+ message_list .append ({
3110+ 'id' : message_id ,
3111+ 'role' : 'assistant' ,
3112+ ** assistant_message ,
3113+ })
3114+ else :
3115+ messages_map = await Chats .get_messages_map_by_chat_id (chat_id )
3116+ if not messages_map :
3117+ return
3118+
3119+ message_list = get_message_list (messages_map , message_id )
3120+ if not message_list :
3121+ return
30923122
30933123 model_id = model .get ('id' ) if isinstance (model , dict ) else model
30943124
@@ -3101,6 +3131,7 @@ async def outlet_filter_handler(ctx):
31013131 'content' : m .get ('content' , '' ),
31023132 'info' : m .get ('info' ),
31033133 'timestamp' : m .get ('timestamp' ),
3134+ ** ({'output' : m ['output' ]} if m .get ('output' ) else {}),
31043135 ** ({'usage' : m ['usage' ]} if m .get ('usage' ) else {}),
31053136 ** ({'sources' : m ['sources' ]} if m .get ('sources' ) else {}),
31063137 }
@@ -3141,20 +3172,22 @@ async def outlet_filter_handler(ctx):
31413172 )
31423173
31433174 # Persist outlet-modified content and notify frontend
3175+ # (skip DB persistence for temp chats — they have no DB record)
31443176 if outlet_result and outlet_result .get ('messages' ):
3145- for msg in outlet_result ['messages' ]:
3146- msg_id = msg .get ('id' )
3147- if msg_id and msg_id in messages_map :
3148- original = messages_map [msg_id ]
3149- if original .get ('content' ) != msg .get ('content' ):
3150- await Chats .upsert_message_to_chat_by_id_and_message_id (
3151- chat_id ,
3152- msg_id ,
3153- {
3154- 'content' : msg ['content' ],
3155- 'originalContent' : original .get ('content' ),
3156- },
3157- )
3177+ if not is_temp_chat and messages_map :
3178+ for message in outlet_result ['messages' ]:
3179+ outlet_message_id = message .get ('id' )
3180+ if outlet_message_id and outlet_message_id in messages_map :
3181+ original_message = messages_map [outlet_message_id ]
3182+ if original_message .get ('content' ) != message .get ('content' ):
3183+ await Chats .upsert_message_to_chat_by_id_and_message_id (
3184+ chat_id ,
3185+ outlet_message_id ,
3186+ {
3187+ 'content' : message ['content' ],
3188+ 'originalContent' : original_message .get ('content' ),
3189+ },
3190+ )
31583191
31593192 if event_emitter :
31603193 await event_emitter (
@@ -3288,6 +3321,11 @@ async def non_streaming_chat_response_handler(response, ctx):
32883321 )
32893322
32903323 await background_tasks_handler (ctx )
3324+ ctx ['assistant_message' ] = {
3325+ 'content' : content ,
3326+ 'output' : response_output ,
3327+ ** ({'usage' : usage } if usage else {}),
3328+ }
32913329 await outlet_filter_handler (ctx )
32923330
32933331 response = build_response_object (response , merge_events_into_response (response_data , events ))
@@ -4800,6 +4838,11 @@ async def restricted_import(name, globals=None, locals=None, fromlist=(), level=
48004838 )
48014839
48024840 await background_tasks_handler (ctx )
4841+ ctx ['assistant_message' ] = {
4842+ 'content' : serialize_output (output ),
4843+ 'output' : output ,
4844+ ** ({'usage' : usage } if usage else {}),
4845+ }
48034846 await outlet_filter_handler (ctx )
48044847 except asyncio .CancelledError :
48054848 log .warning ('Task was cancelled!' )
0 commit comments