feat(models): manifest-driven model capabilities and curated labels - #3603
Open
wpfleger96 wants to merge 23 commits into
Open
feat(models): manifest-driven model capabilities and curated labels#3603wpfleger96 wants to merge 23 commits into
wpfleger96 wants to merge 23 commits into
Conversation
…ev registry lookup The frontend heuristic in #3586 title-cased every word and converted adjacent digit pairs to decimals for any string starting with 'databricks-'. This invented false labels for custom workspace endpoints: 'databricks-team-2025-01' → 'Team 2025.01', 'databricks-finance-2025-01-30' → 'Finance 2025.01 30'. Replace with a lookup-and-pass-through approach drawn from the same design goose uses in production: - Generator script (scripts/generate-databricks-model-names.py) fetches https://models.dev/api.json and emits a sorted Rust static slice of (id, name) pairs under crates/buzz-agent/src/databricks_model_names.rs. Refresh by rerunning the script and committing the diff. - catalog.rs consults the table via databricks_model_name(id): known managed endpoints get curated names (e.g. 'databricks-gpt-5-5' → 'GPT-5.5'), unknown/custom endpoints return their raw ID unchanged. Applied to all ModelEntry construction paths: v1/v2 discovery, the empty-list fallback, and discovery_failure_fallback. - Frontend: a matching TS registry (desktop/src/features/agents/lib/ databricksModelNames.ts) covers persisted raw IDs on cards, rows, and popovers that render before discovery data is available. formatAgentModelLabel and formatDefaultModelLabel use the registry; no heuristic string mangling exists anywhere in the TS layer. - AGENTS.md documents the three-tier label precedence: API/runtime name first, table-backed fallback second, raw ID last. Supersedes #3586 (kennylopez-model-display-labels). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…l PR - Generator emits both Rust and TypeScript registries in one invocation; both are formatted (cargo fmt, biome) so regenerate is byte-for-byte stable - TS registry uses Map<string, string> — eliminates Object.prototype key hole where 'constructor', '__proto__', 'toString' resolved through Object.prototype instead of passing through as raw IDs - Centralize three-tier resolver (resolveModelLabel) in formatAgentModelLabel.ts; apply to ModelPicker trigger + unsupported-switching state, usePersonaModelDiscovery default rows, and AgentConfigFields defaultModelLabel — all surfaces now show curated names where available instead of raw endpoint IDs - lib.rs module ordering fixed; just fmt-check green - Tests: prototype-key cases (constructor, __proto__, toString, hasOwnProperty), resolver precedence (discovered name wins, blank falls through), DATABRICKS_MODEL_NAMES Map type assertion, Rust/TS parity spot-check; 3794 TS tests pass, 0 fail - AGENTS.md refresh instructions updated: generator emits both files, resolveModelLabel is the single frontend resolver entry point; curl --fail + --max-time 30, explicit JSON shape validation, key/value character validation added to generator Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Two discovered-row callsites still formatted labels inline, so a known Databricks endpoint returned by discovery without a name rendered as its raw ID instead of the curated registry name — the exact inconsistency the shared resolver exists to prevent. The generator also trusted the models.dev payload shape: a non-object model value silently emitted `id -> id`, baking a wrong label into both committed artifacts where no test could distinguish it from a genuine pass-through. Validation now rejects that instead. Registry parity is pinned across the whole table rather than five sampled rows, so a half-committed regenerate cannot pass. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Pre-push branch-skew guard blocked the push: main changed crates/buzz-agent/src/lib.rs and desktop/src/features/agents/AGENTS.md, both touched by this branch, so local checks had run on a tree CI would never test. Both auto-merged without conflict. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
… oracle (#3821) ## What this does Introduces the model-capability manifest infrastructure (Phase 1 of the Model-Capability Manifest plan v4, Thufir-approved 9/9/9). No consumer cutover — `config.rs`, `llm.rs`, `catalog.rs`, and `buzzAgentConfig.ts` are unchanged. Phase 2 wires them. **Single source of truth** replaces hand-mirrored metadata across four files: ``` scripts/model-capabilities.json → hand-curated manifest scripts/generate-model-capabilities.mjs → emits Rust + TS artifacts crates/buzz-agent/src/generated_model_capabilities.rs desktop/src/features/agents/ui/modelCapabilities.ts ``` ## Resolver contract (plan v4 §Resolver contract) Total function `resolve(provider, raw_model_id) → CapabilityResult`. Three ordered steps: 1. Provider-qualified raw exact lookup — key is `(provider, raw_model_id)`, matched before any prefix stripping. A prefixed alias never inherits an exact record. 2. Provider-scoped ordered family rules — on normalized (prefix-stripped) alias, by `match_priority` desc. 3. Per-axis provider fallback — `blank` vs `concrete_unknown`, per provider. Result is complete — every axis populated, runtime consumers never compose fields. ## Boundaries the manifest does NOT own - Transport for pure OpenAI, legacy Databricks, OpenRouter: `OpenAiApi`/`openai_request()` remain authoritative. `databricks_v2_wire_route` is DBv2-only (all other providers emit `not-applicable`). - Final display labels: `resolveModelLabel()` three-tier precedence unchanged. `registry_label` feeds only the static registry tier. - `llm.rs` scope: only `databricks_v2_route_for_model` (Phase 2). ## Test oracle (three independent layers) 1. Generated full-table coverage — `scripts/generated-model-capabilities-coverage.json`: every manifest entry + provider fallbacks. 2. Hand-authored normative corpus — `scripts/normative-corpus.json` (44 vectors): Anthropic manual-budget/adaptive families, OpenAI gpt-5 adversarial boundary cases, DBv2 segment-routing collision tests, P2-A resolver-contract vectors, P2-B blank/concrete-unknown per provider. Runs against JS resolver (`run-corpus.mjs`) and mirrored in Rust (`generated_model_capabilities_tests.rs`). 3. Schema-negative tests — `scripts/test-manifest-validator.mjs` (17 tests): every validator rule has a failing-input test. ## Reconciliation table `scripts/MODELS_DEV_RECONCILIATION.md` — all models.dev divergences dispositioned. `databricks-gpt-5-4-mini` and `databricks-gpt-5-4-nano` adopt models.dev `[low,medium,high]` (family rule adds `none+xhigh` the endpoint doesn't advertise). ## CI `.github/workflows/model-capability-regen-diff.yml`: triggers on manifest/generator/artifact changes; regenerates and fails if stale; runs JS corpus + schema-negative tests. ## Acceptance criteria (plan v4 Phase 1) - Byte-clean regen: `node scripts/generate-model-capabilities.mjs --check` passes - Rust compiles: `cargo check -p buzz-agent` - TS typechecks: `pnpm tsc --noEmit --strict` - 44/44 normative corpus vectors pass (JS interpreter) - 41/41 Rust corpus tests pass - 17/17 schema-negative tests pass (every validator rule) - Reconciliation table complete with doc citations - No consumer changes (config.rs, llm.rs, catalog.rs, buzzAgentConfig.ts untouched) --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…el-label-registry-sync * origin/main: (39 commits) feat(relay): accept kind:30621 multi-repo projects at ingest (#3171) fix(release): preserve main in desktop PR body (#3979) chore(release): release Buzz Desktop version 0.5.3 (#3972) fix(release): require exact-head approval for desktop tags (#3973) fix(release): make desktop tagging squash-safe (#3965) Revert "chore(release): release Buzz Desktop version 0.5.3" (#3960) docs(nips): add single-coordinate manual-unread override layer and verification model to NIP-RS (#2864) chore(release): release Buzz Desktop version 0.5.3 fix(release): make immutable desktop release operable (#3943) feat(desktop): import local Pocket voices (#3259) fix(desktop): open profiles from avatars (#3751) refactor(voice): extract reusable Pocket primitives + Pocket voice settings (relands #2467 + #3208) (#3910) docs: add VISION_REMOTE_AGENTS.md (#3924) feat(desktop): auto-enable huddle transcription for agents (#3180) feat(agent): optional reply guard reminds a silent turn to publish (#3763) feat(desktop): upgrade Pocket TTS model (#3266) feat(desktop): delete a message by clearing its edit to empty (#3813) feat(relay): raise hosted community limit to five (#3829) feat(desktop): locally stored NIP-49 encrypted key backup (#2937) fix(catalog): update Amp tagline (#3806) ... Signed-off-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…capabilities module (#3958) ## What Phase 2 consumer cutover targeting the `duncan/databricks-model-label-registry` umbrella branch. Wires `crates/**` and `desktop/**` consumers to the generated capability module introduced in Phase 1 (#3821), while keeping old and new paths both live for differential testing. Phase 3 removes the old paths. ## Commits (boundary-separated) ### feat(agent): Phase 2a — wire Rust consumers to generated capability module (`crates/**`, `scripts/**`) - `catalog.rs`: `DATABRICKS_V2_KNOWN_MODELS` re-exported from the generated module — single source of truth. - `llm.rs`: `databricks_v2_route_for_model` delegates to `resolve_model_capabilities("databricks_v2", model)`. Old segment-based classifier preserved as `#[cfg(test)] _old_*` for the differential harness. New `databricks_v2_route_differential_old_vs_new` test confirms 100% agreement on all 20 route vectors. - `config.rs`: new `effort_table_fixture_differential_old_vs_new` test runs `resolve_model_capabilities` over the 36-entry `effortTable.fixture.json` and asserts old/new agree modulo a doc-cited allowlist (4 F1 corrections). - `scripts/run-differential.mjs`: JS differential harness over effortTable fixture + normative corpus + catalog-sample fixture. 85 checks, 0 unexpected divergences (5 allowlisted: 4 F1 corrections + goose-opus-5 anthropic route correction). - `scripts/MODELS_DEV_RECONCILIATION.md`: deferred MINOR from Phase 1 — 8 trailing-double-space line breaks replaced with `<br>`. ### feat(desktop): Phase 2b — cut TS consumers to generated model-capabilities module (`desktop/**`) - `buzzAgentConfig.ts`: adds `getProviderEffortConfigFromManifest(provider, model?)` — thin wrapper over `resolveModelCapabilities()` from `modelCapabilities.ts`. Maps `supportedEfforts → validValues` and `defaultEffort → defaultValue` (null preserved for manual-budget/Inherit). Old `getProviderEffortConfig()` and all hand-tables stay live for the differential harness; Phase 3 retires them. - `formatAgentModelLabel.ts`: registry-label lookup re-pointed from hand-maintained `databricksModelNames.ts` import to generated `DATABRICKS_MODEL_NAMES` exported from `modelCapabilities.ts`. Same Map shape, identical contents, behavior unchanged. ### fix(scripts): add ts-esm-loader and fix allowlist coverage in run-differential (`scripts/**`) - `scripts/ts-esm-loader.mjs`: minimal ESM custom loader that resolves extensionless relative TS imports. Required because Phase 2b's `buzzAgentConfig.ts` imports `modelCapabilities` without `.ts` extension — which Node's `--experimental-strip-types` runner cannot resolve without a hook. - `scripts/run-differential.mjs`: shebang updated to self-bootstrap with the loader; fixes the `totalAllowlisted` counter (was declared but never incremented — always printed `0 allowlisted`). Replaced with per-axis hit tracking: reports exercised slot count (`N/total`) in summary; fails with `STALE_ALLOWLIST` if any declared entry fires zero divergences, preventing stale entries from silently masking future regressions. ## Verification - `cargo test -p buzz-agent --lib`: 426/426 - Corpus: 45/45 · schema-negative: 24/24 · `--check` byte-clean - Differential: 85 checks, 0 unexpected divergences, 6/6 allowlist slots exercised - Desktop: 3847/3847 · typecheck clean · biome clean - Mobile: 1019 pass, 1 skipped — same 5 flaky tests in `mobile/test/features/channels/` that reproduce at the umbrella base; zero mobile files in this branch range - `git diff --check`: clean ## What Remains (Phase 3) Remove old hand-maintained paths: `_old_*` functions in `llm.rs`/`config.rs`, old `getProviderEffortConfig` tables in `buzzAgentConfig.ts`, old `databricksModelNames.ts` import in `formatAgentModelLabel.ts`, old `databricks_model_names.rs` module. --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: npub1g8493u0xfsjrvflg4n08ezd7vec99mnwzlv0qgwpr9d7gvjwhuzqx59rhw <41ea58f1e64c243627e8acde7c89be667052ee6e17d8f021c1195be4324ebf04@buzz.block.builderlab.xyz> Signed-off-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Co-authored-by: npub1g8493u0xfsjrvflg4n08ezd7vec99mnwzlv0qgwpr9d7gvjwhuzqx59rhw <41ea58f1e64c243627e8acde7c89be667052ee6e17d8f021c1195be4324ebf04@buzz.block.builderlab.xyz>
* origin/main: (40 commits) fix(mobile): recover stale relay sessions (#4372) chore(release): release Buzz Desktop version 0.5.4 (#4562) test(mobile): assert follow boundary semantics (#4559) docs(release): align desktop handoff instructions (#3988) fix: report agent usage per provider round, not once per turn (#4545) fix(desktop): harden Windows installs against Defender block and orphaned Node (#4382) feat(desktop): improve channel template discovery (#4549) fix(desktop): save key backups to authorized path (#4022) Add channel activity hover menu (#3935) feat(desktop): show saved Run on settings when editing an agent (#4539) fix(desktop): disambiguate provider API key labels and annotate mint key (#4406) fix(desktop): make OpenAI key re-enterable after first save in card mint dialog (#4140) fix(config-bridge): add harness-definition env tier and fix equal-value model override (#3580) Polish mobile composer and messaging UI (#3918) ci(linux): enable mesh-llm feature in Linux release and canary builds (#4524) fix(desktop): stop the create-agent provider config probe from erasing keystrokes (#4411) fix(mobile): recover and pace live subscriptions (#3053) feat(acp): deliver system prompt via _meta.systemPrompt for claude-agent-acp (#4395) fix(security): bump nostr crates for RUSTSEC-2026-0225..0232 + default sprig image to published digest (#4392) fix(desktop): back/forward via keyboard chords, mouse X1/X2 buttons, and swipe gestures (#3778) ... Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
force-pushed
the
duncan/databricks-model-label-registry
branch
from
August 3, 2026 20:04
cc00060 to
4d47f48
Compare
…t apparatus (#4589) ## Summary Retires the old hand-table authorities and transitional verification scaffolding from the model-capability manifest arc. All production routes now run exclusively through the generated interpreters introduced in Phase 1 ([#3821](#3821)) and wired in Phase 2 ([#3958](#3958)). Stack: [#3821](#3821) → [#3958](#3958) → this PR Base: [#3603](#3603) ## What the manifest system is now **Source of truth:** `scripts/model-capabilities.json` **Generator:** `scripts/generate-model-capabilities.mjs` — emits Rust and TS interpreters only (coverage JSON output removed) **Generated interpreters:** `crates/buzz-agent/src/generated_model_capabilities.rs` (+ normative tests), `desktop/src/features/agents/ui/modelCapabilities.ts` **Label registry:** `generate-databricks-model-names.py` → `databricks_model_names.rs` / `databricksModelNames.ts` **Permanent gates:** `scripts/normative-corpus.json` + `scripts/run-corpus.mjs` (both-interpreter equivalence, 51 vectors), `scripts/test-manifest-validator.mjs` (schema, 24 cases), regen-diff job inside `ci.yml` **One doc:** `scripts/MODEL_CAPABILITIES.md` ## Deleted **Old hand-table authorities (production):** - `getProviderEffortConfig_oldHandTable()` and all supporting helpers from `desktop/src/features/agents/ui/buzzAgentConfig.ts` - `normalize_effort_for_openai_route()`, `_old_anthropic_thinking_config_for_databricks_v2()`, test-only re-export wrappers from `crates/buzz-agent/src/config.rs` - `strip_catalog_prefix()`, `anthropic_thinking_config()`, `anthropic_model_supports_xhigh()`, `clamp_adaptive_effort()`, `anthropic_efforts_for_model()`, `is_manual_budget_model()`, `is_adaptive_thinking_model()`, `gpt5_token_matches()`, `gpt5_base_matches()`, `openai_efforts_for_model()` from `crates/buzz-agent/src/config.rs` — all superseded by generated interpreter - Old DBv2 body-level tests, `_OLD_DATABRICKS_V2_*` constants, `model_name_segments()`, `_old_databricks_v2_route_for_model()`, all Phase-2 behavioral differential test functions from `crates/buzz-agent/src/llm.rs` **Transitional scaffolding:** - `scripts/run-differential.mjs` — old-vs-new JS differential harness - `scripts/run-mutation-evidence.mjs` — one-time mutation evidence runner - `desktop/src/features/agents/ui/effortTable.fixture.json` — Phase-2 TS/Rust sync fixture - `desktop/src/features/agents/ui/effortTable.fixture.test.mjs` — fixture sync guard - `.github/workflows/model-capability-regen-diff.yml` — standalone workflow (steps folded into `ci.yml`) **One-time evidence and generated snapshots:** - `scripts/MUTATION_EVIDENCE.md`, `scripts/MODEL_CAPABILITIES_SCHEMA.md`, `scripts/MODELS_DEV_RECONCILIATION.md` — consolidated into `scripts/MODEL_CAPABILITIES.md` - `scripts/generated-model-capabilities-coverage.json` — full-table snapshot (generator no longer emits it) - `scripts/catalog-sample-fixture.json` — models.dev snapshot used only by the deleted differential harness ## Verification - `cargo test -p buzz-agent --lib` with `RUSTFLAGS="-D warnings"`: **337/337** (clean — no dead_code warnings) - `node --experimental-strip-types scripts/run-corpus.mjs`: **51/51** - `node scripts/generate-model-capabilities.mjs` + regen diff: **clean (exit 0)** - `node --test scripts/test-manifest-validator.mjs`: **24/24** - `just clippy`: zero warnings, zero errors --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96
added a commit
that referenced
this pull request
Aug 3, 2026
…t apparatus (#4589) ## Summary Retires the old hand-table authorities and transitional verification scaffolding from the model-capability manifest arc. All production routes now run exclusively through the generated interpreters introduced in Phase 1 ([#3821](#3821)) and wired in Phase 2 ([#3958](#3958)). Stack: [#3821](#3821) → [#3958](#3958) → this PR Base: [#3603](#3603) ## What the manifest system is now **Source of truth:** `scripts/model-capabilities.json` **Generator:** `scripts/generate-model-capabilities.mjs` — emits Rust and TS interpreters only (coverage JSON output removed) **Generated interpreters:** `crates/buzz-agent/src/generated_model_capabilities.rs` (+ normative tests), `desktop/src/features/agents/ui/modelCapabilities.ts` **Label registry:** `generate-databricks-model-names.py` → `databricks_model_names.rs` / `databricksModelNames.ts` **Permanent gates:** `scripts/normative-corpus.json` + `scripts/run-corpus.mjs` (both-interpreter equivalence, 51 vectors), `scripts/test-manifest-validator.mjs` (schema, 24 cases), regen-diff job inside `ci.yml` **One doc:** `scripts/MODEL_CAPABILITIES.md` ## Deleted **Old hand-table authorities (production):** - `getProviderEffortConfig_oldHandTable()` and all supporting helpers from `desktop/src/features/agents/ui/buzzAgentConfig.ts` - `normalize_effort_for_openai_route()`, `_old_anthropic_thinking_config_for_databricks_v2()`, test-only re-export wrappers from `crates/buzz-agent/src/config.rs` - `strip_catalog_prefix()`, `anthropic_thinking_config()`, `anthropic_model_supports_xhigh()`, `clamp_adaptive_effort()`, `anthropic_efforts_for_model()`, `is_manual_budget_model()`, `is_adaptive_thinking_model()`, `gpt5_token_matches()`, `gpt5_base_matches()`, `openai_efforts_for_model()` from `crates/buzz-agent/src/config.rs` — all superseded by generated interpreter - Old DBv2 body-level tests, `_OLD_DATABRICKS_V2_*` constants, `model_name_segments()`, `_old_databricks_v2_route_for_model()`, all Phase-2 behavioral differential test functions from `crates/buzz-agent/src/llm.rs` **Transitional scaffolding:** - `scripts/run-differential.mjs` — old-vs-new JS differential harness - `scripts/run-mutation-evidence.mjs` — one-time mutation evidence runner - `desktop/src/features/agents/ui/effortTable.fixture.json` — Phase-2 TS/Rust sync fixture - `desktop/src/features/agents/ui/effortTable.fixture.test.mjs` — fixture sync guard - `.github/workflows/model-capability-regen-diff.yml` — standalone workflow (steps folded into `ci.yml`) **One-time evidence and generated snapshots:** - `scripts/MUTATION_EVIDENCE.md`, `scripts/MODEL_CAPABILITIES_SCHEMA.md`, `scripts/MODELS_DEV_RECONCILIATION.md` — consolidated into `scripts/MODEL_CAPABILITIES.md` - `scripts/generated-model-capabilities-coverage.json` — full-table snapshot (generator no longer emits it) - `scripts/catalog-sample-fixture.json` — models.dev snapshot used only by the deleted differential harness ## Verification - `cargo test -p buzz-agent --lib` with `RUSTFLAGS="-D warnings"`: **337/337** (clean — no dead_code warnings) - `node --experimental-strip-types scripts/run-corpus.mjs`: **51/51** - `node scripts/generate-model-capabilities.mjs` + regen diff: **clean (exit 0)** - `node --test scripts/test-manifest-validator.mjs`: **24/24** - `just clippy`: zero warnings, zero errors --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Delete scripts/MODEL_CAPABILITIES.md and update the layer-3 note in generated_model_capabilities_tests.rs to be self-contained, dropping the now-dangling file reference. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…rra/validator
CRITICAL: Fix Rust gpt5-base short-version guard to mirror TS regex semantics.
The old 4-char window check diverged from TS /^\d{1,3}(?:[^a-z\d]|$)/i for
inputs like gpt-5-10-preview (10 digits). Replaced with find(non-digit) approach
that exactly matches the TS digit-run semantics. Add left-boundary guards (start
or preceded by '-'/'.') to both gpt5_token_matches_rs and gpt5_base_matches_rs
to prevent sgpt-model-class false-positives.
IMPORTANT: Add exact_records validation to generator — enum checks for all
optional override axes, non-empty override check, canonical-order enforcement,
default_effort-in-override check, match_priority non-negative-int check
(injected into source comments, treated as injection surface). Add 9 schema-
negative tests in test-manifest-validator.mjs.
IMPORTANT: Restrict DBv2 gpt segment rule from starts_with("gpt") to exact
segment match ("gpt" or "gpt5"). Raise priority 5->6 to restore old dual-marker
OpenAI-before-Claude contract. Add left-boundary guards to token helpers. Add
collision-negative corpus vectors: gptoss-model, gptj-6b, gpt-neox,
customgpt-5-5-endpoint.
MINOR: Restore .trim() on model string before resolveModelCapabilities call in
buzzAgentConfig.ts. Make exact-record lookup case-insensitive (lowercase keys at
build + lookup). Extend run-corpus.mjs to compare all 6 axes including
normalization_policy and registry_label. Add positive corpus vectors: opus-5
rule, dbv2 gpt-segment, sol/luna/terra, gpt-5-4-nano exact record, openrouter/
unknown/legacy-databricks fallbacks, case-insensitive lookup vectors. Fix Rust
corpus test harness provider lowercasing to handle vectors like provider=OpenAI.
HYGIENE: Fix "Generated 3 files" -> "Generated 2 files" message. Remove dead
$schema pointer from manifest. Add module doc to generated_model_capabilities_tests.rs
noting hand-maintained status. Switch PROVIDER_ALIASES from plain object to Map
in formatAgentModelLabel.ts and run-corpus.mjs. Align CI node-version to 24.
Tighten python SAFE_NAME_RE from * to + to reject empty display names.
luna/terra: models.dev confirms databricks-gpt-5-6-luna and -terra advertise
[low,medium,high] (differs from sol's [low,medium,high,max]). Added two exact
records with supported_efforts=[low,medium,high], default_effort=medium.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…-phase2-integration Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…gment, 6-axis corpus, validation symmetry, prototype-leak - stripCatalogPrefix boundary-aligned: customgpt/sgpt/mygpt no longer false-strip to gpt-* forms; boundary check requires position 0 or non-alphanumeric precursor - New match_kind gpt-version-segment: gpt-neox-20b routes mlflow-chat (was residual collision); gpt segment match requires next segment to start with digit or be dashless gpt5 form - PROVIDER_FALLBACKS Record→Map: constructor/__proto__ prototype-key leak closed; resolveModelCapabilities/getProviderEffortConfig return complete records for all provider strings - Corpus 69→77 vectors, all 6-axis mandatory; JS and Rust runners hard-fail on missing axes; prototype-key vectors added; boundary-negative vectors added (sgpt-5-5, mygpt-5, customgpt-5-5-endpoint all route mlflow-chat); gpt-neox-20b pinned as mlflow-chat (corrected behavior, not residual collision) - Manifest validator 33→42 tests: family match_priority integer guard, lowercase duplicate-key detection, post-inheritance materialized default∈supported check, assertEfforts shared helper covering family/fallback/exact - Clippy: map_or(false)→is_some_and in emitter template; fmt clean - Desktop regression tests: constructor/__proto__ prototype-key stability Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…gression tests Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
force-pushed
the
duncan/databricks-model-label-registry
branch
from
August 4, 2026 19:36
c1f7517 to
8016fe9
Compare
Emitter generated `DEFAULT_FALLBACK` as an untyped object literal; its `as const` effort arrays and widened `defaultEffort` union didn't satisfy `CapabilityResult`, failing tsc with TS2322 at line 861. Add explicit type annotation matching the PROVIDER_FALLBACKS Map value type so the `??` fallback path type-checks. Regen TS artifact only (Rust unaffected). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
force-pushed
the
duncan/databricks-model-label-registry
branch
from
August 4, 2026 21:16
0189510 to
15aa135
Compare
…to exact records Implements Thufir pass-1 finding 5 and Will's display ruling (a): a model's display name comes from an exact/curated record only; family labels never masquerade as model names. Changes: - Fold all 30 registry_labels entries into databricks_v2 exact records; reconcile GPT-5.4 mini/nano casing to models.dev verbatim (lowercase). - Remove registry_label from all 16 family rules — family-matched models resolve registryLabel: null (display falls to raw ID or discovery name). - Emit DATABRICKS_MODEL_NAMES from exact records (provider=databricks_v2 + registry_label), replacing the registryLabelsArr source. - Point catalog.rs at generated_model_capabilities::DATABRICKS_MODEL_NAMES. - Delete python chain: generate-databricks-model-names.py, databricks_model_names.rs (+ lib.rs decl), databricksModelNames.ts, databricksModelNames.test.mjs. - Update desktop/src/features/agents/AGENTS.md: manifest is the label authority; document display rule (a) and single-chain refresh. - Corpus: 80 vectors (3 added for gpt-5-mini/nano exact-label pins and one family-matched-no-exact → null); 37 existing vectors updated to null for family-matched labels; 3 casing vectors updated to lowercase. - Validator: replace 3 stale registry_labels schema-negative tests with 2 exact_record tests (duplicate key rejection, empty label rejection). - File-size ratchet: add fileOverrides parameter to runFileSizeCheck so the generated modelCapabilities.ts can have a tighter per-file ceiling (1200) rather than the hand-authored 1000-line default. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…s + curated labels) Main's #4008 reauthentication loop (discover_databricks_models_with_token_source), authenticated_empty_v2_catalog(), configured_model_fallback(), and removal of discovery_failure_fallback() all land. Our labeling wins at every ModelEntry construction site: databricks_model_name() applied in parse_v1_endpoints, parse_v2_endpoints_page, and authenticated_empty_v2_catalog (curated label + suffix). DATABRICKS_V2_KNOWN_MODELS stays as the generated-constant re-export. lib.rs auto-merged cleanly: resolve_models_catalog now returns Result (main's shape); discovery_failure_fallback callers replaced by configured_model_fallback. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
The key was an empty array with zero references in the generator or validator after the consolidation round folded all labels into exact records. Regen is byte-clean before and after the deletion. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Route the display name through databricks_model_name() so that when Databricks discovery fails the picker shows the curated label (e.g. GPT-5.5) rather than the raw model ID — consistent with every other ModelEntry construction site in catalog.rs. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
… fileOverrides boundary Rule (a) is now structurally unexpressible: the generator rejects any family rule carrying registry_label (exit non-zero), removes the dead reads from resolveFamilyRules() and both emitters, and adds a schema-negative test to catch reintroduction. The fileOverrides integration test is replaced with a real temporary- repository runFileSizeCheck() call: proves the named path passes under its raised ceiling, proves a second governed path at the same size still fails (no leak), and restores process.exitCode and console.error in cleanup for test isolation. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Add a second empty commit to the temp repo before staging test files so HEAD^1 resolves in CI (where resolveBaseRef returns HEAD^1 as the base). Remove now-unused spawnSync import. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR establishes a single hand-curated model-capability manifest (
scripts/model-capabilities.json) as the source of truth for model metadata — display labels, supported reasoning-effort sets, default efforts, thinking modes, and Databricks v2 wire routes. A generator emits equivalent Rust and TypeScript interpreters from it, production resolution in both languages runs on the generated interpreters, and the superseded hand-maintained tables are deleted. It also ships the curated Databricks label registry and the frontendresolveModelLabel()contract.Closes #3586. Landed as three sub-PRs into this branch: #3821 (manifest + generator), #3958 (production integration), #4589 (hand-table retirement).
Capability manifest and generated interpreters
scripts/generate-model-capabilities.mjsreads the manifest and emits two committed artifacts from one source of truth:crates/buzz-agent/src/generated_model_capabilities.rsdesktop/src/features/agents/ui/modelCapabilities.tsThe generator validates every interpolated manifest string through a shared
requireSafeString()boundary (rejects quotes, backslashes, control chars), enforces the manifest schema (41 negative tests inscripts/test-manifest-validator.mjs, covering effort canonicality, post-inheritance record consistency, integer match priorities, and normalized duplicate keys), and supports--checkfor byte-clean verification.Production integration
Rust (
buzz-agent): reasoning-effort normalization for OpenAI and legacy Databricks flows throughnormalize_effort_for_provider(), backed by the generated interpreter;anthropic_body()is provider-aware and Adaptive thinking clamps against the generatedsupported_efforts; Databricks v2 request routing reads the manifest'sdatabricks_v2_wire_routeinstead of a hand-maintained segment classifier. The superseded effort/thinking hand tables and model-family classifiers inconfig.rsandllm.rsare deleted — the generated interpreter is the only authority.Desktop:
getProviderEffortConfig()resolves through the generatedmodelCapabilities.ts;canonicalizeProvider()(trim/lowercase plus thedatabricks-v2andopenai-compataliases) is applied before every provider-scoped lookup, and the provider is threaded through all label/effort surfaces so a supplied provider can never fall through to unscoped registry lookups. The old hand-table effort path and its fixture are deleted.Drift protection
The
model-capabilitiesjob in.github/workflows/ci.ymlgates every PR:scripts/normative-corpus.json) against both interpreters —scripts/run-corpus.mjsfor TS, generated Rust tests for Rust — every vector pins all six capability axes (label, thinking mode, effort set, default effort, wire route, normalization policy), and both runners reject sparse vectors;cargo test -p buzz-agent --lib(the only CI gate exercising thebuzz-agentunit suite;just test-unitexcludes that crate).Model display labels
The manifest's
databricks_v2exact records carry aregistry_labelaxis with models.dev-verbatim display names for the ~30 managed Databricks endpoints. The generator derives a flatDATABRICKS_MODEL_NAMESregistry from those records and emits it into both artifacts (Rust static slice, TSMap), so the two languages cannot drift.Display rule: a model's display name comes from an exact/curated record only — family rules carry no labels, so a family-matched ID with no curated record resolves
registryLabel: nulland displays its raw ID (or its upstream discovery name). Endpoint IDs likedatabricks-gpt-5-5resolve to human-readable labels (GPT-5.5); unknown or custom workspace endpoints pass through as their raw ID unchanged, so a custom endpoint likedatabricks-team-2025-01can never be given an invented name.Rust label resolution
databricks_model_name(id)incrates/buzz-agent/src/catalog.rsreads the generated registry and is applied at everyModelEntryconstruction path — v1 and v2 discovery parsing, the authenticated-empty-catalog slate, and the configured-model fallback — soAgentModelInfo.namereaches the frontend already curated. Mirrors the existingopenai_model_display_nameprecedent; no new IPC.DATABRICKS_V2_KNOWN_MODELSis likewise a re-export of the generated constant.Frontend label resolution
resolveModelLabel(id, discoveredName?, provider?)indesktop/src/features/agents/lib/formatAgentModelLabel.tsowns the label contract with three-tier precedence: nonblank discovered/API name, then registry lookup by ID (provider-qualified exact record when a provider is supplied; unscoped registry only on the providerless path), then raw ID. Every model-label surface routes through it —ModelPicker,usePersonaModelDiscovery,agentCardModelLabel,AgentConfigFields,ManagedAgentRow,UserProfilePopover.formatAgentModelLabel()wraps the resolver so a null or empty ID rendersAuto.Tests
cargo test -p buzz-agent --libcovers the corpus harness and generated-interpreter tests as a CI merge gate.Config::validate(), Anthropic-route effort normalization (none/minimalomitted from the wire), and the unsupported-effort clamp throughanthropic_body()(a no-xhighmodel record clampsxhightohigh).databricks-gpt-5-mini→GPT-5 Mini), and a family-matched ID with no curated record pinsregistry_label: null; provider-alias tests pinopenai-compat/databricks-v2canonicalization in the desktop surfaces.usePersonaModelDiscovery.test.mjspins discovery-row label precedence; Rust unit tests incatalog.rscover known IDs, custom endpoints, and the known-models fallback slate.Docs and build infra
desktop/src/features/agents/AGENTS.mddocuments label precedence and the regeneration workflow (editscripts/model-capabilities.json, runnode scripts/generate-model-capabilities.mjs); the generator and CI job emit the regeneration command on any stale-artifact failure.desktop/scripts/check-file-sizes.mjsgains afileOverridesmechanism because the generatedmodelCapabilities.tsexceeds the 1000-line ceiling intended for hand-authored files.