8000 feat(automations): templates in params and prompts, with outside text kept marked by adeelahmad · Pull Request #454 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(automations): templates in params and prompts, with outside text kept marked - #454

Merged
adeelahmad merged 1 commit into
mainfrom
claude/project-thread-oi3om9
Oct 16, 2026
Merged

adeelahmad merged 1 commit into
mainfrom
claude/project-thread-oi3om9

Conversation

@adeelahmad
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Workflow studio M9, part 1 of 3 (variables and templates): the templating core. Saved variables (vars, set_variable) and the variable picker's catalog and preview come in the next two PRs.

Description

Before: an automation's action params rendered with a baseline in automation_nodes.py. A typo gave Jinja's 'dict object' has no attribute 'subjct'. Prompts wrapped outside text before rendering, so {{ event.object.content | plain }} stripped the markers (the HTML parser read them as tags) and | truncate could cut the closing one. There were no filters for times or addresses, and a prompt could only be inline text.

After:

  • Run context (variables.context): every key of the contract, plus now_local, which is now in the run's time zone (the trigger's, else the automation's first schedule's, else UTC).
  • Params (variables.render): one {{ }} expression keeps its type, and dicts and lists are walked. a.b reads a dict's key before a method of the same name (steps.n3.items is the output's items), in the automation sandbox only.
  • Errors name the param, the missing variable and the nearest name, with the line: text: events.mail.object.subjct is not defined; did you mean subject?. Paths guarded by default or is defined don't count.
  • Outside text in params keeps its words but loses invisible tag characters (untrusted.visible).
  • Prompts (variables.prompt): each activity's lens.untrusted fields, steps and vars are marked as data with untrusted.Marked. Written out, it carries wrap's markers. Filters, string methods and slices work on its words and give marked text back, so | plain | truncate(4000), .upper() and | emails | first keep the markers. ==, in and length read the words.
  • Saved prompt templates: a prompt param may name one ({"template": 5, "version": 2}). It is checked when the workflow is saved. The template's own instructions and output schema fill ask_model's system and json_schema when the node doesn't set them.
  • Filters in every template's sandbox: date(fmt, tz), local, ago, plain, emails, defang. They only add; json, tc and Jinja's own filters are unchanged.

actions.render_prompt and the baseline in automation_nodes now call variables, so there is one renderer.

Motivation and Context

Workflow studio, module M9 (plan section 5, brief workflow-studio/briefs/M9.md). This lets people write joined messages like {{ events.mail.object.subject }} on {{ events.soon.object.startTime | date('%a %H:%M') }} and prompts that keep outside text marked as data.

Default taken (reversible): every saved variable's text is marked in prompts, because a run may have set it from outside text. Marking only the variables that really were is under Refine later.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests (tests/domain/test_variables.py).
  • My change requires documentation updates, and I have updated docs/ accordingly (docs/automations.md → Variables and templates).
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md. (n/a: the title says it)

Done questions (AGENTS.md)

  • Goal: part 1 of 3 of M9. Merged when CI is green.
  • Agents: templates are what agents write into automations through the API and MCP. The catalog and preview endpoints come in part 3.
  • Zero setup: no new prerequisite. The filters use the standard library and code Lens already has (mailbox.html_text, untrusted.defang).
  • Fewest clicks: errors name the nearest variable, so a typo is fixed without looking it up.
  • Configurable: n/a, no new setting. Marking follows ai.untrusted_marking.
  • Light: pure Python, no new dependency.
  • Private and secure: outside text stays marked through filters, string methods and slices in prompts, and the sandbox's limits are unchanged and tested. There is no new entry point, so no new threat model entry (M12 does the pass).
  • Cost: n/a, no model calls.
  • User decides: defaults unchanged. Templates elsewhere render as before, since the filters only add and the dict-key order applies to automation params only.
  • Upgrades: n/a, no stored data changes.
  • Honest: docs label templates built and saved variables, catalog and preview planned.
  • Tests and docs updated. No generated files change (no API change).
  • Open standards; no new dependencies.
  • Refine later items are written in docs/automations.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JZDyxMfCBYNRw12CHqE9ss


Generated by Claude Code

@adeelahmad adeelahmad self-assigned this Oct 16, 2026
@adeelahmad
adeelahmad force-pushed the claude/project-thread-oi3om9 branch 2 times, most recently from 05a06f2 to adfca1d Compare October 16, 2026 01:21
… kept marked

variables.py builds the run context (now_local in the run's time zone), fills

8000
params in (one expression keeps its type; errors name the param and the nearest
variable), and renders prompts with outside text marked as data, which filters
and string methods can't strip. A prompt param may name a saved prompt template
by version. New filters for every template: date, local, ago, plain, emails,
defang.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZDyxMfCBYNRw12CHqE9ss
@adeelahmad
adeelahmad force-pushed the claude/project-thread-oi3om9 branch from adfca1d to c62aaa2 Compare October 16, 2026 01:36
@adeelahmad
adeelahmad merged commit f095452 into main Oct 16, 2026
10 checks passed
@adeelahmad
adeelahmad deleted the claude/project-thread-oi3om9 branch October 16, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0