自动化
自动化
自动化是位于 src/automation/+<name>.automation.ts 的后台工作:定时、事件驱动、由 webhook 触发,或手动发起。除集成的持久代码体(数据源的 read、出站规则的 run)外,它是唯一可以进行外部 I/O 的地方——HTTP、AI、邮件与聊天消息发送、文件渲染与地理编码。字面量声明触发器与权限;代码体用 a.run(…) 附加,且只能附加一次。
// src/automation/+permit_expiry_watch.automation.ts (templates/construction)
import { automation } from '@norbital-ai/bolt';
import { DAILY_0600, digestOutput, jsonRows } from '../lib/digest.ts';
const a = automation({
description:
'Sweeps the active and expiring permits to work every morning at 6am and publishes the first 25 as a JSON extract …',
on: DAILY_0600,
runAs: ['construction_read'],
output: digestOutput
});
export default a;
a.run(function* (_, ctx) {
const { rows } = yield* ctx.read('permits_to_work', {
where: { status: { in: ['active', 'expiring_soon'] } },
orderBy: { requested_date: 'asc' },
limit: 25
});
return { generated_at: ctx.now, count: rows.length, rows: jsonRows(rows) };
});
// src/lib/digest.ts (excerpt)
export const digestOutput = {
kind: 'object',
fields: {
generated_at: { kind: 'instant' },
count: { kind: 'int' },
rows: { kind: 'list', of: { kind: 'json' } }
}
} as const;
export const DAILY_0600 = { cron: '0 6 * * *' } as const; 触发器
{ cron, tz? }——五个字段或一个宏,默认使用工作区时区,除非tz另行指定。{ created | updated | deleted: '<collection>', where?, delay? }——updated还可以指定fields。where只在触发写入时计算一次;运行会收到触发行的ids(deleted运行还会收到它们删除前的内容),并自行重新检查其状态。{ webhook: '/<path>', verify: { scheme, secret } }——支持的方案有bearer、hmac-sha256、svix、stripe、slack与meta。- 没有
on——只能手动发起:页面中的bolt.start、工具栏中的start项、操作或其他运行中的ctx.schedule,或 Agent。
// src/automation/+review_job_assignment_suspicion.automation.ts (templates/field-operations, excerpt)
const review = automation({
description: 'When an assignment is filed or changes: inspects photos awaiting facts, then reviews …',
on: [
{ created: 'job_assignments' },
{
updated: 'job_assignments',
fields: ['suspicion_checked_at'],
where: { suspicion_checked_at: { isNull: true } }
}
],
input: {
/** Event runs: the assignments that fired. */
ids: { kind: 'list', of: { kind: 'id', of: 'job_assignments' }, optional: true },
/** Manual runs may target one unchecked assignment. */
assignment_id: { kind: 'id', of: 'job_assignments', optional: true }
},
output: { kind: 'object', fields: { assignment_count: { kind: 'int' } /* … */ } },
runAs: ['suspicion_review_automation'],
concurrency: { max: 1 }
});
export default review; 权限
runAs 指定运行所依据的策略,其读取与写入与其他人一样按这些策略的授权评判。runAs: 'trigger' 以发起者的身份运行,只允许用于没有 on 的自动化。当成员的某个策略在 automations 中列出某个自动化时,该成员可以发起它。
运行
一次运行就是一次调用。它的 ctx 以 runAs 的身份读取、写入、调度与通知,并额外提供 send、request、web、files、ai 与 geo,以及 progress、attempt 与 cause。声明的 output 是运行可读取的结果,由 RunStatus 与运行页面显示。一次调用容纳不下的工作,可以用 ctx.schedule 按块分发,或为自己安排后续运行。
调度
ctx.schedule(name, input) 尽快排入一次运行;ctx.schedule(name, input, { at, key? }) 在之后的时间排入,相同 key 的已排队运行会被替换。retry: { attempts, backoff? } 只重试暂时性失败,concurrency: { max } 限制并行运行数。没有任何轮询:每个未来的运行都是一行带到期时间的排队记录。
自动化、操作还是 transform?
- transform——在写入内部完成的派生与拒绝。
- 操作——调用方会等待其完成的具名、带类型的写入,没有 I/O。
- 自动化——任何涉及 I/O 或 AI 的工作、任何按时间或在提交之后进行的工作,以及需要汇报进度的批量工作。