148 lines
5.5 KiB
PL/PgSQL
148 lines
5.5 KiB
PL/PgSQL
begin;
|
|
|
|
-- BUG-177: starting birth-time rectification from the homepage is an explicit
|
|
-- create action. Existing unfinished cases remain resumable through their
|
|
-- exact history/session entry, but no longer block a separate new case.
|
|
drop index if exists public.agentic_rectification_cases_one_resumable_per_user;
|
|
|
|
create or replace function public.open_agentic_rectification_case(
|
|
p_user_id uuid,
|
|
p_request_id uuid,
|
|
p_intent text,
|
|
p_session_id uuid,
|
|
p_skill_name text,
|
|
p_skill_version text,
|
|
p_baseline_profile_fingerprint text,
|
|
p_baseline_birth_snapshot jsonb,
|
|
p_candidate_range jsonb
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
v_session public.chat_sessions%rowtype;
|
|
v_session_id uuid;
|
|
begin
|
|
if p_user_id is null or p_request_id is null then
|
|
raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001';
|
|
end if;
|
|
if p_intent not in ('homepage', 'session', 'new') then
|
|
raise exception 'agentic_rectification_invalid_intent' using errcode = 'P0001';
|
|
end if;
|
|
if length(btrim(p_skill_name)) = 0 or length(btrim(p_skill_version)) = 0
|
|
or length(btrim(coalesce(p_baseline_profile_fingerprint, ''))) = 0 then
|
|
raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001';
|
|
end if;
|
|
|
|
-- Serialize same-user opens so a repeated requestId is deterministic. A
|
|
-- separate click carries a separate requestId and is allowed to create.
|
|
perform pg_catalog.pg_advisory_xact_lock(
|
|
pg_catalog.hashtext('agentic_rectification_open:' || p_user_id::text)
|
|
);
|
|
|
|
select c.* into v_case
|
|
from public.agentic_rectification_cases c
|
|
join public.agentic_rectification_open_ledger l
|
|
on l.case_id = c.id and l.session_id = c.session_id
|
|
where l.user_id = p_user_id and l.request_id = p_request_id
|
|
limit 1;
|
|
|
|
if found then
|
|
return jsonb_build_object(
|
|
'disposition', case
|
|
when v_case.status = any (public.agentic_rectification_resumable_statuses()) then 'resumed'
|
|
else 'readonly'
|
|
end,
|
|
'case_id', v_case.id,
|
|
'session_id', v_case.session_id,
|
|
'status', v_case.status,
|
|
'should_start_opening', false,
|
|
'skill_version', v_case.skill_version
|
|
);
|
|
end if;
|
|
|
|
if p_intent = 'session' then
|
|
if p_session_id is null then
|
|
raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001';
|
|
end if;
|
|
select * into v_session
|
|
from public.chat_sessions
|
|
where id = p_session_id and user_id = p_user_id;
|
|
if not found then
|
|
raise exception 'agentic_rectification_session_not_found' using errcode = 'P0001';
|
|
end if;
|
|
if v_session.session_type <> 'birth_time_rectification' then
|
|
raise exception 'agentic_rectification_session_not_rectification' using errcode = 'P0001';
|
|
end if;
|
|
select * into v_case
|
|
from public.agentic_rectification_cases
|
|
where session_id = p_session_id;
|
|
if not found then
|
|
raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
|
|
end if;
|
|
return jsonb_build_object(
|
|
'disposition', case
|
|
when v_case.status = any (public.agentic_rectification_resumable_statuses()) then 'resumed'
|
|
else 'readonly'
|
|
end,
|
|
'case_id', v_case.id,
|
|
'session_id', v_case.session_id,
|
|
'status', v_case.status,
|
|
'should_start_opening', false,
|
|
'skill_version', v_case.skill_version
|
|
);
|
|
end if;
|
|
|
|
if p_baseline_birth_snapshot is null or jsonb_typeof(p_baseline_birth_snapshot) <> 'object'
|
|
or p_baseline_birth_snapshot ->> 'birth_date' is null
|
|
or p_baseline_birth_snapshot ->> 'latitude' is null
|
|
or p_baseline_birth_snapshot ->> 'longitude' is null
|
|
or p_baseline_birth_snapshot ->> 'timezone_offset' is null
|
|
or length(btrim(coalesce(p_baseline_birth_snapshot ->> 'birth_time_source', ''))) = 0 then
|
|
raise exception 'agentic_rectification_profile_incomplete' using errcode = 'P0001';
|
|
end if;
|
|
if p_candidate_range is null or jsonb_typeof(p_candidate_range) <> 'object'
|
|
or not (p_candidate_range ->> 'start_time') ~ '^([01][0-9]|2[0-3]):[0-5][0-9]$'
|
|
or not (p_candidate_range ->> 'end_time') ~ '^([01][0-9]|2[0-3]):[0-5][0-9]$' then
|
|
raise exception 'agentic_rectification_invalid_range' using errcode = 'P0001';
|
|
end if;
|
|
|
|
insert into public.chat_sessions (user_id, title, theme, session_type, messages)
|
|
values (p_user_id, '生时校正', 'general', 'birth_time_rectification', '[]'::jsonb)
|
|
returning id into v_session_id;
|
|
|
|
insert into public.agentic_rectification_cases (
|
|
user_id, session_id, status, skill_name, skill_version,
|
|
baseline_profile_fingerprint, baseline_birth_snapshot, candidate_range
|
|
) values (
|
|
p_user_id, v_session_id, 'draft', p_skill_name, p_skill_version,
|
|
p_baseline_profile_fingerprint, p_baseline_birth_snapshot, p_candidate_range
|
|
) returning * into v_case;
|
|
|
|
insert into public.agentic_rectification_open_ledger (
|
|
request_id, user_id, case_id, session_id, intent
|
|
) values (
|
|
p_request_id, p_user_id, v_case.id, v_session_id, p_intent
|
|
);
|
|
|
|
return jsonb_build_object(
|
|
'disposition', 'created',
|
|
'case_id', v_case.id,
|
|
'session_id', v_session_id,
|
|
'status', v_case.status,
|
|
'should_start_opening', true,
|
|
'skill_version', v_case.skill_version
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.open_agentic_rectification_case(uuid, uuid, text, uuid, text, text, text, jsonb, jsonb)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.open_agentic_rectification_case(uuid, uuid, text, uuid, text, text, text, jsonb, jsonb)
|
|
to service_role;
|
|
|
|
commit;
|