b6989c3eea
List GET no longer ships transcripts; consult appends questions after reserve and ignores client history so dual-tab last-write-wins cannot erase messages. Co-authored-by: Cursor <cursoragent@cursor.com>
117 lines
3.4 KiB
PL/PgSQL
117 lines
3.4 KiB
PL/PgSQL
begin;
|
|
|
|
create or replace function public.append_consultation_question(
|
|
p_user_id uuid,
|
|
p_request_id text,
|
|
p_session_id uuid,
|
|
p_question_message jsonb
|
|
)
|
|
returns table(success boolean, error_code text)
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_session public.chat_sessions%rowtype;
|
|
v_message jsonb;
|
|
v_text text;
|
|
v_request_id text;
|
|
v_count integer;
|
|
v_chars integer;
|
|
v_new_chars integer;
|
|
begin
|
|
v_request_id := btrim(coalesce(p_request_id, ''));
|
|
if p_user_id is null or p_session_id is null or v_request_id = '' then
|
|
return query select false, 'invalid_request'::text;
|
|
return;
|
|
end if;
|
|
if jsonb_typeof(p_question_message) <> 'object'
|
|
or p_question_message->>'role' <> 'user' then
|
|
return query select false, 'invalid_question_message'::text;
|
|
return;
|
|
end if;
|
|
v_text := btrim(coalesce(p_question_message->>'text', ''));
|
|
if v_text = '' or char_length(v_text) > 16000 then
|
|
return query select false, 'invalid_question_message'::text;
|
|
return;
|
|
end if;
|
|
|
|
perform pg_advisory_xact_lock(hashtextextended(p_user_id::text || ':' || v_request_id, 0));
|
|
|
|
select session.* into v_session
|
|
from public.chat_sessions as session
|
|
where session.id = p_session_id
|
|
and session.user_id = p_user_id
|
|
and session.session_type = 'consultation'
|
|
for update;
|
|
|
|
if not found then
|
|
return query select false, 'session_missing'::text;
|
|
return;
|
|
end if;
|
|
|
|
if exists (
|
|
select 1
|
|
from jsonb_array_elements(coalesce(v_session.messages, '[]'::jsonb)) as elem
|
|
where elem->>'requestId' = v_request_id
|
|
) then
|
|
return query select true, null::text;
|
|
return;
|
|
end if;
|
|
|
|
v_count := jsonb_array_length(coalesce(v_session.messages, '[]'::jsonb));
|
|
select coalesce(sum(
|
|
length(coalesce(elem->>'text', ''))
|
|
+ length(coalesce(elem->>'thinkingText', ''))
|
|
+ case
|
|
when elem ? 'thinkingSections' then length((elem->'thinkingSections')::text)
|
|
else 0
|
|
end
|
|
), 0)
|
|
into v_chars
|
|
from jsonb_array_elements(coalesce(v_session.messages, '[]'::jsonb)) as elem;
|
|
|
|
v_new_chars := length(v_text);
|
|
if v_count >= 200 or (v_chars + v_new_chars) > 200000 then
|
|
return query select false, 'session_full'::text;
|
|
return;
|
|
end if;
|
|
|
|
v_message := p_question_message || jsonb_build_object('requestId', v_request_id);
|
|
|
|
update public.chat_sessions as session
|
|
set messages = coalesce(session.messages, '[]'::jsonb) || jsonb_build_array(v_message),
|
|
title = case
|
|
when coalesce(btrim(session.title), '') in ('', '新对话') then
|
|
case
|
|
when char_length(v_text) > 14 then left(v_text, 14) || '…'
|
|
else v_text
|
|
end
|
|
else session.title
|
|
end,
|
|
updated_at = clock_timestamp()
|
|
where session.id = p_session_id
|
|
and session.user_id = p_user_id
|
|
and session.session_type = 'consultation';
|
|
if not found then
|
|
return query select false, 'session_missing'::text;
|
|
return;
|
|
end if;
|
|
|
|
return query select true, null::text;
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.append_consultation_question(uuid, text, uuid, jsonb)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.append_consultation_question(uuid, text, uuid, jsonb)
|
|
to service_role;
|
|
do $$ begin
|
|
if exists(select 1 from pg_roles where rolname = 'admin_runtime') then
|
|
grant execute on function public.append_consultation_question(uuid, text, uuid, jsonb)
|
|
to admin_runtime;
|
|
end if;
|
|
end $$;
|
|
|
|
commit;
|