feat(wizard): render schema description, examples, defaults#75
Conversation
Schema-driven prompts in `connections new` previously ignored every JSON Schema annotation except `default` (and only on plain string fields). Even when the API attached descriptive metadata to a field, the wizard still showed bare `field_name:` with the only hint being "optional — press Enter to skip" when the field was non-required. Surface that metadata at the prompt: - `description` is rendered as inquire help text on every supported field type (string, password, integer, boolean, array). When the field is also optional, the description and the existing "optional — press Enter to skip" hint are concatenated rather than one displacing the other. - `examples[0]` is rendered as the inquire placeholder for plain strings, integers, and arrays when no explicit `default` is set. Password fields skip the placeholder (placeholders alongside hidden input read awkwardly in terminals); their description still carries any example shape. This is a generic improvement keyed on schema content, not on connector type — every connector that adds description / examples to its connection-types schema picks it up automatically.
The blocking HTTP client was built via reqwest::blocking::Client::new() with no explicit configuration, which on macOS surfaces as "error sending request" when a request is in flight long enough for the OS to drop the quiet TCP connection (e.g. while the server is doing slow synchronous work like ducklake schema discovery against a remote catalog). Add an explicit overall request timeout (5 min) to bound the worst case if the server genuinely hangs, and a 30s TCP keepalive so the socket stays warm across long synchronous server work. Both values live as constants near the helper for clarity.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
| let example = field["examples"] | ||
| .as_array() | ||
| .and_then(|a| a.first()) | ||
| .and_then(|v| v.as_str()); |
There was a problem hiding this comment.
nit: as_str() silently returns None for non-string JSON values, so this works for string fields but not for integer fields whose schemas naturally carry numeric examples (e.g. "examples": [8080]). The PR description says integer placeholders are supported, but a schema like that will silently produce no placeholder.
Fix: widen the extraction to also accept numbers and coerce them to String. Because with_placeholder takes a &str, the owned string needs to live long enough — easiest approach is to compute example as Option<String> from the start:
| let example = field["examples"] | |
| .as_array() | |
| .and_then(|a| a.first()) | |
| .and_then(|v| v.as_str()); | |
| let example: Option<String> = field["examples"] | |
| .as_array() | |
| .and_then(|a| a.first()) | |
| .and_then(|v| v.as_str().map(str::to_owned).or_else(|| v.as_i64().map(|n| n.to_string()))); |
Then use example.as_deref() at every call site. (not blocking)
The previous extraction used `as_str()` only, which silently returned None for numeric JSON examples. So a schema like `"examples": [8080]` on an integer field — exactly the kind of example that would benefit from a placeholder — produced no placeholder despite the integer branch wiring one up. Widen the extraction to also accept i64 and coerce to String, then pass through call sites via `as_deref()`. No schema in runtimedb today carries numeric examples, so this is a pure consistency fix — but it aligns the code with what the original commit's description claimed to support.
Summary
Two small CLI changes that go alongside runtimedb #408:
feat(wizard): render schema description, examples, and defaults(src/connections_new.rs). The schema-drivenconnections newwizard previously ignored every JSON Schema annotation exceptdefault(and only on plain string fields). Nowprompt_fieldalso readsdescription(rendered as inquire help text on every supported field type — string, password, integer, boolean, array) andexamples[0](rendered as the inquire placeholder for plain strings, integers, and arrays when nodefaultis set; password fields skip the placeholder by design and rely on the description). When a field is optional, the description and "optional — press Enter to skip" hint are concatenated rather than one displacing the other.fix(api): add request timeout and tcp keepalive(src/api.rs). The blocking HTTP client was built viareqwest::blocking::Client::new()with no explicit configuration. On macOS this surfaces aserror sending requestwhen a request is in flight long enough for the OS to drop the quiet TCP connection (e.g. while runtimedb is doing slow synchronous work like ducklake schema discovery against a remote catalog). Add an explicit 5-min request timeout (bounds the worst case if the server genuinely hangs) and a 30s TCP keepalive (keeps the socket warm across long synchronous server work).Why
The schema-metadata change is what makes runtimedb #408 actually useful in the CLI. Without it, the new descriptions on
credentials_jsonfor ducklake / bigquery / snowflake are sent over the wire but never reach the user — the wizard would still show barecredentials_json:prompts. Both changes are generic and schema-driven; no per-connector code anywhere in the CLI.The timeout fix was hit live while testing the ducklake wizard against a local runtimedb: the wizard's POST landed correctly server-side and the connection was created, but the CLI gave up waiting before discovery returned and printed
error sending request. Addingtcp_keepaliveis what actually fixes the symptom (prevents the OS from dropping the quiet socket); the explicittimeoutis belt-and-suspenders for "what if the server actually hangs."Wire compatibility
Pure additive client behaviour. Nothing in the wire contract changes:
What this branch does NOT contain
credentials_jsonfield, so the wizard never has multi-field auth to bundle.Client::new()sites injwt.rs/auth.rs/skill.rs. We can consolidate them in a follow-up if you want; this PR only touches the construction sites inApiClient.Test plan
cargo test— 121 tests pass locally.cargo buildclean.feat/credentials-json-schema-metadatabranch:connections create list ducklake --output json— new descriptions/examples/defaults flow through.connections newfor ducklake — every prompt now shows description help text;s3_endpoint/s3_regionshow defaults;credentials_jsonprompt shows the JSON shape from the description.error sending request).