10 Commits
Author SHA1 Message Date
Dumitru Picalau 26df88216f feat(ai): chat round, node negatives, pack builder quality fixes (#69)
Chat round (explain on selection, page starters, reactions, streamed notes, thinking), negatives on node fixed values and combines, Pack builder quality fixes from 31 real-model eval rounds, and small-model support (scoped tools, checked tool arguments on local servers, two-phase steps, fixed prefix shown in Test connection).
2026-10-17 01:23:58 +02:00
DumiFlex 9fe33ab4b2 feat(syntax): accept an axis accessor on a var reference
A reference now carries at most one pick index and one axis, in either
order - $o.0.SHOES and $o.SHOES.0 name the same value. Accepting both is
deliberate: $o.0 is already meaningful on its own, so appending .SHOES is
composition rather than a second syntax, and rejecting it would make the
natural spelling the broken one.

Two mirrored regex alternatives, so .0.1 and .SHOES.BELTS reject by not
matching their second segment and the tail stays literal text - no
validation pass. Both tokenizers normalise to one (name, index, axis)
triple immediately, so nothing downstream learns which spelling was used.

Replaces the var_nondigit_accessor_is_text corpus case, which pinned the
behaviour this changes, with cases for both orders and both nonsense forms.
2026-08-17 21:04:56 +03:00
DumiFlex 0b36ce892b feat(engine): multi-pick prefix gains N-M range + ~ independent flag
The {N$$sep$$} brace prefix now also accepts a count range ({N-M$$}) and a
~ independent flag ({N~$$} / {N-M~$$}, repeats allowed; absent = unique).
Both tokenizers (Python engine + TS richTokenize) parse it identically
into dp-multi meta {min, max, independent}; legacy `count` is kept (== max)
so existing readers + the resolver behave unchanged for a fixed {N$$}.
Shared syntax-corpus.json locks Py≡TS parity (existing multi_pick entries
gain the new keys; new range/lone-ref cases added).

Resolution of the range/independent semantics lands next (engine resolver);
this commit is tokenizer + parity only — a fixed {N$$} is byte-for-byte
unchanged.
2026-06-09 17:54:48 +03:00
DumiFlex 3ac0afa979 feat(engine): tokenize var.K list accessor (py+ts parity) 2026-06-08 14:12:42 +03:00
DumiFlex 13de622c6b feat(engine): multi-tag options + boolean sub-category filters (v2)
Option sub_category -> sub_categories[] (default []). Both pool filters (instance category_filter, nested @{} ref) become boolean expressions (and/or/not/parens; comma=or) matched against an option's tag set via the shared engine/syntax/subcat_filter matcher, applied BEFORE constraints. Exclude-null is a separate flag: instance exclude_null + the trailing !null ref marker, replacing the old 'null' keyword.

4-segment ref grammar @{uuid#name:expr!null} single-sourced across tokenize.py/scan.py/pipeline.py/_constraints.py (! excluded from name/expr captures); tokenizer REF meta now carries filter_expr + exclude_null instead of a comma-split list. scan.py findall unpack sites updated for the 4th group.

validate_payload: per-option sub_categories[] must be in the registry; optional tag_groups (UI-only axes, members in-registry, <=1 group); registry names validated via subcat_filter.validate_subcat_name (rejects whitespace, boolean/ref chars, reserved words incl. null). wp_api/_validators delegates to the same function.

Constraints stay alive via a primary-tag stopgap: _apply_constraint_to_options + _record_pick use sub_categories[0] as the matrix key; true multi-tag matrix matching is SP3. Cascade fix_subcat_delete/rename + orchestrator scrub the per-option list; instance_schemas category_filter -> string. Existing engine tests migrated to the v2 shape; added tests for the ref regex, payload validation, and multi-tag pool filtering.
2026-06-07 00:43:55 +03:00
DumiFlex 85cf827d56 chore: pre-pair-badge polish (bundle, cascade, debug, light-theme, cleaner)
Accumulated branch work that was uncommitted alongside the pair-badge feature in the prior commit. Captured as a single sweep commit so the branch can merge cleanly; future work should commit per-feature to avoid this.
2026-05-26 11:24:43 +03:00
DumiFlex b950b8fd82 feat(engine,scanner): nested-ref constraints + @{uuid:subcat} filter + smarter target classification
Three improvements aimed at making constraints actually useful in
composed pipelines, with the conflict scanner keeping up.

## Phase A — nested constraints (engine)

Pre-2026-05 constraints only fired when the target wildcard ran as a
top-level chain module. Wildcards reached through `@{uuid}` refs from
inside another wildcard's option value silently bypassed every rule.
Composition (outfit-set wildcards, palette reuse) was a constraint
blind spot.

- New `engine/modules/_constraints.py` holds the shared application
  logic (loop constraints by target uuid, look up source pick, apply
  matrix/exception cells, emit unknown_constraint_source +
  constraint_excludes_all_options warnings)
- `wildcard_handler.resolve` now delegates to the helper instead of
  inlining the loop
- `engine/syntax/resolve._resolve_ref` calls the same helper after
  fetching the catalog wildcard but before rolling — nested target
  wildcards now get constrained identically to chain-level ones
- `ResolveContext` exposes `get_constraints()` + `get_picks()` so the
  resolver has the back-channel it needs without depending on the
  full pipeline ctx dict

## Phase B — `@{uuid:subcat[,subcat]}` filter

New optional ref syntax. `@{color:warm}` resolves the catalog wildcard
`color` but restricts its option pool to entries whose `sub_category`
is in the filter list. Same semantics as chain-level
`instance.category_filter`, but scoped per call site so one library
wildcard stays reusable.

- Python tokenizer regex extended to capture optional `:subcat,subcat`
  group; `_resolve_ref` filters options pre-pick + pre-constraint
- TS `richTokenize.ts` mirrors the grammar so previews + RichTextInput
  recognise the new form
- `extension/graph.ts:WC_REF_RE` + `preview-tokens.ts:REF_RE` updated
  to skip the filter when extracting uuids (uuid is still group 1)
- Empty pool after filter → empty string output + new
  `ref_subcategory_empty_pool` warning so the user sees an
  unsatisfiable filter instead of falling back silently

## Phase C — scanner reach-set + classification refinement

Constraint scanner pre-fix:
- flagged `constraint_target_in_upstream` whenever target had ANY
  upstream instance, even if a downstream / local-after / nested-after
  instance was also present
- flagged `constraint_target_missing` for targets reachable only
  through nested `@{}` refs

Both false-positives. Post-fix scanner computes
`localNestedReachAfter[i]` — transitive `@{}` walk through the local
catalog starting from modules at positions ≥ i — and uses it to:

- skip `target_in_upstream` when a bindable instance exists elsewhere
  (downstream, local-after-self, nested-after)
- skip `target_missing` when target is reachable via nested ref from
  any later chain wildcard
- still flag both when no bindable instance exists (sole-upstream,
  truly-missing both remain caught)

## Tests

- 8 new Python tests under `TestNestedConstraints` +
  `TestNestedSubcategoryFilter` (constraint applies through nested,
  excludes-all warning, source-not-yet-picked warning, subcat narrows,
  multi-subcat union, empty pool warning, empty filter no-op,
  subcat+constraint composition)
- 7 new TS tests under `scanConflicts — constraint nested-reach
  classification` (nested reachable doesn't flag missing, transitive
  deep reach, upstream+downstream silent, upstream+local-after silent,
  sole-upstream still flags, nested-from-before-constraint still
  flags, nested with subcat filter still reaches)

## Numbers

- 696 pytest pass (+8)
- 1672 vitest pass (+7)
- ruff clean
- bundle 306899/307200 (301 bytes headroom)
2026-05-19 21:40:08 +03:00
DumiFlex df0ff9441b feat(syntax): tokenize dp_brace + dp_multi with nesting support 2026-04-28 04:17:54 +03:00
DumiFlex 4717865061 feat(syntax): tokenize $var and @{uuid} kinds + corpus cases 2026-04-28 04:05:17 +03:00
DumiFlex 761b45c8b2 feat(syntax): tokenize_text — text + escape kinds with lossless invariant 2026-04-28 03:35:16 +03:00