Skip to content

[P2] flow: create_record node value semantics ambiguous (literal vs CEL vs macro vs ref) #1315

Description

@xuyushun441-sys

来源:docs/PLATFORM_GAPS_FROM_TEMPLATES.md 第 16 条(P2)。

现象

Flow 节点 create_record 的 value 字段语义不明:

  • 字面字符串?
  • CEL 表达式?
  • macro?
  • 同名 source 字段引用?

模板作者写流靠猜,文档没有明确指引哪个字段是哪种解析。

复现

{
  kind: 'create_record',
  object: 'helpdesk_message',
  values: {
    body: '{{ai_suggested_reply}}',  // 这是 macro?
    ticket: '$source.id',             // 这是引用?
    direction: 'outbound',            // 字面?
  },
}
// 实际行为不一致,部分字段被原样字符串化

建议范围

M1:统一语义

  • 显式区分:{ literal: '...' } / { expr: '...' } / { ref: 'source.field' }
  • 或:所有 value 默认 CEL,字面值用 '"text"'

M2:文档 + IDE

  • 节点参考文档配示例
  • TS 类型让 IDE 提示语义

M3:lint / build 校验

  • 编译时校验 value 写法 + 提示常见错误

验收

Activity

  1. os-zhuang commented on Jun 15, 2026

    @os-zhuang
    Contributor

    Closing — the framework already has one consistent, deterministic value-resolution contract for flow node values; the confusion in the repro was wrong-syntax guessing ({{double-brace}}, $source.x), not inconsistent behavior. The single source of truth is the interpolate() engine (template.ts).

    The contract (authoritative)

    A node value (e.g. create_record / update_record fields) is a string template. {…} tokens are resolved; everything else is a literal.

    Token Resolves to
    {var} the flow variable var (any type; preserves type when the whole value is a single token)
    {var.path.seg} dotted path walk on the resolved value (objects)
    {var.0} / {rec.items.2} array index (numeric segment) — added in #1872
    {record.id} a record variable's field (e.g. a create_record outputVariable now holds the record — #1873)
    {$User.Id} / {$User.Email} current user
    {NOW()} / {TODAY()} / {TODAY() + 90} timestamp / date (+ N days)
    {a + b}, {x ? y : z} arithmetic / mixed expression over variables (safe charset)
    anything without {…} literal string

    So body: '{{ai_suggested_reply}}' should be '{ai_suggested_reply}'; ticket: '$source.id' should be '{source.id}' (with source bound as a variable).

    On the proposed M1 (typed { literal } / { expr } / { ref })

    Declined as a breaking redesign of every existing flow + template. The existing single-syntax contract is sufficient once documented; this issue (and #1873/#1872) have removed the actual sharp edges.

    Remaining

    The "all templates write flows consistently" acceptance item is an objectstack-ai/templates task (cross-repo) — please track it there. The framework-side semantics are consistent and documented (template.ts header + this contract). If a specific value form still resolves surprisingly, file a focused bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or requestpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions