Skip to content

Fix: add litellm/ prefix for Agents SDK model routing - #7

Merged
rejojer merged 2 commits into
devfrom
fix/litellm-agent-model-prefix
Apr 8, 2026
Merged

Fix: add litellm/ prefix for Agents SDK model routing#7
rejojer merged 2 commits into
devfrom
fix/litellm-agent-model-prefix

Conversation

@rejojer

@rejojer rejojer commented Apr 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Add litellm/ prefix to all Agent(model=...) calls so non-OpenAI models (e.g., anthropic/claude-sonnet-4-6, gemini/gemini-2.5-pro) are correctly routed through LiteLLM by the OpenAI Agents SDK
  • litellm.completion() and PageIndexClient calls remain unchanged (they use LiteLLM format directly)
  • Update README: improve quick start comments, polish model format docs
  • Remove PageIndex section from .env.example

Test plan

  • Verified all 4 model formats (gpt-5.4, openai/gpt-5.4, anthropic/claude-sonnet-4-6, gemini/gemini-2.5-pro) work with both litellm.completion() and Agent(model=litellm/...) using LLM_API_KEY
  • Unit tests pass
The OpenAI Agents SDK requires a litellm/ prefix to route non-OpenAI
models through LiteLLM. Without it, models like anthropic/claude-sonnet-4-6
fail with "Unknown prefix". This adds the prefix at all Agent() call sites
while keeping litellm.completion() calls unchanged.

Also updates README quick start comments and model format docs.
@rejojer

rejojer commented Apr 7, 2026

Copy link
Copy Markdown
Member Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

