Tags: VectifyAI/OpenKB
Tags
feat(web): 7566 default port + "web" install extra/command (api alias… …es kept) + panel chrome-lane fix (#193) * feat(api): default port 7566 + name the install extra/command "web" The API server also serves the Knowledge Workbench UI, so `web` reads truer than `api` for what people install and run. Make `[web]` the canonical extra and add an `openkb-web` console script; keep `[api]` (as a self-referential alias) and `openkb-api` working for backwards compatibility. README and the rest-api example now lead with the `web` names. `python -m openkb.api` (the module path) is unchanged. Also move the default API port off the crowded 8000 to 7566 ("KB" = ASCII 75,66) to cut collisions with other local dev servers. Updated: the argparse default, the default CORS origins, the Vite dev-proxy target, the connection-dialog placeholder, and the README/examples. A server already running on 8000 keeps its port; the new default only applies to freshly started servers. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(workbench): keep ArtifactPanel header buttons out from under the global chrome pills The docked artifact panel's header action buttons (open-in-tab / download / close) sit at the panel's top-right — exactly where App.tsx's global floating chrome cluster (theme + i18n toggles, `absolute right-3 z-40`) renders. The cluster's higher stacking context covered the download and close buttons. Reserve the ~112px chrome lane on the header with `pr-28`, matching the existing convention used by KbList's header row and KbDetail's gear row, so the panel buttons always clear the pills. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG
feat: make indexing and compile concurrency configurable (#174) * feat(indexer): expose pageindex_max_concurrency to cap indexing concurrency PageIndex fans out one indexing LLM call per structure node; on a large document that can open a socket per node and exhaust the process file-descriptor limit ("[Errno 24] Too many open files"). This wires an OpenKB config knob through to PageIndex's IndexConfig.max_concurrency cap. - New `pageindex_max_concurrency` KB config key (default None = let PageIndex apply its own default). - indexer forwards it via `_build_index_config` only when set AND the installed PageIndex's IndexConfig declares the field, so OpenKB keeps working against a pinned PageIndex that predates it (IndexConfig forbids unknown kwargs). * feat(config): make compile concurrency configurable (closes #173) Concept/entity generation ran at a hardcoded concurrency of 5 (DEFAULT_COMPILE_CONCURRENCY) with no way to lower it when the LLM provider rate-limits. Add a `compile_concurrency` config key (default 5) and thread it through every add / recompile / cloud-import compile call via a shared `_compile_concurrency` resolver (null / non-positive → the compiler default). Pairs with `pageindex_max_concurrency` (indexing side) from this PR — both concurrency knobs are now KB-configurable. * fix(config): address xhigh code-review findings on the concurrency knobs - resolve_compile_concurrency moves to config.py (matching resolve_timeout's convention) and now rejects bool (bool is an int subclass, so `compile_concurrency: true` previously silently became concurrency=1) and logs a warning on any malformed value, same as the other resolvers. - _build_index_config now warns when pageindex_max_concurrency is configured but the installed PageIndex doesn't support the field yet, instead of silently dropping it with no signal to the user. - Replaced the tautological test_forwards_max_concurrency_when_supported (which branched on the same runtime condition as the code under test, so it never exercised the forwarding assertion under CI's pinned PageIndex) with fake IndexConfig doubles that make both branches deterministic regardless of the installed pageindex version. - Added a cross-check test pinning DEFAULT_CONFIG["compile_concurrency"] against the compiler's own DEFAULT_COMPILE_CONCURRENCY so the two literals can't silently drift apart. - Added an end-to-end test proving index_long_document's own loaded config (not just a hand-built dict) reaches PageIndexClient's IndexConfig. - Hoisted the compile-concurrency resolution out of `recompile --all`'s per-document loop (was recomputed every iteration despite being loop-invariant). - Documented both new config.yaml keys in config.yaml.example and examples/configuration/README.md (kept in sync). * refactor(config): unify pageindex_max_concurrency + compile_concurrency into `concurrency` PageIndex indexing and OpenKB's own concept/entity compilation never run concurrently with each other for the same document (they're sequential phases of one add), and both knobs exist for the exact same reason — the user hit a provider rate limit or an fd ceiling. Splitting them by internal subsystem leaked OpenKB's architecture into the config surface for no practical benefit, since a user tuning one for a rate limit would set the other to the same value anyway. - Single `concurrency` config key (default null = each stage keeps its own built-in default). - config.resolve_concurrency(config) -> int | None: validates (rejects bool and non-positive values with a warning), returns None on unset/invalid — no default substitution inside; callers decide what None means for them. - cli.py's compile call sites: `resolve_concurrency(config) or DEFAULT_COMPILE_CONCURRENCY`. - indexer.py's _build_index_config now routes through resolve_concurrency (openkb validates before forwarding to PageIndex, rather than relying solely on PageIndex's own future validator) instead of raw config.get. - This also removes the prior dual-literal-default drift risk entirely: there's no second numeric default to keep in sync, since an unset `concurrency` simply forwards nothing to PageIndex and lets the compiler use its own DEFAULT_COMPILE_CONCURRENCY. - Updated config.yaml.example and examples/configuration/README.md (kept in sync) to the single key. * build(deps): bump pageindex to 0.3.0.dev2 (ships IndexConfig.max_concurrency) 0.3.0.dev2 is the first published release that declares IndexConfig.max_concurrency, so `concurrency` in config.yaml now takes effect for the indexing stage in a normal `pip install` / `uv sync`, not just against a local editable checkout. Vetted: downloaded the wheel and confirmed its sha256 matches PyPI (b0cb1f6e…) and that IndexConfig declares `max_concurrency: int | None` with a positivity field_validator. uv.lock regenerated via `uv lock --upgrade-package pageindex`. The runtime `"max_concurrency" in IndexConfig.model_fields` guard in indexer._build_index_config is now always-true under the pinned dependency, but is kept as graceful degradation for mismatched local installs. * refactor(config): keep concurrency out of DEFAULT_CONFIG (align with other optional knobs) Every other optional tuning knob (timeout, extra_headers, litellm, entity_types, parallel_tool_calls) is resolved via its resolver's .get() and lives only in config.yaml.example, not DEFAULT_CONFIG — which holds just the core keys openkb init writes (model, language, pageindex_threshold). concurrency was the lone exception; resolve_concurrency already reads it via .get(), so the DEFAULT_CONFIG entry was redundant. Remove it for consistency. * build(deps): bump pageindex 0.3.0.dev2 -> 0.3.0.dev3 Vetted: identical Requires-Dist/Requires-Python to dev2; IndexConfig, PageIndexClient, and IndexConfig.max_concurrency (used by #174) all still present; wheel/sdist hashes verified against PyPI. uv.lock regenerated via `uv lock` (change scoped to the pageindex entry). Also aligns the stale dev1 reference in the config README. * feat(cli): add --version flag The CLI group had no way to report its version (`openkb version` / `openkb -v` both fail). Add `@click.version_option(package_name="openkb")` so `openkb --version` prints "openkb <version>", read from installed package metadata (tracks the hatch-vcs-derived version, no hardcoded string).
feat(config): pass through LiteLLM settings via a `litellm:` config b… …lock (#138) Add an optional `litellm:` mapping in .openkb/config.yaml as the single place to tune LiteLLM. Keys are forwarded to LiteLLM: `timeout` and `extra_headers` apply per request (the existing per-call mechanism, covering both the compiler and the agents-SDK paths), and the rest are set as litellm module globals (drop_params, num_retries, ssl_verify, ...). Resolves the Ollama UnsupportedParamsError in #137: `litellm: {drop_params: true}` lets LiteLLM drop params a provider rejects (e.g. parallel_tool_calls on Ollama). - config.resolve_litellm_settings(): validate the value is a mapping, drop non-string keys, pass values through verbatim (the user owns them). - cli._setup_llm_key(): the `litellm:` block is canonical — when it specifies `timeout` / `extra_headers` they route to the per-call stashes and replace the legacy top-level keys (an empty `extra_headers: {}` clears, not reverts); the rest go to cli._apply_litellm_settings(), which setattrs each onto litellm. Guards: skip+warn an unknown key, and refuse to overwrite a litellm function. Globals are applied process-wide and not reset. - Back-compat: the legacy top-level `timeout:` / `extra_headers:` keys still work (now undocumented; the `litellm:` block is the documented surface). - warnings go through the logger (stderr), not click.echo, so a typo can't corrupt piped stdout (e.g. `openkb query > out.txt`). - docs: config.yaml.example consolidated under `litellm:`; README drops the now-redundant top-level extra_headers section. Closes #137
feat(skills): add openkb-deck-neon (dark Aurora Glass) + make it the … …default deck skill (#101) * feat(skills): add openkb-deck-neon — dark Aurora Glass deck skill A neon / glassmorphism deck visual direction parallel to openkb-deck-editorial: near-black canvas, teal/sky/magenta accents, aurora atmosphere, glass panels, and a scale-to-fit 16:9 stage that letterbox-fills any viewport (no fixed 1280px card).
refactor(locks): delegate cross-platform file locking to portalocker (#… …100) * refactor(locks): delegate file locking to portalocker Replace the hand-rolled fcntl/msvcrt flock/funlock (merged in #99) with portalocker, which is fcntl-backed on POSIX and msvcrt/Win32-backed on Windows with maintained, cross-platform-tested behaviour. Removes the hand-written Windows retry/timeout loop that could not be exercised on POSIX. - flock/funlock now delegate to portalocker.lock/unlock. - Drop the guarded 'import fcntl', the msvcrt fallback, and _WINDOWS_LOCK_TIMEOUT. - Keep the os.fchmod guard and Windows directory-fsync skip (atomic writes, which portalocker does not cover). - Pin portalocker==3.2.0 (BSD-3) to match the exact-pin dependency policy. Note: true shared (reader) locks on Windows would still need pywin32; without it portalocker uses msvcrt (exclusive). Not added — in-process concurrent KB reads are rare. Refs #93. Tests: swap the msvcrt-internals tests for a cross-process exclusion test that verifies flock takes a real OS lock, plus the retained atomic-write/fsync-skip guards. Full suite 749 passed. * fix(locks): review fixes — accurate docs, fcntl import guard, test hardening Addresses /code-review findings on the portalocker refactor: - flock docstring corrected: portalocker uses Win32 LockFileEx (pywin32, pulled in automatically on Windows) for SHARED locks, so concurrent readers ARE honoured; EXCLUSIVE uses msvcrt (retries ~10s then raises, not an infinite block); failures raise portalocker.LockException, not OSError. - Re-add the issue #93 regression guard: assert no openkb module hard-imports the Unix-only fcntl at module level (replaces the dropped import-without-fcntl test without depending on portalocker internals). - Strengthen the cross-process lock test: assert both BLOCKED (while held) and ACQUIRED (after release), and check the probe's exit code so an ImportError surfaces clearly instead of an empty-stdout false failure. - Drop the now-dead 'import pytest' / 'import portalocker' from the test module. * test(locks): resolve code-quality bot nits — single openkb import style Drop the unused 'import openkb' and derive the package dir from locks.__file__ instead, so the test module uses one import style for openkb (github-code-quality bot). The unused 'import portalocker' was already removed in the prior commit.
PreviousNext