merge: fix/logs-perf

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-06 19:57:20 +08:00
commit 60ca662530
7 files changed
+855 -144

No files matched your search

+293 -142
View File
@@ -5,7 +5,8 @@ import { redact } from "../../logger.ts";
import { BUSINESS_EXPR } from "../auth-settings/engine-business.ts";
// 日志聚合查询(界面第二轮 V 线):四个来源各自出同一组列,按 (at, id) 倒序各取 limit+1 条,union 后再取前 limit 条。
// 每个来源单独 order + limit,PG 能沿各自的时间索引倒着扫,不需要把全部来源物化再排序。
// 每个来源单独 order + limit,PG 能沿各自的时间索引倒着扫,不需要把全部来源物化再排序;
// 筛选只用原始列,标题等昂贵列只对取出的行算(见 SourceBuilder)。
//
// 来源与口径(docs/runbook/logs.md):
// - engine_run → task:引擎一次运行;时间 = 创建时间;标题 = 业务对象名(没有时为工作流名);对象 = 业务对象
@@ -54,11 +55,73 @@ const SOURCE_TYPES: Record<LogSource, LogType[]> = {
const UUID_RE = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
function engineSource(schema: string): RawBuilder<unknown> {
/** 关键词命中的业务对象每类最多取这么多个(只影响「按业务标题搜任务」,标题极泛的词会漏掉更早的对象) */
export const KEYWORD_OBJECT_CAP = 2000;
/** 各来源共用的已解析筛选 */
interface Filter {
types: Set<LogType> | null;
levels: LogLevel[] | null;
from: Date | null;
to: Date | null;
/** ilike 模式(已转义,带 %) */
like: string | null;
/** 关键词命中的业务对象 "kind:id"(只给引擎来源用) */
matched: string[];
objectType: string | null;
objectId: string | null;
hideRoutine: boolean;
cursor: Cursor | null;
}
/**
* 每个来源分两段:
* 1. 只用原始列(及一次性算好的业务引用)筛选,`order by 时间 desc, 日志 id desc limit n`,PG 沿时间索引倒着扫、凑够 n 条就停;
* 2. 只对这 n 行算标题、对象标签、extra 等昂贵列。
* 以前是先构造带派生列(标题子查询、search 拼接)的子查询再在外层筛选,带筛选时要对全部引擎运行算一遍派生列。
*/
type SourceBuilder = (f: Filter, n: number) => RawBuilder<unknown>;
/** 时间范围与游标条件;at、logId 是该来源的时间列与日志 id 表达式 */
function commonConds(f: Filter, at: RawBuilder<unknown>, logId: RawBuilder<unknown>): RawBuilder<unknown>[] {
const out: RawBuilder<unknown>[] = [];
if (f.from) out.push(sql`${at} >= ${f.from}`);
if (f.to) out.push(sql`${at} < ${f.to}`);
if (f.cursor) {
const ts = sql`(timestamptz 'epoch' + ${f.cursor.us} * interval '1 microsecond')`;
// 拆成 at <= ts(可走索引)+ 同一时刻再比日志 id,与 (at, id) < (ts, id) 等价
out.push(sql`${at} <= ${ts} and (${at} < ${ts} or ${logId} < ${f.cursor.id})`);
}
return out;
}
const andAll = (conds: RawBuilder<unknown>[]) => (conds.length ? sql.join(conds, sql` and `) : sql`true`);
const levelIn = (expr: RawBuilder<unknown>, f: Filter) => (f.levels ? [sql`${expr} = any(${f.levels}::text[])`] : []);
function engineSource(schema: string): SourceBuilder {
if (!/^[a-z_][a-z0-9_]*$/.test(schema)) throw new Error(`非法 schema 名 ${schema}`);
const t = sql.raw(`"${schema}".workflow_runs`);
const kind = sql`(biz.b->>'kind')`;
const ref = sql`(biz.b->>'refId')`;
const st = sql.raw("workflow_runs.status");
const logId = sql`('engine_run:' || workflow_runs.id)`;
// 第一段:业务引用 BUSINESS_EXPR 每行只算一次(offset 0 阻止子查询上拉,否则每处引用都会把整个表达式展开重算)。
// 智能体结果(级别、例行要用)的 lateral 也加 offset 0:保持逐行嵌套循环,凑够 n 条就停;
// 不加时规划器会改成与 agent_run 的哈希连接,要先扫完全部运行。
const kind1 = sql`(biz.b->>'kind')`;
const ref1 = sql`(biz.b->>'refId')`;
const uuid1 = sql`(case when ${ref1} ~* ${UUID_RE} then ${ref1}::uuid end)`;
const level = sql`(case
when ${st} = 'failed' then 'error'
when ${st} = 'canceled' then 'warn'
when ${st} in ('completed', 'succeeded') then (case ag.status
when 'failed' then 'error' when 'budget_exceeded' then 'warn' when 'cancelled' then 'warn' else 'success' end)
else 'running' end)`;
const routine = sql`(biz.b is null
or coalesce(${kind1} = 'schedule' and ${st} in ('completed', 'succeeded'), false)
or coalesce(ag.trigger in ('event', 'schedule'), false))`;
// 第二段:p.kind / p.ref 是第一段带出来的列
const kind = sql.raw("p.kind");
const ref = sql.raw("p.ref");
const uuidRef = sql`(case when ${ref} ~* ${UUID_RE} then ${ref}::uuid end)`;
const objectType = sql`(case ${kind} ${sql.join(
Object.entries(BUSINESS_OBJECT_TYPE).map(([k, v]) => sql`when ${sql.lit(k)} then ${sql.lit(v)}`),
@@ -77,128 +140,211 @@ function engineSource(schema: string): RawBuilder<unknown> {
when 'decision' then (select d.title from decision d where d.id = ${uuidRef})
when 'media' then (select e.title from media_entity e where e.id = ${uuidRef})
end)`;
const agent = sql`(case when ${kind} = 'agent' then
(select jsonb_build_object('status', a.status, 'trigger', a.trigger) from agent_run a where a.id = ${uuidRef}) end)`;
const st = sql.raw("workflow_runs.status");
return sql`select
'engine_run:' || workflow_runs.id as id,
'task'::text as type,
'engine_run'::text as source,
workflow_runs.id::text as ref_id,
workflow_runs.created_at as at,
workflow_runs.finished_at as finished_at,
(case when workflow_runs.finished_at is not null and workflow_runs.started_at is not null
then extract(epoch from workflow_runs.finished_at - workflow_runs.started_at) * 1000 end)::float8 as duration_ms,
(case
when ${st} = 'failed' then 'error'
when ${st} = 'canceled' then 'warn'
when ${st} in ('completed', 'succeeded') then (case ag.a->>'status'
when 'failed' then 'error' when 'budget_exceeded' then 'warn' when 'cancelled' then 'warn' else 'success' end)
else 'running' end) as level,
${st}::text as status,
coalesce(bt.title, workflow_runs.workflow_name) as title,
(case when ${st} = 'failed' then left(coalesce(workflow_runs.error->>'message', workflow_runs.error::text), 500) end)
as message,
${objectType} as object_type,
${ref} as object_id,
bt.title as object_label,
null::text as actor_type,
null::text as actor_id,
jsonb_build_object('workflowName', workflow_runs.workflow_name, 'businessKind', ${kind},
'businessRefId', ${ref}, 'businessTitle', bt.title, 'outcome', ag.a->>'status',
'agentTrigger', ag.a->>'trigger', 'attempts', workflow_runs.attempts) as extra,
(biz.b is null
or coalesce(${kind} = 'schedule' and ${st} in ('completed', 'succeeded'), false)
or coalesce((ag.a->>'trigger') in ('event', 'schedule'), false)) as routine,
concat_ws(' ', workflow_runs.workflow_name, workflow_runs.id, bt.title, ${ref},
left(workflow_runs.error::text, 500)) as search
from ${t}
cross join lateral (select ${BUSINESS_EXPR} as b) biz
cross join lateral (select ${title} as title) bt
cross join lateral (select ${agent} as a) ag
where workflow_runs.namespace_id = 'default'`;
return (f, n) => {
const conds: RawBuilder<unknown>[] = [
sql`workflow_runs.namespace_id = 'default'`,
...commonConds(f, sql`workflow_runs.created_at`, logId),
];
conds.push(...levelIn(level, f));
if (f.hideRoutine) conds.push(sql`not ${routine}`);
if (f.like) {
// 标题命中 → 业务引用在命中集合里;其余按原始列(工作流名、运行 id、业务对象 id、错误)
conds.push(sql`(${f.matched.length ? sql`(${kind1} || ':' || ${ref1}) = any(${f.matched}::text[]) or ` : sql``}
workflow_runs.workflow_name ilike ${f.like} or workflow_runs.id ilike ${f.like} or ${ref1} ilike ${f.like}
or left(workflow_runs.error::text, 500) ilike ${f.like})`);
}
if (f.objectType) {
const kinds = Object.entries(BUSINESS_OBJECT_TYPE)
.filter(([, v]) => v === f.objectType)
.map(([k]) => k);
conds.push(kinds.length ? sql`${kind1} = any(${kinds}::text[])` : sql`false`);
}
if (f.objectId) conds.push(sql`${ref1} = ${f.objectId}`);
return sql`select
'engine_run:' || p.id as id,
'task'::text as type,
'engine_run'::text as source,
p.id::text as ref_id,
p.created_at as at,
p.finished_at as finished_at,
(case when p.finished_at is not null and p.started_at is not null
then extract(epoch from p.finished_at - p.started_at) * 1000 end)::float8 as duration_ms,
p.level,
p.status::text as status,
coalesce(bt.title, p.workflow_name) as title,
(case when p.status = 'failed' then left(coalesce(p.error->>'message', p.error::text), 500) end) as message,
${objectType} as object_type,
${ref} as object_id,
bt.title as object_label,
null::text as actor_type,
null::text as actor_id,
jsonb_build_object('workflowName', p.workflow_name, 'businessKind', ${kind},
'businessRefId', ${ref}, 'businessTitle', bt.title, 'outcome', p.agent_status,
'agentTrigger', p.agent_trigger, 'attempts', p.attempts) as extra
from (
select workflow_runs.id, workflow_runs.created_at, workflow_runs.started_at, workflow_runs.finished_at,
workflow_runs.status, workflow_runs.workflow_name, workflow_runs.error, workflow_runs.attempts,
${kind1} as kind, ${ref1} as ref, ag.status as agent_status, ag.trigger as agent_trigger, ${level} as level
from ${t}
cross join lateral (select ${BUSINESS_EXPR} as b offset 0) biz
left join lateral (select a.status::text as status, a.trigger::text as trigger from agent_run a
where ${kind1} = 'agent' and a.id = ${uuid1} offset 0) ag on true
where ${andAll(conds)}
order by workflow_runs.created_at desc, ${logId} desc
limit ${n}
) p
cross join lateral (select ${title} as title offset 0) bt`;
};
}
const SCHEDULE_SOURCE = sql`select
'schedule_run:' || r.id::text as id,
'auto'::text as type,
'schedule_run'::text as source,
r.id::text as ref_id,
r.started_at as at,
r.finished_at as finished_at,
r.duration_ms::float8 as duration_ms,
(case
// 定时任务运行、智能体后台调查、审计:行数少、列都在本行(定时任务只多一个小表 join),两段合成一条查询:
// 级别 / 类型 / 例行 / 关键词都是本行列上的表达式,直接放进 where,再按时间倒序取 n 条。
const scheduleSource: SourceBuilder = (f, n) => {
const logId = sql`('schedule_run:' || r.id::text)`;
const level = sql`(case
when r.status = 'failed' or r.agent_status = 'failed' then 'error'
when r.agent_status in ('budget_exceeded', 'cancelled') then 'warn'
when r.status = 'ok' then 'success'
when r.status = 'skipped' then 'info'
else 'running' end) as level,
r.status::text as status,
coalesce(j.name, r.job_id) as title,
coalesce(r.error, r.summary) as message,
'scheduled_job'::text as object_type,
r.job_id as object_id,
j.name as object_label,
r.trigger::text as actor_type,
null::text as actor_id,
jsonb_build_object('jobId', r.job_id, 'jobKind', j.kind, 'trigger', r.trigger, 'agentRunId', r.agent_run_id,
'agentStatus', r.agent_status, 'summary', r.summary, 'error', r.error) as extra,
(r.status in ('ok', 'skipped') and coalesce(j.kind::text, 'task') <> 'agent_check'
and r.agent_status is distinct from 'failed') as routine,
concat_ws(' ', r.job_id, j.name, r.summary, r.error, r.agent_run_id::text) as search
from scheduled_job_run r left join scheduled_job j on j.id = r.job_id`;
else 'running' end)`;
const conds = [...commonConds(f, sql`r.started_at`, logId), ...levelIn(level, f)];
if (f.hideRoutine) {
conds.push(sql`not (r.status in ('ok', 'skipped') and coalesce(j.kind::text, 'task') <> 'agent_check'
and r.agent_status is distinct from 'failed')`);
}
if (f.like) {
conds.push(sql`concat_ws(' ', r.job_id, j.name, r.summary, r.error, r.agent_run_id::text) ilike ${f.like}`);
}
if (f.objectType && f.objectType !== "scheduled_job") conds.push(sql`false`);
if (f.objectId) conds.push(sql`r.job_id = ${f.objectId}`);
return sql`select
${logId} as id,
'auto'::text as type,
'schedule_run'::text as source,
r.id::text as ref_id,
r.started_at as at,
r.finished_at as finished_at,
r.duration_ms::float8 as duration_ms,
${level} as level,
r.status::text as status,
coalesce(j.name, r.job_id) as title,
coalesce(r.error, r.summary) as message,
'scheduled_job'::text as object_type,
r.job_id as object_id,
j.name as object_label,
r.trigger::text as actor_type,
null::text as actor_id,
jsonb_build_object('jobId', r.job_id, 'jobKind', j.kind, 'trigger', r.trigger, 'agentRunId', r.agent_run_id,
'agentStatus', r.agent_status, 'summary', r.summary, 'error', r.error) as extra
from scheduled_job_run r left join scheduled_job j on j.id = r.job_id
where ${andAll(conds)}
order by r.started_at desc, ${logId} desc
limit ${n}`;
};
const AGENT_SOURCE = sql`select
'agent_run:' || a.id::text as id,
'auto'::text as type,
'agent_run'::text as source,
a.id::text as ref_id,
a.created_at as at,
a.finished_at as finished_at,
(case when a.finished_at is not null and a.started_at is not null
then extract(epoch from a.finished_at - a.started_at) * 1000 end)::float8 as duration_ms,
(case a.status
const agentSource: SourceBuilder = (f, n) => {
const logId = sql`('agent_run:' || a.id::text)`;
const level = sql`(case a.status
when 'succeeded' then 'success' when 'failed' then 'error'
when 'cancelled' then 'warn' when 'budget_exceeded' then 'warn' else 'running' end) as level,
a.status::text as status,
a.goal as title,
coalesce(a.summary, a.error->>'message', a.spawn_reason) as message,
'agent_run'::text as object_type,
a.id::text as object_id,
null::text as object_label,
'event'::text as actor_type,
a.created_by as actor_id,
jsonb_build_object('trigger', a.trigger, 'mode', a.mode, 'toolCalls', a.tool_call_count,
'spawnReason', a.spawn_reason, 'model', a.model) as extra,
false as routine,
concat_ws(' ', a.goal, a.summary, a.id::text, left(a.error::text, 500)) as search
from agent_run a where a.trigger = 'event' and a.parent_run_id is null`;
when 'cancelled' then 'warn' when 'budget_exceeded' then 'warn' else 'running' end)`;
const conds = [
sql`a.trigger = 'event' and a.parent_run_id is null`,
...commonConds(f, sql`a.created_at`, logId),
...levelIn(level, f),
];
if (f.like) {
conds.push(sql`concat_ws(' ', a.goal, a.summary, a.id::text, left(a.error::text, 500)) ilike ${f.like}`);
}
if (f.objectType && f.objectType !== "agent_run") conds.push(sql`false`);
if (f.objectId) conds.push(sql`a.id::text = ${f.objectId}`);
return sql`select
${logId} as id,
'auto'::text as type,
'agent_run'::text as source,
a.id::text as ref_id,
a.created_at as at,
a.finished_at as finished_at,
(case when a.finished_at is not null and a.started_at is not null
then extract(epoch from a.finished_at - a.started_at) * 1000 end)::float8 as duration_ms,
${level} as level,
a.status::text as status,
a.goal as title,
coalesce(a.summary, a.error->>'message', a.spawn_reason) as message,
'agent_run'::text as object_type,
a.id::text as object_id,
null::text as object_label,
'event'::text as actor_type,
a.created_by as actor_id,
jsonb_build_object('trigger', a.trigger, 'mode', a.mode, 'toolCalls', a.tool_call_count,
'spawnReason', a.spawn_reason, 'model', a.model) as extra
from agent_run a
where ${andAll(conds)}
order by a.created_at desc, ${logId} desc
limit ${n}`;
};
const AUDIT_SOURCE = sql`select
'audit_event:' || e.id::text as id,
(case when e.action like 'admin.%' or e.action like 'api_key.%' then 'auth' else 'audit' end) as type,
'audit_event'::text as source,
e.id::text as ref_id,
e.at as at,
null::timestamptz as finished_at,
null::float8 as duration_ms,
(case
const auditSource: SourceBuilder = (f, n) => {
const logId = sql`('audit_event:' || e.id::text)`;
const type = sql`(case when e.action like 'admin.%' or e.action like 'api_key.%' then 'auth' else 'audit' end)`;
const level = sql`(case
when e.action in ('admin.login_failed', 'capability.denied') then 'warn'
when e.action in ('admin.login_success', 'admin.passkey_login', 'admin.setup') then 'success'
else 'info' end) as level,
e.action as status,
e.action as title,
(case when e.action like 'admin.%' then concat_ws(' · ', e.payload->>'username', e.payload->>'ip')
else nullif(concat_ws(' · ', e.payload->>'reason', e.payload->>'error'), '') end) as message,
e.target_type as object_type,
e.target_id as object_id,
null::text as object_label,
e.actor_type as actor_type,
e.actor_id as actor_id,
jsonb_build_object('action', e.action, 'traceId', e.trace_id, 'payload', e.payload) as extra,
false as routine,
concat_ws(' ', e.action, e.target_type, e.target_id, e.actor_id, left(e.payload::text, 2000)) as search
from audit_event e`;
else 'info' end)`;
const conds = [...commonConds(f, sql`e.at`, logId), ...levelIn(level, f)];
if (f.types) conds.push(sql`${type} = any(${[...f.types]}::text[])`);
if (f.like) {
conds.push(sql`concat_ws(' ', e.action, e.target_type, e.target_id, e.actor_id, left(e.payload::text, 2000))
ilike ${f.like}`);
}
if (f.objectType) conds.push(sql`e.target_type = ${f.objectType}`);
if (f.objectId) conds.push(sql`e.target_id = ${f.objectId}`);
return sql`select
${logId} as id,
${type} as type,
'audit_event'::text as source,
e.id::text as ref_id,
e.at as at,
null::timestamptz as finished_at,
null::float8 as duration_ms,
${level} as level,
e.action as status,
e.action as title,
(case when e.action like 'admin.%' then concat_ws(' · ', e.payload->>'username', e.payload->>'ip')
else nullif(concat_ws(' · ', e.payload->>'reason', e.payload->>'error'), '') end) as message,
e.target_type as object_type,
e.target_id as object_id,
null::text as object_label,
e.actor_type as actor_type,
e.actor_id as actor_id,
jsonb_build_object('action', e.action, 'traceId', e.trace_id, 'payload', e.payload) as extra
from audit_event e
where ${andAll(conds)}
order by e.at desc, ${logId} desc
limit ${n}`;
};
/**
* 关键词命中的业务对象("kind:id"),口径与引擎运行的标题一致(标题 = 业务对象名);每类最多 KEYWORD_OBJECT_CAP 个。
* 这些表都不大,先查出 id 集合,引擎来源再按业务引用 ∈ 集合筛选,不用对每条运行算标题。
*/
async function keywordObjects(db: Kysely<DB>, like: string): Promise<string[]> {
const cap = KEYWORD_OBJECT_CAP;
const r = await sql<{ k: string }>`
(select 'schedule:' || j.id as k from scheduled_job j where j.name ilike ${like} limit ${cap})
union all (select 'agent:' || a.id from agent_run a where a.goal ilike ${like} limit ${cap})
union all (select 'download:' || d.id from download_task d where d.name ilike ${like} limit ${cap})
union all (select 'organization:' || r.id from organization_record r left join media_entity e on e.id = r.media_entity_id
where coalesce(e.title, r.target_path, r.source_path) ilike ${like} limit ${cap})
union all (select 'subscription:' || s.id from subscription s left join media_entity e on e.id = s.media_entity_id
where coalesce(e.title, s.title_query) ilike ${like} limit ${cap})
union all (select 'feed:' || f.id from feed_source f where f.name ilike ${like} limit ${cap})
union all (select 'site:' || s.id from site s where s.name ilike ${like} limit ${cap})
union all (select 'decision:' || d.id from decision d where d.title ilike ${like} limit ${cap})
union all (select 'media:' || e.id from media_entity e where e.title ilike ${like} limit ${cap})`.execute(db);
return r.rows.map((x) => x.k);
}
type Row = {
id: string;
@@ -234,6 +380,7 @@ export interface LogQueries {
export function logQueries(db: Kysely<DB>, opts: { engineSchema?: string } = {}): LogQueries {
const engineSchema = opts.engineSchema ?? "openworkflow";
const engine = engineSource(engineSchema);
let engineReady = false;
const engineExists = async () => {
if (engineReady) return true;
@@ -247,35 +394,39 @@ export function logQueries(db: Kysely<DB>, opts: { engineSchema?: string } = {})
return {
async list(q) {
const types = q.type?.length ? new Set(q.type) : null;
const sources: [LogSource, RawBuilder<unknown>][] = [];
const want = (s: LogSource) => !types || SOURCE_TYPES[s].some((t) => types.has(t));
if (want("engine_run") && (await engineExists())) sources.push(["engine_run", engineSource(engineSchema)]);
if (want("schedule_run")) sources.push(["schedule_run", SCHEDULE_SOURCE]);
if (want("agent_run")) sources.push(["agent_run", AGENT_SOURCE]);
if (want("audit_event")) sources.push(["audit_event", AUDIT_SOURCE]);
if (!sources.length) return { items: [], nextCursor: null };
const conds: RawBuilder<unknown>[] = [];
if (types) conds.push(sql`s.type = any(${[...types]}::text[])`);
if (q.level?.length) conds.push(sql`s.level = any(${q.level}::text[])`);
if (q.from) conds.push(sql`s.at >= ${new Date(q.from)}`);
if (q.to) conds.push(sql`s.at < ${new Date(q.to)}`);
if (q.q) conds.push(sql`s.search ilike ${`%${escapeLike(q.q)}%`}`);
if (q.objectType) conds.push(sql`s.object_type = ${q.objectType}`);
if (q.objectId) conds.push(sql`s.object_id = ${q.objectId}`);
if (q.system !== "1" && !q.objectId) conds.push(sql`not s.routine`);
const cur = decodeCursor(q.cursor);
if (cur) {
conds.push(sql`(s.at, s.id) < (timestamptz 'epoch' + ${cur.us} * interval '1 microsecond', ${cur.id})`);
}
const where = conds.length ? sql`where ${sql.join(conds, sql` and `)}` : sql``;
const withEngine = want("engine_run") && (await engineExists());
const like = q.q ? `%${escapeLike(q.q)}%` : null;
const f: Filter = {
types,
levels: q.level?.length ? q.level : null,
from: q.from ? new Date(q.from) : null,
to: q.to ? new Date(q.to) : null,
like,
matched: like && withEngine ? await keywordObjects(db, like) : [],
objectType: q.objectType || null,
objectId: q.objectId || null,
hideRoutine: q.system !== "1" && !q.objectId,
cursor: decodeCursor(q.cursor),
};
const n = q.limit + 1;
const parts = sources.map(
([, src]) => sql`(select s.* from (${src}) s ${where} order by s.at desc, s.id desc limit ${n})`,
);
const rows = await sql<Row>`select u.*, (extract(epoch from u.at) * 1000000)::bigint as cursor_us
from (${sql.join(parts, sql` union all `)}) u
order by u.at desc, u.id desc limit ${n}`.execute(db);
const parts: RawBuilder<unknown>[] = [];
if (withEngine) parts.push(engine(f, n));
if (want("schedule_run")) parts.push(scheduleSource(f, n));
if (want("agent_run")) parts.push(agentSource(f, n));
if (want("audit_event")) parts.push(auditSource(f, n));
if (!parts.length) return { items: [], nextCursor: null };
// 表达式很长,估算代价会触发 JIT,编译一次就要上秒;这条查询只取几百行,关掉 JIT
const rows = await db.transaction().execute(async (trx) => {
await sql`set local jit = off`.execute(trx);
return sql<Row>`select u.*, (extract(epoch from u.at) * 1000000)::bigint as cursor_us
from (${sql.join(
parts.map((p) => sql`(${p})`),
sql` union all `,
)}) u
order by u.at desc, u.id desc limit ${n}`.execute(trx);
});
const items = rows.rows.slice(0, q.limit);
const last = items[items.length - 1];
return {