@rejojer
rejojer merged commit 0117751 into dev Apr 8, 2026
KylinMountain added a commit that referenced this pull request Jul 21, 2026
…es (#198)

* feat(api): delete a knowledge base (POST /api/v1/kb/delete + openkb delete-kb)

Physical, irreversible KB deletion with a type-the-name confirmation.

- config.delete_kb: rmtree the KB directory + unregister it from the global
  registry (known_kbs / kb_aliases / default_kb, via the new unregister_kb).
  Guards against deleting a non-KB path; tolerates a ghost registry entry
  (directory already gone) by just unregistering.
- POST /api/v1/kb/delete: confirm_name must equal kb, re-checked server-side.
  Lives in a new api_kbs_router (sibling of the config/graph/output routers) so
  api.py stays under the 800-line gate; delete_kb self-locks (config lock), no
  create_app closure needed.
- openkb delete-kb NAME: type-the-name prompt (or --yes) then delete.

Tests: endpoint (success + unregister, confirm mismatch, non-KB target) in
test_api.py; config (physical delete + unregister, refuse non-KB, ghost
tolerance) in test_config.py.

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

* feat(api): delete a wiki page (POST /api/v1/page/delete) with backlink impact

Delete a concept/entity page and degrade references cleanly instead of leaving
them dangling:

- page_ops.delete_wiki_page: dry_run reports the backlink pages (whose inbound
  [[wikilinks]] would be demoted) without touching anything; execute removes the
  page under the KB ingest lock, strips its index.md entry outright
  (compiler.remove_doc_from_index — the entry is a [[link]] line), and demotes
  the now-dangling inbound [[links]] to plain text in ONLY those backlink pages
  (lint.fix_broken_links restrict_to). The page ref is "section/stem", validated
  to concepts/ or entities/ only (path-traversal-safe).
- New api_pages_router hosts POST /api/v1/page (read — relocated here from
  api.py to keep it under the 800-line gate) + POST /api/v1/page/delete.

Tests: dry-run impact + execute (page gone, inbound link demoted to text, index
entry removed, sibling kept), 404 on missing page, and rejection of unsafe /
non-editable refs.

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

* feat(api): edit a wiki page (PUT /api/v1/page) + link context (POST /api/v1/page/links)

- page_ops.edit_wiki_page: replace a concept/entity page's BODY while preserving
  its code-managed OKF frontmatter (type/description/sources) verbatim; any
  frontmatter in the submitted content is dropped. Dead [[wikilinks]] the user
  typed are demoted to plain text on save (OpenKB keeps the wiki broken-link-free)
  and returned as ghosts_stripped so the UI can warn. Atomic write under the KB
  ingest lock.
- page_ops.page_link_context (POST /api/v1/page/links): outbound + inbound links
  for the edit-impact panel. Editing the body does not break either (links are
  path-based), so this is context, not a blocker — the honest impact model.
- PUT /api/v1/page added to api_pages_router.

Tests: edit preserves frontmatter + keeps a resolvable link + demotes a dead one
(reports ghosts_stripped) + replaces the body; 404 on a missing page; links
reports out/backlinks.

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

* feat(web): delete a knowledge base from the settings sheet (type-name confirm)

Adds a Danger Zone section to KbSettingsSheet: a type-the-name confirmation
gates deleteKb() (POST /api/v1/kb/delete); on success KbDetail navigates back
to the KB list. New deleteKb client + kbSettings danger* keys + common cancel
(zh + en, identical key sets).

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

* feat(web): in-reader page edit + delete with impact preview (F2/F3)

For an open concept/entity page, the reader header now shows Edit and Delete:
- Delete: a dry-run first (deletePage dryRun) surfaces the backlink pages whose
  [[links]] will demote to plain text; a red confirm card lists them, then the
  real delete closes the page and refreshes the inventory.
- Edit: a body textarea (frontmatter is preserved server-side), Save via
  PUT /api/v1/page, a links panel (getPageLinks: out/backlinks), a "recompile
  may overwrite" note, and a toast listing any dead links demoted to text.

Adds the deletePage/editPage/getPageLinks wiki clients and kb:pageOps.* locale
keys (zh + en, identical key sets). Build green (i18n guard + tsc + vite).

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

* fix(workbench): address code-review findings (content-mgmt correctness + concurrency)

Backend (page_ops / kb_admin / lint):
- delete/edit now do their read-modify-write INSIDE the KB ingest lock and
  re-check the page exists under it: no stale backlink snapshot, no resurrecting
  a concurrently-deleted page, no 500 on a racing unlink (missing_ok=True). [#4,#5,#6]
- delete_kb serializes rmtree under the ingest lock (was fully unlocked). Moved
  delete_kb/unregister_kb into a new openkb/kb_admin.py so config.py drops back
  under the per-file line gate (751 lines). [#1,#15]
- page deletion no longer scans or rewrites lint's _EXCLUDED_FILES
  (AGENTS.md/SCHEMA.md/log.md); fix_broken_links(restrict_to) also refuses them,
  which protects `openkb remove` too. [#2]
- edit_wiki_page treats `content` as the body verbatim — no naive frontmatter
  split that silently dropped a body opening with a '---' block. [#3]
- delete uses the real on-disk stem for the exact-match index-entry removal
  (case-insensitive FS), and adds index.md to the demotion set so a [[target]]
  embedded in another entry's brief no longer dangles. [#7,#9]

API / CLI:
- delete-KB endpoint & CLI can now clean a ghost registry entry (registered name
  whose directory was removed by hand), catch delete_kb's ValueError -> 400, and
  the endpoint is typed `-> KbDeleteResponse`. [#8,#13,E5]

Frontend (KbDetail):
- Deleting a KB dispatches `openkb:reload-kbs` so the sidebar refreshes
  immediately (was stale until a manual reload) — live-test fix.
- Removed the dead `pageReloadSeq` path (editPage always returns content). [#14]

Tests: excluded-doc-untouched, '---'-body preservation, ghost-KB unregister;
non-KB-target test updated to the new resolution model. Backend 1234 passed,
mypy/ruff clean, frontend build green.

Not changed (intentional): pages_linking_to is NOT folded into build_graph (that
excludes explorations/ backlinks) [#10]; the preview+confirm delete inherently
scans per request [#11]; EDITABLE_SECTIONS stays duplicated in the frontend,
which can't import the Python constant [#12].

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

* feat(workbench): allow editing summary pages (edit ⊇ delete section sets)

Summaries are compiled markdown like concepts/entities (a recompile regenerates
them), so they are now editable via PUT /api/v1/page. They remain NOT
independently deletable — a summary is removed by deleting its source document.

Split page_ops into EDITABLE_SECTIONS (concepts/entities/summaries) vs
DELETABLE_SECTIONS (concepts/entities); validate_page_ref takes the allowlist.
Frontend ReaderBody gates Edit on canEdit (incl. summaries), Delete on canDelete.

Test: summary editable (frontmatter preserved) + summary delete rejected (400).

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

* fix(api): cross-platform delete_kb + endpoint OSError handling (xhigh review #1,#2)

- delete_kb no longer holds the ingest lock DURING rmtree (the lock file lives
  inside the KB dir; Windows cannot delete an open file — the prior review-fix
  regressed this). It now takes the lock as a BARRIER (drain + wait out any
  in-flight mutation), releases it, re-checks existence, then rmtrees. [#1]
- delete-KB endpoint maps FileNotFoundError to an idempotent success (a
  concurrent delete already removed the tree) and other OSError to a clean 500
  with a message, instead of an uncaught 500 stack trace. [#2]

Tests: endpoint OSError -> clean 500, FileNotFoundError -> 200 deleted.

Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG
KylinMountain added a commit that referenced this pull request Jul 22, 2026
…ane (#197) (#199)

* feat(web): read a document's converted source text in the Documents pane (#197)

The Documents pane listed each ingested doc (name/type/hash) with no way to
read the converted full text ingestion produced under wiki/sources/.

Backend: new POST /api/v1/document/source resolves a doc hash to its source
text — short docs read <doc_name>.md; long docs concatenate the per-page
<doc_name>.json (page text joined by a thematic break). Hash is the identifier
(unique, avoids doc_name/stem collisions); resolution prefers the registry's
stored source_path then falls back to the wiki/sources/<doc_name>.{md,json}
convention, with a path-traversal guard. Read-only (sources are do-not-edit).

Frontend: document rows are now clickable and open a wide read-only slide-out
reader (MarkdownView) — ESC/overlay/close to dismiss, independent scroll,
content cached + memoized per hash, native find-in-page preserved (no
virtualization). Delete stays inline (stopPropagation). Closed drawer is inert.

Known limitation: images embedded in long-doc pages are not rendered inline yet.

* fix(web): address xhigh code-review findings for the document reader (#197)

Correctness / a11y:
- Rebuild the reader drawer on Radix Dialog (like KbSettingsSheet) instead of
  a hand-rolled overlay: proper modal focus trap, initial + return focus,
  Escape, and background inert (was: aria-modal with none of it) [#4]. This
  also removes the hand-rolled window keydown listener that re-subscribed every
  render [#7].
- Restructure each document row so the open-reader target is a real <button>
  and the delete control is a SIBLING, not nested. Keyboard-activating delete
  no longer bubbles into opening the reader, and the invalid nested-interactive
  markup is gone [#1, #5].
- Resolve a source file by the doc's own type (long → .json first, else .md),
  so two docs sharing a doc_name each resolve to their own file rather than
  whichever extension is tried first [#2].
- Guard source reads: skip non-dict page entries, reject non-list JSON, and
  return a controlled 500 on corrupt/unreadable sources instead of an
  unhandled exception [#3].
- Invalidate the per-hash content cache when the inventory changes, so a
  reopen after recompile refetches instead of serving stale text [#6].

Fetch/cache/memoized body moved to DocumentsPane so they survive the drawer's
unmount-on-close. #8 (frontmatter stripping) intentionally not applied: source
docs render verbatim (a user's own frontmatter is content, unlike wiki-page OKF
metadata). Adds tests for the collision and malformed-JSON paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant