3 Commits
Author SHA1 Message Date
dsh-slopo agent 9ebd484e60 fix: draw the API key once, and let status answer the dimensions question
Release / release (push) Successful in 6s
Two things a user setting this up hit immediately.

The card drew `embeddingApiKey` twice. The render loop walked every entry in
FIELDS, and the secret — which is drawn by hand, as a write-only password
control — was one of them, so a second control appeared beside it: an ordinary
text input, echoing the key in clear as you typed. One key, two boxes, one of
them visible. The loop skips secrets now, and the tests count controls rather
than checking that each expected label is present, because a duplicate beside
the real control passed the old assertions.

`status` could not answer the one question a new user cannot look up: how wide
is this model? The probe that reports it was gated on every required setting
being present, so in exactly the state that needs the answer — dimensions
unset — it reported nothing and said "Missing: embedding_dimensions". It now
runs whenever the endpoint can be named (a model and a base URL), and the
status message names the width it observed:

  Missing: embedding_dimensions. The endpoint is reachable and returned 768
  dimensions, so set embeddingDimensions to 768.

The probe also tells "not set yet" apart from "set wrong", because the two have
different remedies.

Also documents both ways to read the width by hand, since a wrong value is
frozen into the index at first use and costs a full re-embed to correct.
2026-09-26 07:05:36 +01:00
dsh-slopo agent 46124b11aa Fix: status could not be serialised when the probe SUCCEEDED
The probe returned `error: undefined` on a dimension match. `undefined` is not a
JSON value -- JSON.stringify silently drops it from an object -- so the shape
looked harmless and was not: the harness enforces the declared output schema
against the canonical value before materialising it, and an explicit undefined
property fails that check. A perfectly healthy status call could not be returned
at all.

Fixed at the boundary rather than at each site. Every return now funnels through
`toJsonValue`, which drops undefined properties exactly as JSON.stringify would,
maps non-finite numbers to null (same reasoning: JSON.stringify(NaN) is "null"),
turns an undefined array slot into null rather than shifting indices, and refuses
a circular value instead of recursing forever. `update` was carrying
`errorCode: undefined` and `ensureSlopo` a `detail: undefined` on the same path,
so a per-site fix would have left two more of these waiting.

The probe also now omits `error` rather than assigning undefined, since it is a
plausible thing for another consumer to read.

Four regression tests, and they were checked against a negative control: with the
sanitiser reverted and the undefined restored, exactly the "probe SUCCEEDS" test
fails with "does not survive a JSON round trip" and the others still pass, which
is what makes it a test of this bug rather than of the JSON round trip in
general.
2026-09-22 13:08:22 +01:00
dsh-slopo agent d7eccc6366 Add a real pre-flight to status
Slopo reports a bad embedding configuration as the two words "Embedding failed."
on stdout, with the real reason in its agent log. That is a slow way to learn
that a model string has the wrong provider prefix, or that the dimensions do not
match what the model actually returns — the second of which is expensive, because
slopo freezes the dimensions into the index at first use.

`status` now does three things instead of one: it reports the resolved settings,
it runs `slopo --version` through the shell seam, and it makes one tiny embedding
request against the configured endpoint and compares the returned width with the
configured one. Verified against a real Ollama: a correct config reports ok, a
dimension mismatch names both numbers, and a wrong model returns the endpoint's
own 404 rather than a silent failure minutes into an embed.

The probe is a direct fetch rather than a shell call, because it is one small
HTTP request and does not belong behind a boundary that exists to confine
filesystem writes.

Two smaller things this needed:
- the sandbox policy is now resolved once at the top of execute, so `status` can
  use it without a second resolution
- provider-prefix stripping is an allow-list, not "drop the first segment".
  `unclemusclez/jina-embeddings-v2-base-code:latest` is a real model name with no
  prefix at all, and an unknown first segment is left alone so a wrong guess is
  visible in the reported `sentModel` rather than silent
2026-09-22 07:22:03 +01:00