Skip to content

feat(workbench): configurable entity types (global default + per-KB override)#200

Merged
KylinMountain merged 3 commits into
mainfrom
feat/workbench-entity-types-config
Jul 22, 2026
Merged

feat(workbench): configurable entity types (global default + per-KB override)#200
KylinMountain merged 3 commits into
mainfrom
feat/workbench-entity-types-config

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

Makes the entity-extraction vocabulary (entity_types) user-configurable — a global default plus a per-KB override — surfacing a setting the compiler already honored but that was previously only editable by hand-writing config.yaml.

Backend (92f8f41)

entity_types now flows through the config read/write API, layering global.yaml → KB config.yaml exactly like the other config scalars:

  • a KB list overrides the global list wholesale; an explicit null inherits; unset falls back to DEFAULT_ENTITY_TYPES (person/organization/place/product/work/event/other).
  • GLOBAL_SCALAR_KEYS gains entity_types (the value-not-None-wins layering + per-key sources tracking is type-agnostic, so it works for a list).
  • GET/PATCH /api/v1/kb/config and GET/PATCH /api/v1/config carry entity_types. Reads report the cleaned effective list (resolve_entity_types: lowercased, charset-restricted, deduped, "other" ensured) plus the raw global value for the inherited badge.
  • The compiler already consumed config["entity_types"] via resolve_entity_types; nothing there changed.

Frontend (9abd2bb)

  • EntityTypesEditor: a shared chips editor — Enter/comma to add, × to remove, "other" rendered as a fixed "always included" chip, IME-safe composition.
  • KB settings sheet: an EntityTypesRow with the same inherit/override Switch as the scalar rows — override on seeds + persists the KB's own list, off reverts via null; the inherited state shows the global/default list as a badge. Each chip change persists and adopts the server-cleaned response.
  • Global Settings (general tab): a global chips editor, order-sensitive diff into the save patch (joins the existing dirty/save-bar flow).
  • Both surfaces show a "changes affect future recompiles only; existing entity pages keep their type" note.

Semantics

  • Per-KB list replaces the global list (not merged) — same as a scalar override.
  • "other" is always ensured server-side (the coercion fallback), shown as non-removable.
  • Changing the vocabulary only affects future compiles; existing entity pages keep their type: until recompiled.

Verification

Backend pytest 1240 passed, mypy/ruff clean; new tests cover KB override (cleaned + source kb) + null revert, global patch, and global-source inheritance. Frontend npm run build green (i18n guard: zh/en key sets identical across common/kbSettings/settings). Manually exercised on a running openkb-web.

Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG

… API

entity_types (the entity-extraction vocabulary) is now surfaced through the
config read/write API, layering global.yaml -> KB config.yaml like the other
scalars: a KB list overrides the global list wholesale, an explicit null
inherits, and unset falls back to DEFAULT_ENTITY_TYPES. The compiler already
consumed config["entity_types"] via resolve_entity_types; this just exposes it.

- GLOBAL_SCALAR_KEYS gains "entity_types" (layering + per-key `sources` tracking;
  the value-not-None-wins rule is type-agnostic, so it works for a list).
- _KbConfigWritable / GlobalConfigValues / KbConfigResponse / GlobalConfigResponse
  carry entity_types; read_kb_config/read_global_config report the cleaned
  EFFECTIVE list (resolve_entity_types) plus the raw global value for the badge.
- PATCH /api/v1/kb/config and PATCH /api/v1/config accept entity_types.

Tests: KB override (cleaned + source 'kb') + null revert, global patch, global
inheritance; updated the global-defaults shape assertion. Frontend UI follows.

Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG
…r-KB override)

- EntityTypesEditor: shared controlled chips editor (Enter/comma to add, x to
  remove; "other" is a fixed always-included chip; IME-safe composition).
- KbSettingsSheet: an EntityTypesRow with the same inherit/override Switch as the
  scalar rows — turning override on seeds+persists the KB's own list, off reverts
  via null; inherited state shows the global/default list as a badge. Each chip
  change persists and adopts the server-cleaned response.
- Settings (general tab): a global entity-types chips editor, order-sensitive
  diff into the save patch (joins the existing dirty/SaveBar flow).
- "changes affect future recompiles only" note on both surfaces.

New keys in common/kbSettings/settings (zh + en, identical sets). Build green
(i18n guard OK). Backend was committed in 92f8f41.

Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG
…y-list inherit, silent reads, set-diff

- config: define DEFAULT_ENTITY_TYPES before DEFAULT_CONFIG and add
  `entity_types` to DEFAULT_CONFIG so the key layers like every other
  GLOBAL_SCALAR_KEY and always appears in the effective config (#1).
- config: resolve_effective_config treats an empty entity_types list the
  same as null → inherit, so a KB that cleared its override doesn't pin an
  empty vocabulary (#2).
- config: resolve_entity_types(config, *, warn=True); config-read paths pass
  warn=False so a plain GET doesn't spam coercion warnings (#4).
- api_config: both read paths call resolve_entity_types(..., warn=False).
- KbSettingsSheet: inherited badge shows the effective list, not
  `globalValue ?? effective`; drop the now-unused globalValue prop (#3).
- Settings: global entity_types diff is order-insensitive — the vocabulary
  is a set, so re-adding a removed type is not a change (#6).

Backend pytest 1240 passed; ruff/format/mypy clean; frontend build green.

Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG
@KylinMountain
KylinMountain merged commit ff54396 into main Jul 22, 2026
4 checks passed
@KylinMountain
KylinMountain deleted the feat/workbench-entity-types-config branch July 22, 2026 03:44
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