Skip to content

feat(automation): script-node outputVariable + interpolated inputs (pure-function pattern, #1870)#1926

Merged
os-zhuang merged 1 commit into
mainfrom
feat/script-output-variable
Jun 15, 2026
Merged

feat(automation): script-node outputVariable + interpolated inputs (pure-function pattern, #1870)#1926
os-zhuang merged 1 commit into
mainfrom
feat/script-output-variable

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

The long-term design for flow functions, decided from the templates evaluation. A flow function (script node) is a pure compute step — and ALL data I/O stays declarative on the flow graph.

Why pure-function (not a data API on the function)

The AI templates wrote invoke_function expecting the function to update the record directly, but flow functions get FlowFunctionContext (input/variables/automation/logger) — no data API, by design. That boundary is correct for a metadata-first, AI-authored platform:

  • Visible: data effects stay on the flow graph (update_record), not hidden in code.
  • Governed: writes go through the engine's data path (RLS, tenancy, transactions, hooks) — a raw function data-API would bypass that (the managedBy is not enforced: generic CRUD bypasses better-auth on sys_team (data-integrity / security) #1591 class).
  • Build-checkable: declarative writes are validated at objectstack build; opaque function I/O is exactly the "passes build / fails at runtime" class this season fought.
  • Two-tier already correct: L2 hooks are the data-lifecycle layer (they get ctx.api); flow functions are orchestration compute.

So the fix makes the pure-function pattern ergonomic, not the imperative one work.

What's added

  • config.outputVariable — exposes the function's return value as a flow variable, so a later declarative node persists it.
  • config.inputs are interpolated against live flow variables (they were passed raw) — so a function can consume a prior node's output.
{ id: 'ai', type: 'script', config: { function: 'helpdesk.aiTriageStub', inputs: { ticketId: '{record.id}' }, outputVariable: 'ai' } },
{ id: 'apply', type: 'update_record', config: { objectName: 'helpdesk_ticket', filter: { id: '{record.id}' },
    fields: { ai_category: '{ai.ai_category}', ai_sentiment: '{ai.ai_sentiment}' } } },

Also

  • Skill: automation pitfall [WIP] Create a new release version #9 now teaches this pattern (function returns → outputVariable → update_record; hooks for data side effects).
  • Tests: +1 end-to-end (compute → outputVariable → downstream node interpolates {ai.field}); @objectstack/service-automation 202 pass; check:skill-docs passes.

This is the framework foundation for the templates' #1870 remediation (restructure the 4 AI flows to function-returns + update_record).

🤖 Generated with Claude Code

…ure-function pattern, #1870)

Long-term design for flow functions (per the templates evaluation): a flow
`function` is a PURE compute step — inputs → return value — and ALL data I/O
stays declarative on the flow graph. This keeps the data layer visible, governed
(RLS/tenancy/transactions via the engine's data path), and build-checkable
(create/update_record nodes the build already validates) — rather than giving
functions a raw data API that hides writes and bypasses governance. (Data-
lifecycle side effects remain L2 hooks, which legitimately get ctx.api.)

Two enablers:
- `config.outputVariable` exposes the function's return value as a flow variable
  → a later update_record persists it (`fields: { ai_category: '{ai.ai_category}' }`).
- `config.inputs` are now interpolated against live flow variables, so a function
  can consume a prior node's output (`inputs: { ticketId: '{record.id}' }`).

Skill: automation pitfall #9 now teaches the pure-function pattern (function
returns → outputVariable → update_record; hooks for data side effects).
+1 end-to-end test (compute → outputVariable → downstream node interpolates it);
service-automation 202; check:skill-docs passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 15, 2026 4:33pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Jun 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): packages/services.

5 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/guides/packages.mdx (via packages/services)
  • content/docs/guides/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/guides/runtime-services/index.mdx (via packages/services)
  • content/docs/guides/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/protocol/objectos/i18n-standard.mdx (via packages/services)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 1402be0 into main Jun 15, 2026
14 checks passed
@os-zhuang
os-zhuang deleted the feat/script-output-variable branch June 15, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant