语言参考
Agent Flow 语言的完整参考。权威实现:
packages/lang/src/language/agent-flow.langium(文法)与
packages/compiler/src/checker.ts(静态语义)。
词法
注释与空白
- 行注释
// ...;块注释/* ... */(可跨行,不可嵌套) - 空白与注释是隐藏 token;语言不区分换行
标识符
ID = /[_a-zA-Z][\w$]*/
字符串
| 形式 | 说明 |
|---|---|
"..." | 单行;转义 \" \\ \n \t \r,其余 \x 视为 x |
"""...""" | 多行;内容逐字保留;用于 task,仅裁掉首尾换行 |
数值与时长
| Token | 正则 | 说明 |
|---|---|---|
NUMBER | /\d+(\.\d+)?/ | 十进制;无负数字面量 |
DURATION | /\d+(ms|s|m|h)(?![a-zA-Z0-9_])/ | 500ms 5s 10m 2h;统一换算毫秒 |
分隔符惯例
| 结构 | 逗号 |
|---|---|
| 数组、tools、调用实参、retry 错误码 | 必需;适用处允许尾逗号 |
| 对象、type、limits、parallel 分支 | 必需;允许尾逗号 |
| workflow/stage/agent/verify 语句 | 不使用逗号 |
类型
TypeRef := PrimaryTypeRef Suffix*
PrimaryTypeRef := 'member' '<' Id '>' | Id
Suffix := '[' RangeBounds? ']'
RangeBounds := NUMBER '..' NUMBER
重复后缀可表达嵌套数组(path[][]);可选字段写作 field?: Type。
读取可选字段得到内部 T?,用 value ?? fallback 消除缺失可能;null 是显式空值。
类型种类、解析顺序、可赋值性与 JSON Schema 映射见 类型系统一页的完整表格。
顶层声明
Workflow := 'workflow' ID '(' 'input' ':' TypeRef (',' 'context' ':' TypeRef)? ')' '->' TypeRef '{' Member* '}'
UseStatement := 'use' ('agent' | 'team') STRING 'as' ID
LimitsBlock := 'limits' '{' LimitField+ '}'
LimitField := ('concurrency' | 'agent_runs' | 'duration') ':' (NUMBER | DURATION)
TypeDeclaration := 'type' ID '{' (FieldName '?'? ':' TypeRef (',' ...)* ','?)? '}'
管道与阶段
Pipeline := 'pipeline' ID? '{' PipelineStatement* '}'
Stage := 'stage' ID '->' TypeRef '{' StageStatement* '}'
- pipeline 的顶层最后一个语句必须是
return;if内允许类型安全的提前返回 - stage 名即结果变量;stage 按源序执行,体内可读取此前 stage 的结果
- 后续或不存在的 stage 名尚不可见,按未知变量诊断
语句
| 语句 | 文法 | 约束 |
|---|---|---|
| let | let ID = 表达式 | 同作用域不可重名 |
| require | require 表达式 else fail STRING | 条件必须 bool |
| emit | emit progress 对象字面量 | 仅 progress 事件 |
| return | return 表达式 | 类型须匹配声明 |
| if | if 表达式 { 语句+ } (else { 语句+ })? | 条件必须 bool;块作用域 |
表达式
优先级(由紧到松)
后缀 .member [*]投影 f(args)
比较 == != < <= > >= / in a..b(不可链式)
not not (作用于整个比较级操作数)
and and (左结合)
or or (左结合)
空值合并 ?? (右结合,最松)
not a == b 解析为 not (a == b);圆括号可显式分组。
optional ?? fallback 返回非可选的兼容公共类型。
字面量与基本形式
- 字符串/多行字符串/数值/布尔/时长
- 数组字面量
[e1, e2](逗号必需;推断兼容的公共元素 类型) - 对象字面量
{ f1, f2: e2 }:name: expr显式字段;name简写字段 等价name: name,name 必须是可见变量 - 成员访问
expr.member:- 对象类型 → 字段类型(不存在报
invalid-member-access) - 数组 → 仅
.count(number)、.empty/.any(bool) Verification→.passed/.failed/.checks- 外部类型 / context(any)→ 任意成员,结果 any
- 团队绑定 →
.main(agent-target) - 危险成员名
constructorprototype__proto____defineGetter____defineSetter____lookupGetter____lookupSetter__hasOwnPropertyisPrototypeOfpropertyIsEnumerabletoLocaleStringtoStringvalueOf一律拒绝(dangerous-member-access)
- 对象类型 → 字段类型(不存在报
- 投影
xs[*].field:xs必须数组;等价xs.map(x => x.field); 结果为字段类型数组;裸投影xs[*]不合法 - 调用
f(args):仅内建函数与team.member(...)(后者只能在 agent() 的 target 位置)
内建函数
| 函数 | 参数 | 结果 | 语义 |
|---|---|---|---|
unique(array) | 数组 | bool | 元素(按字符串化)无重复 |
disjoint(arrayOfArrays) | 数组的数组 | bool | 子数组两两无公共元素 |
union(arrayOfArrays) | 数组的数组 | 数组 | 顺序拼接所有子数组 |
range 与 in
a .. b:两侧须数值/时长;语法上只能作为in的右操作数x in a..b:闭区间,x >= a && x <= b- 比较、
in和范围不可链式书写
agent() 调用
AgentExpression := 'agent' '(' Expression ')' '{' AgentOption* '}'
AgentOption :=
'task' TaskString # 必需,唯一
| 'input' ObjectLiteral
| 'tools' 'none' | '[' (','? Id)* ']'
| 'write' Expression # 类型须为 path[]
| 'expect' TypeRef # 必需,唯一;不可 Verification/外部类型
| 'timeout' DURATION # 正时长
| 'retry' '{' 'attempts' ':' NUMBER ('on' ':' '[' Code (',' Code)* ']')? '}'
Code := 'timeout' | 'rate_limit' | 'transient'
target 三形态:别名 / team.main / team.member(expr)。
attempts 为额外次数;on 缺省 ['transient'];判定按错误码。
parallel / parallel map / verify
ParallelExpression := 'parallel' '{' (','? ID '=' Expression)+ '}'
ParallelMapExpression := 'parallel' 'map' Expression 'as' ID ('limit' NUMBER)? '{' Expression '}'
VerifyExpression := 'verify' '{' (','? VerifyCheck)* 'pass' 'when' Expression '}'
VerifyCheck := 'check' ID '=' Expression | 'parallel' '{' (','? 'check' ID '=' Expression)+ '}'
- parallel:分支并发,barrier 语义;结果
{分支名: 类型} - parallel map:源须数组;
limit正整数;结果顺序与输入一致;类型T[] → U[] - verify:check 名唯一;check 初始化在外层作用域,
pass when在 verify 作用域;结果Verification<{checks...}>
作用域
workflow :input、context(声明类型时强类型,否则 any)、use 别名
pipeline :+ 已完成 stage 结果(源序渐进)
stage :+ 源码中此前完成的 stage 结果
block :if then/else
map :循环变量
verify :check 名(仅 pass when 可见)
保留字与字段软关键字
以下词在变量、stage、type、资源别名、parallel/check/map 名称等位置是保留字:
agent agent_runs and as attempts
check concurrency else emit expect
fail false if in let
limit limits map none not
on or parallel pass pipeline
progress rate_limit require return retry
stage task team timeout tools
transient true type use verify
when write workflow
在 type 字段、对象字段和 .field 成员访问位置,它们是软关键字,
type Event { type: text, retry?: bool } 合法。input、context、
duration、member 也可作普通值标识符。该区分让外部 JSON 字段名
保持自由,同时保护会进入代码生成命名空间的声明名。
JS 风格的 while、for、function、class 不是保留字——但 V1
语法不存在这些语句,写出来同样报语法错误。
高频撞名场景
| 场景 | ✗ | ✓ |
|---|---|---|
| map 循环变量 | as task / as check / as map | item / job / slot |
| check 名 | check task = ... | tests / security / policy |
| parallel 分支名 | tools = ... | frontend = ...(普通名词) |
| 对象显式字段 | { type: value } |