Skip to content

Tags: VectifyAI/OpenKB

Tags

v0.5.0-rc1

Toggle v0.5.0-rc1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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

v0.4.5

Toggle v0.4.5's commit message
chore(deps): update uv.lock for openai==2.44.0 pin (#187)

v0.4.4

Toggle v0.4.4's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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).

v0.4.4-rc1

Toggle v0.4.4-rc1's commit message
openkb 0.4.4-rc1

- feat(config): configurable ingest concurrency (#174, closes #173)
- fix(agent): Bedrock parallel_tool_calls + per-agent defaults (merged #177/#175)
- build(deps): pageindex 0.3.0.dev3

Pre-release cut from feat/pageindex-max-concurrency for real-world testing.

v0.4.3

Toggle v0.4.3's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(converter): preserve docx embedded images from markitdown (#163)

Fixes #162.

v0.4.2

Toggle v0.4.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
docs: compress architecture diagram to WebP (#145)

Convert assets/openkb-architecture.png (1.78MB) to WebP at q85
(~195KB, -89%) and update the README reference. Visually lossless for
the diagram's text and line work.

v0.4.2-rc1

Toggle v0.4.2-rc1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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

v0.4.1

Toggle v0.4.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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).

v0.4.0-rc3

Toggle v0.4.0-rc3's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.