运行时、沙箱与错误
.flow 不是被解释执行的——它被编译成受限 JavaScript,在沙箱里跑。
本页讲执行模型、agent 调用的宿主管线、事件与错误码。
执行模型
一次 run 的完整旅程:
- 输入校验:workflow 输入按 input 类型的 JSON Schema 校验
(外部类型 Schema 为
{},接受任意);失败 →WorkflowInputValidationError - 沙箱装载:编译产物在子进程 →
isolated-vm→ 可信 bootstrap ($runtimeABI)中执行;唯一出网通道是$host.invoke(op, payload), 跨边界值只能是 JSON - 确定性执行:pipeline/stage/if/parallel/parallelMap/verify/require/
投影/内建函数在 bootstrap 内确定执行;
agent调用与事件转发到宿主侧 - 输出校验:最终返回值按输出类型 Schema 再校验一次;失败 →
OutputValidationError
第 2、4 步意味着:跨界数据永远是可信的、可序列化的。
agent 调用的宿主管线
每一次 agent() 都走同一条管线:
检查取消/期限
→ agent_runs 预算(超限 = LimitExceededError)
→ 并发闸(semaphore)
→ target 解析
team.main / team.member → 成员资格校验(失败 = CapabilityViolationError)
→ tools 收窄(请求 ∩ host policy)
→ write 策略描述符
→ OutputContract{schema, repairAttempts}
→ [尝试循环]
限时调用:min(timeout, 剩余期限) 的 AbortSignal + Promise 竞速
(迟到结果永不生效)
→ 结构化 → Ajv 校验
→ 失败且预算未尽 → 携带 {previousOutput, errors} 修复重调
→ 失败且错误 码 ∈ retry.on 且次数未尽 → 重试
→ 事件 agent.started / agent.completed / agent.failed
事件
FlowEventSink.emit 转发全部事件,类型包括:
workflow.started / workflow.completed / workflow.failed
pipeline.started / pipeline.completed / pipeline.failed
stage.started / stage.completed / stage.failed
agent.started / agent.completed / agent.failed
verify.evaluated / require.failed / progress
emit progress {...} 只产生 progress 事件——Runtime 不关心消费方,
CLI / WebSocket / OpenTelemetry 由宿主接入。事件流是 workflow
可观测性的一等入口。
运行时错误码
| 码 | 错误类 | 产生时机 |
|---|---|---|
workflow-input-validation | WorkflowInputValidationError | 输入未通过 Schema |
output-validation | OutputValidationError | agent 输出(修复耗尽)或 workflow 输出未通过 Schema |
agent-invocation | AgentInvocationError | agent 调用失败/超时 |
capability-violation | CapabilityViolationError | 非团队成员解析、target 非法等 |
limit-exceeded | LimitExceededError | agent_runs 超限 |
workflow-timeout | WorkflowTimeoutError | duration 超限 |
assertion | WorkflowAssertionError | require 失败 |
cancelled | FlowCancelledError | 外部取消 |
isolate | FlowIsolateError | isolate 内部错误 |
worker-crashed | FlowWorkerCrashedError | 沙箱子进程崩溃(所有 pending promise 随之 reject) |
错误跨进程传递用 DTO(__flowError: true + code/message/stage/span/details),
宿主侧重构为类型化错误。retry.on 匹配的是这里的错误码,不是 message。
序列化边界
跨 进程 / isolate / host ABI 的值仅限 JSON: null / bool / number / string / array / plain object。 这就是为什么语言里没有函数值、没有类实例、没有循环引用—— 所有数据结构天生可序列化,是编译目标而不是运行时约定。
编译期 vs 运行期
错误分两层,先编译期后运行期:
- 编译期(
flow check):语法、语义、类型,50 余种诊断码, 见语言参考。 有 error 级诊断时不产出可执行代码 - 运行期:上表的错误码,多数对应声明式结构(
limits/timeout/require/expect),即:把失败模式写进声明,让运行时替你看着