跳到主要内容

自动化

自动化

自动化是位于 src/automation/+<name>.automation.ts 的后台工作:定时、事件驱动、由 webhook 触发,或手动发起。除集成的持久代码体(数据源的 read、出站规则的 run)外,它是唯一可以进行外部 I/O 的地方——HTTP、AI、邮件与聊天消息发送、文件渲染与地理编码。字面量声明触发器与权限;代码体用 a.run(…) 附加,且只能附加一次。

API 参考:automation

// 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 的工作、任何按时间或在提交之后进行的工作,以及需要汇报进度的批量工作。