Skip to content

fix(cli): send Jev a short name for each control - #38

Merged
caelaxie merged 4 commits into
mainfrom
caelaxie/shorten-jev-criteria
Sep 24, 2026
Merged

caelaxie merged 4 commits into
mainfrom
caelaxie/shorten-jev-criteria

Conversation

@caelaxie

@caelaxie caelaxie commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Why

Jev rejected a rank of the Electron chat window after that window grew to 143 controls. The request was about 150KB. TypeSafe answered HTTP 400 with {"detail":{"error_type":"max_tokens_exceeded"}}. criteria() was sending each control's full accessibility text, including the text inside a field and lines that wrap under it. That text is copied into the state and into two questions.

The accessibility parser now keeps one visible name per row. It keeps the first line and drops a renderer suffix (Value, Placeholder, Description, Text, or Secondary Actions). Darwin's bare Placeholder: is included: a leading space and no comma, used when the control has no name and no value. A trait list such as (selected, settable) stays, including on a single-word role, so button (selected, expanded) New Note keeps New Note. criteria() joins that role and name and stops at 80 code points. button New Note is unchanged. The raw row stays on line. The local suggestion uses the visible name, with no cap.

disabled and settable are read from that same trait list. (selected, disabled) disables the control. A field value that contains those words does not.

Scope

  • parseTreeMoves in packages/cli/src/intent/tree.ts
  • criteria in packages/cli/src/intent/evaluate.ts
  • Cases in tests/intent/tree.test.ts and tests/intent/evaluate.test.ts

Tradeoffs

The control list stays in the state and on both choice questions. Cutting each name is what brings a full 255-control request back under the limit. A second request after a token error would send the same oversized body again.

Jev sees the field's name. The text inside the field stays off the request. Two fields with the same name still look the same.

A text row whose renderer appends the value with a space and no suffix has no boundary to cut. The 80-code-point cap is the bound. Those rows stay out of the rank unless the role or a settable trait marks them clickable.

A visible name that itself contains Placeholder: is cut at that mark. That is the same string Darwin writes for a bare placeholder.

Blast Radius

This changes the text sent to Jev and the clickable map on jev.debug, because both call criteria(). A short name such as button New Note is the same string as before. Ranking of a window whose controls already had short names does not change.

The suggestion label is the visible name. A field value that used to ride along in the label stays on line and in the snapshot text.

A combined trait list now changes the flags. button (selected, disabled) Format is not clickable. button (selected, settable) is settable. A lone (disabled) trait behaves as before.

Verification

pnpm exec vitest run --config vitest.workspace.ts tests/intent passed 85 tests. pnpm --filter @crosshands/cli typecheck passed. oxlint reported 0 warnings on the four edited files.

The tests lock button (selected, expanded) New Note, a bare Placeholder:, a 5000-character name, an emoji cap that stays on a code-point boundary, and a field value that says (disabled) without disabling the control.

A request in the same shape as liveEvaluator, with 255 names of 80 dense characters, was 68401 bytes. POST https://api.typesafe.ai/v1/systemone returned HTTP 200 from model jev-1.13.0 with input_tokens 49439. The same shape at 150468 dense bytes had returned HTTP 400 and {"detail":{"error_type":"max_tokens_exceeded"}}. That measurement is from the earlier short-name payload. This parser move posts the same shape: one name of at most 80 code points, copied into the state and both choice questions.

A posted control keeps its role and visible name. The field value,
wrapped lines, and anything past 80 characters stay out of the request.
Stop the posted name at a comma, a new line, or 80 characters so a
text field's contents cannot push the rank request over Jev's token limit.
The first comma is often inside a trait list such as (selected, settable).
Cut at the renderer metadata suffix, then cap the first line at 80 characters.
Cut renderer suffixes in the accessibility parser, and keep trait commas
in the name. criteria() only caps that name at 80 code points.
@caelaxie
caelaxie merged commit 9ff62b0 into main Sep 24, 2026
9 checks passed
@caelaxie
caelaxie deleted the caelaxie/shorten-jev-criteria branch September 24, 2026 01:29
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.

1 participant