ReactiveDag.Node.PerKey (reactive_dag v0.17.0-rc)

Copy Markdown View Source

The PER-ENTRY MAP: for each claimed row of the input, call a generic action with that row and write its structured output into this node's attributes.

recompute_by :key, to: :transcripts, from: :key

per_key :summarise,
  args: [text: :body],
  fingerprint: [:body],
  into: [summary: :summary]

The loop every per-row node hand-writes — scope to the claimed keys, read the rows, call something once per row, write the result — with the library driving it. That matters beyond ergonomics: because the library now SEES the input rows, it can fingerprint them and skip the call when nothing that feeds it has changed. A run action is opaque by design (the library passes keys and gets keys back), so no amount of declaration outside it could do that.

fingerprint: names the input fields the result depends on. Their hash is stored on the output row; when a recompute finds it unchanged, the action is NOT called and the key is not reported changed. For an expensive or non-deterministic action — an LLM call above all — that is the difference between a whole-cell claim costing one call and costing all of them.

The action is an ordinary generic Ash action taking the row's fields as arguments and returning a map. That it might be AshAi.Actions.prompt/2 is the library's business not at all.