8000 feat(automations): more operators for conditions by adeelahmad · Pull Request #434 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(automations): more operators for conditions - #434

Merged
adeelahmad merged 16 commits into
mainfrom
claude/project-thread-li6m25
Oct 18, 2026
Merged

adeelahmad merged 16 commits into
mainfrom
claude/project-thread-li6m25

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 15, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: a condition (a trigger's where, an automation's If, a condition, filter or switch node's match tree, the timeline's where) could only test exists, empty, equals, not_equals, contains, gt and lt.

After: match trees also take in, not_in, starts_with, ends_with, matches, between, before, after, within, weekday, time_between and changed, each checked when saved with the problem in words, and each read back in words by match.describe ("the subject matches “trip” or “outing”", "now falls on a Saturday or Sunday", "object.state changed for each actor.id").

Workflow studio module M5, part 1 of 5 (plan: section 5, M5, items 1 and 6 for the new operators).

How:

  • app/domain/match.py owns the new tests. A list passes when one of its items does (as contains does); not_in when none does. Times are ISO times or dates, read in env["timezone"] when written without a zone; now comes from env["now"] (the clock only when not given), so tests and dry runs fix time.
  • matches: patterns of up to 200 characters, in any case, refused when they repeat a part that repeats itself ((a+)+), repeat alternatives that may start alike ((a|aa)+) or refer back to a group; at most 20,000 characters of input; compiled patterns cached.
  • changed: compares with the last value the same test saw for the same automation and trigger, kept in a new automation_state table (kind last) through match.State(db, automation, alias, dry=False) in env["state"]; one State per activity, so the If and a node agree; value may name a path (actor.id) to keep values apart. Rows expire 30 days after last seen; match.tidy runs hourly from the routine schedule; at most 1000 rows per automation, oldest dropped and counted.
  • README: the operators move from In progress into the built list, with their checks in docs/requirements.md (make requirements passes); a line under ## Unreleased in CHANGELOG.md.

Defaults taken (reversible): patterns run on the regex module (already installed through fastapi-mail, Apache-2.0, now declared) for its per-match timeout of 50 ms, a hard stop the stdlib re lacks; the parse check still uses Python's own parser. within is either side of now; before/after/between also take now and durations (2h, -30m). The first value changed sees is no change. The threat model's line on members' patterns comes in its own docs pull request right after this one: here it changed threat-model.yaml's hash, which conflicted with almost every pull request that merged while this one's CI ran.

Motivation and Context

Adeel asked for a full workflow studio with conditions joined from any source. This is the condition language it needs: "the sender ends with @stmarys.org", "between 22:00 and 06:00", "the door's state changed".

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.
  • My change requires documentation updates, and I have updated docs/ accordingly.
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

Done questions (AGENTS.md)

  • Goal: the full operator set the plan names, with descriptions; merged on green CI.
  • Agents: the MCP timeline tool's where now lists every operator; automations' API and tools take them too.
  • Zero setup: nothing new to install (regex was already a dependency of a dependency).
  • Fewest clicks and keystrokes: n/a, no UI here (the builder is M11).
  • Configurable: n/a, no new settings.
  • Light: pure Python checks; a new table and two indexes only.
  • Private and secure: members' patterns on outside text are refused when they could run away, read at most 20,000 characters and stop after 50 ms; the threat model's ReDoS line follows in a docs pull request right after this.
  • Cost: no model calls.
  • User decides: old graphs and conditions behave exactly as before; nothing runs on its own.
  • Upgrades: a new table with DEFINE ... IF NOT EXISTS; nothing stored changes shape.
  • Honest: docs and README label the operators built, with checks in docs/requirements.md; refine-later items written down.
  • Tests, docs and generated files updated (tests/domain/test_match_ops.py, docs/automations.md Operators; no generated files change).
  • Open standards; regex is Apache-2.0.
  • Result reported with evidence; "refine later" items written down (variables in match values, statistical conditions).
  • Reuse: builds on the workflow engine's match trees and regex instead of a new pattern engine.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb


Generated by Claude Code

Match trees gain in, not_in, starts_with, ends_with, matches, between,
before, after, within, weekday, time_between and changed. Time and state
come from env (now, timezone, state), never from globals. Patterns are
refused when they could backtrack without end, read at most 20,000
characters and give up after 50 ms (the regex module's timeout).
changed keeps the last value seen per automation, trigger and key in a
new automation_state table, tidied hourly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb
@adeelahmad adeelahmad self-assigned this Oct 15, 2026
…rosecond

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb
adeelahmad added a commit that referenced this pull request Oct 16, 2026
Automations merged (#432 to #464): the stream now holds every kind of
activity, the Timeline page reviews it, and automations act on it with
triggers, conditions, actions, approvals, limits and budgets, made by
agents over MCP and in the assistant or drafted from a sentence. Say so
under Automate it, with the studio labelled planned as
docs/automations.md does; add the open RSS feeds (#453) and condition
operators (#434) to In progress; link the timeline from the docs index.


Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
…-li6m25

# Conflicts:
#	fastapi_backend/app/domain/store.py
#	threat-model.yaml
# Conflicts:
#	threat-model.yaml
…checks

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb
# Conflicts:
#	CHANGELOG.md
#	README.md
#	threat-model.yaml
Ported from #512 so this PR's upgrade check passes while that lands: the
entity-types step re-types weekday Terms as Dates, which the default entity
list leaves out, so the check read them as gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb
Copy link
Copy Markdown
Owner Author

Upgrade from the last release failed on ebd1acb, and the failure doesn't come from this PR. Since #395, the entity-types upgrade step re-types weekday Terms such as Monday as Dates. The default entity list leaves Dates out, so the check counted Friday and Monday as gone. The fix is in #512 and is ported here in 2c6b4fe (ci/upgrade/lens_upgrade.py now also lists DATE and NUMBER entities). Once main has #512, this change does nothing.


Generated by Claude Code

# Conflicts:
#	threat-model.yaml
# Conflicts:
#	CHANGELOG.md
#	threat-model.yaml
# Conflicts:
#	README.md
#	threat-model.yaml
# Conflicts:
#	CHANGELOG.md
#	fastapi_backend/pyproject.toml
#	threat-model.yaml
The threat model's line on members' patterns moves to its own docs pull
request, so this one stops conflicting on threat-model.yaml's hash.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb
# Conflicts:
#	CHANGELOG.md
#	README.md
@adeelahmad
adeelahmad merged commit 9799c1f into main Oct 18, 2026
19 of 20 checks passed
@adeelahmad
adeelahmad deleted the claude/project-thread-li6m25 branch October 18, 2026 01:59
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