Skip to content

feat: make timeoutMs file-configurable like every other knob - #24

Merged
danipl merged 1 commit into
mainfrom
10-make-timeoutms-file-configurable-like-every-other-knob
Oct 5, 2026
Merged

danipl merged 1 commit into
mainfrom
10-make-timeoutms-file-configurable-like-every-other-knob

Conversation

@danipl

@danipl danipl commented Oct 5, 2026

Copy link
Copy Markdown
Owner

What

timeoutMs was env-only (JEV_TIMEOUT_MS); every other knob reads the 7 config layers first. Route A/B users — and macOS GUI users who can only edit jev.yaml — couldn't tune the latency knob.

How

  • loadConfig: pickNumber(layers, "timeoutMs", (v) => v > 0) ?? positiveIntFromEnv("JEV_TIMEOUT_MS", DEFAULT_TIMEOUT_MS)
  • pickNumber gains an optional per-layer validate predicate — non-positive/bogus counts as unset per layer (falls through to lower layers, then env, then default). minConfidence keeps unfiltered behaviour (0 is valid there).

Tests

  • 21: file timeoutMs: 50 + env JEV_TIMEOUT_MS=5000 + hanging stub → aborts at ~50 ms (assert < 1000 ms), passthrough — proves file layer wins and the value is used.
  • 22: timeoutMs: 0 / "abc" → default applies, instant stub answer arrives, trim happens (a 0 ms timeout would abort first → passthrough), no hang/throw.

Docs

README config section + env table, jev.yaml.example, DEVELOPMENT.md §2 and §5 (also fixed pre-existing staleness: JEV_MODEL is already a config-layer field, not env-only), HOW_IT_WORKS.md timeout references.

Gates

npm run typecheck && npm test && npm run build — green (24/24).

Fixes #10

timeoutMs was the only knob read from the environment (JEV_TIMEOUT_MS)
instead of the 7 config layers, so route-A/B users — and GUI users who
can only edit jev.yaml — could not tune the latency knob at all.

- loadConfig: pick timeoutMs from the layers first via pickNumber with a
  > 0 per-layer validator; non-positive/bogus counts as unset and falls
  through lower layers -> env JEV_TIMEOUT_MS -> default 2000.
- pickNumber gains an optional validate predicate (minConfidence keeps
  the unfiltered behaviour, 0 being valid there).
- Tests 21/22: file timeoutMs beats env; bogus (0 / "abc") falls back
  to default and routes normally without hang or throw.
- Docs: README config section, jev.yaml.example, DEVELOPMENT.md §2/§5
  (also fixed a pre-existing staleness: JEV_MODEL was already a
  config-layer field, not env-only), HOW_IT_WORKS.md timeout refs.

Fixes #10
@danipl
danipl merged commit 038195f into main Oct 5, 2026
2 checks passed
@danipl
danipl deleted the 10-make-timeoutms-file-configurable-like-every-other-knob branch October 5, 2026 04:31
danipl added a commit that referenced this pull request Oct 5, 2026
askJev silently dropped every tool past the 254th from the criteria,
so a 260-tool request offered 254 to routing with zero operator signal.
Behavior stays safe (a pick among kept tools still trims); the note is
awareness only. The JEV_MODEL env-only doc claim from the same issue was
already fixed by #24.

- askJev: one "note:" line before the round-trip when names.length > 254
- DEVELOPMENT.md: table row for the note: line (can precede apply: too)
- Test 23: 260-tool payload — stub criteria = 254 tools + respond_to_user,
  note logged, trim still applies
danipl added a commit that referenced this pull request Oct 5, 2026
* feat: log note line when the tool list exceeds the criteria cap

askJev silently dropped every tool past the 254th from the criteria,
so a 260-tool request offered 254 to routing with zero operator signal.
Behavior stays safe (a pick among kept tools still trims); the note is
awareness only. The JEV_MODEL env-only doc claim from the same issue was
already fixed by #24.

- askJev: one "note:" line before the round-trip when names.length > 254
- DEVELOPMENT.md: table row for the note: line (can precede apply: too)
- Test 23: 260-tool payload — stub criteria = 254 tools + respond_to_user,
  note logged, trim still applies

* fix: preserve Responses-API built-ins through the trim (#12)

Jev is never shown built-in tools (invariant 4), yet a confident trim
removed them from the payload — an actor must not silently delete
options it was forbidden to consider. The trim filter now passes
type !== "function" entries untouched; the predicate lives in one
isBuiltIn() used by candidate selection and the kept-count alike.
Corollary: a lone function candidate now reproduces the payload under
trim, so that round-trip is skipped — subsuming the old
[web_search, shell] special case. apply: log gains a
"(+ N built-ins kept)" suffix. Test 7 flipped, test 7b added,
invariant-4 text synced (AGENTS/DEVELOPMENT/README), and the Q2-A
README privacy note ships alongside.
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.

Make timeoutMs file-configurable like every other knob

1 participant