2fe10727eb
User reported the search card "looks broken" when the selected hit is the
law (Wikisource source 5) — the right preview pane just duplicates the
chunk text already visible in the left list card. For PDF sources the
right pane shows the PDF page, but for text-only sources it had nothing
useful to add and fell back to a copy.
Fix:
- /kb/search hits gained chunk_index (shira-hermes b127caf), and
/kb/source/{id}/chunks gained an `around=<chunk_index>&ctx=<k>` window.
- Espo proxy plumbing: getActionChunks reads `around`/`ctx` query
params and forwards them; KnowledgeBaseService::sourceChunks accepts
optional $around + $ctx and appends them to the upstream URL.
- showSearchPreview for non-PDF hits now fetches the matched chunk plus
2 sections before and 2 after, renders them as stacked panels: the
matched section gets a yellow #fff3cd highlight, neighbors render as
muted context blocks. The panel header carries a prominent
"פתח ב-Wikisource" button so users can jump to the public source page.
After render the matched section auto-scrolls into view.
- Race protection via _previewToken: a click on a different hit while a
fetch is in flight cancels the stale render so the user always sees
the section that matches the currently-selected card.
PDF path unchanged.
Refs Task Master #7
96 lines
9.2 KiB
JSON
96 lines
9.2 KiB
JSON
{
|
||
"master": {
|
||
"tasks": [
|
||
{
|
||
"id": 1,
|
||
"title": "feat: search-mode split-view with PDF + page jump",
|
||
"description": "Render /kb/search results as a two-column split view: left column is the stack of ranked hit cards (kind, title, section, page label), right column is an iframe viewing the selected hit's PDF scrolled to page_number. Clicking any hit swaps the iframe. Text-only sources (law from Wikisource) fall back to a chunk/text panel with a Wikisource link so the right column never 404s.",
|
||
"status": "done",
|
||
"priority": "high",
|
||
"details": "Before this change renderSearchResults produced plain vertical text cards — users got the chunk body and had to open the Wikisource link (or track down the PDF manually) to verify context. With 5 of 5 PDFs now carrying accurate page_number (shira-hermes e534709 + 1ca1cc0), the search UI can finally deep-link to the right page. Mirrors the ask-mode split view (v0.1.7 uncommitted).",
|
||
"testStrategy": "Search 'תקנה 37' → first hit should be a regulation/circular → right pane loads the PDF at page ~N where the section appears. Click a lower-ranked law hit → right pane swaps to a Wikisource link view. Search 'הגדרות' → hits span multiple sources → each click swaps iframe source.",
|
||
"subtasks": [],
|
||
"dependencies": [],
|
||
"createdAt": "2026-04-24T15:47:00Z"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"title": "fix(kb/chunker): page_number propagation through split + packing (shira-hermes)",
|
||
"description": "Applied in shira-hermes commits e534709 + 1ca1cc0: (1) _split_oversized now re-derives page_number per piece from markers embedded in parent content + a virtual (offset 0, parent.page_number) anchor, (2) chunk_circular tracks absolute paragraph offsets in the original text so each packed sub-chunk reports its real starting page, (3) _as_dicts strips stray \\x00 bytes left behind when _split_oversized slices through a marker sentinel. Reference data: ספר הליקויים now 211 chunks × 210 pages (1-413) vs 209 × 1 before. Not work for this repo, but the search split-view in task #1 depends on it.",
|
||
"status": "done",
|
||
"priority": "high",
|
||
"details": "Lives in espocrm-extensions/shira-hermes. Logged here for traceability because task #1 can't demonstrate correct page jumps without it.",
|
||
"testStrategy": "Query DB: SELECT source_id, MIN/MAX(page_number), COUNT(DISTINCT page_number) FROM kb_chunk GROUP BY source_id — every PDF source should span multiple distinct pages.",
|
||
"subtasks": [],
|
||
"dependencies": [],
|
||
"createdAt": "2026-04-24T15:47:00Z"
|
||
},
|
||
{
|
||
"id": 3,
|
||
"title": "feat(kb/search): LLM query expansion so ranked-by-title docs don't crowd everything else out (shira-hermes)",
|
||
"description": "User reports searching 'מהי תקנה 37' returns only the תקנה 37 circular and the law — never ספר הליקויים, even though that's where the underlying medical content lives. Root cause is a single-shot retrieval where any document whose title contains the query terms wins by a huge margin. Fix: ask the LLM (via ai-gateway) for up to 3 alternative phrasings, retrieve candidates for the original + each variant in parallel, merge by chunk_id keeping best RRF score, then rerank the union against the ORIGINAL query. After fix: src 29 (ספר הליקויים) shows up with 2 hits in the same query.",
|
||
"status": "done",
|
||
"priority": "high",
|
||
"details": "Lives in espocrm-extensions/shira-hermes commit 1441a41. /kb/search now has expand=true by default, agent path (search_insurance_kb tool) keeps expand=false because the agent already does multi-query via tool calls.",
|
||
"testStrategy": "POST /kb/search {query:'מהי תקנה 37', top_k:8} should return hits from at least 2 distinct source_ids, including src 29 (ספר הליקויים) and src 26 (תקנה 37 חוזר).",
|
||
"subtasks": [],
|
||
"dependencies": [],
|
||
"createdAt": "2026-04-25T10:00:00Z"
|
||
},
|
||
{
|
||
"id": 7,
|
||
"title": "fix: search preview duplicates left card for text sources",
|
||
"description": "User report: searching the law (Wikisource source 5) shows the same chunk content in both the left list-card and the right preview pane. The preview adds zero value when the matched source has no PDF — both panes are visually identical (modulo the left's 14em truncation), which reads as a bug. Fixed by fetching the matched chunk plus K=2 surrounding sections from /kb/source/{id}/chunks?around=N&ctx=2 and rendering them stacked: matched section is highlighted with a yellow header (#fff3cd), neighbors render as muted context blocks above and below. Adds a prominent 'פתח ב-Wikisource' button in the panel header, scrolls the matched section into view on render. Race-safe via _previewToken so a quick second click doesn't render stale results.",
|
||
"status": "done",
|
||
"priority": "high",
|
||
"details": "shira-hermes b127caf added chunk_index to /kb/search hits + an `around`/`ctx` query param to /source/{id}/chunks. Espo controller passes them through. Client uses the new fields in showSearchPreview when the hit is a text source.",
|
||
"testStrategy": "Search 'מהי תקנה 36'; click the law-kind hit. Right pane: yellow-highlighted ס' 36 in the middle, ס' 35 above (muted), ס' 37 below (muted), Wikisource button in header. Click the תקנה 37 חוזר hit: right pane swaps to PDF iframe at the cited page (PDF path unchanged).",
|
||
"subtasks": [],
|
||
"dependencies": [],
|
||
"createdAt": "2026-04-25T12:30:00Z"
|
||
},
|
||
{
|
||
"id": 5,
|
||
"title": "feat(kb): drag-to-resize splitter (both ask + search)",
|
||
"description": "Replace the fixed Bootstrap col-md-5/7 split with a flex layout containing a 6px drag handle. mousedown on the handle starts the drag; while dragging an invisible full-screen overlay covers any iframe so the PDF.js viewer doesn't swallow mouse events. The chosen ratio (15-85%) persists to localStorage as kb-split-pct so the layout sticks across sessions. Both modes share the same _buildSplitShell helper so the look stays consistent.",
|
||
"status": "done",
|
||
"priority": "normal",
|
||
"details": "Default ratio = 42% left (matches the previous col-md-5 ≈ 41.66%). Applied to renderSearchResults, renderAskAnswer, and showSearchPreview (which now uses 100%-height containers via flex column).",
|
||
"testStrategy": "Open ask mode, drag the divider; verify PDF iframe doesn't lose mouse focus mid-drag; reload — divider stays at last position. Repeat in search mode.",
|
||
"subtasks": [],
|
||
"dependencies": [],
|
||
"createdAt": "2026-04-25T11:00:00Z"
|
||
},
|
||
{
|
||
"id": 6,
|
||
"title": "fix: search survives view switch (parity with ask in v0.1.9)",
|
||
"description": "Search mode had the same view-bound promise problem as ask did before v0.1.9: navigating to another EspoCRM screen and back blanked the results. Hoisted {query, kind, promise} to a module-level _activeSearch with the same {query, kind, hits, selectedIdx} sessionStorage replay we already built for ask. Selected hit index also persists so the right pane comes back to the same source/page the user had open.",
|
||
"status": "done",
|
||
"priority": "high",
|
||
"details": "Mirrors the v0.1.9 ask fix in _attachSearchHandlers + afterRender. Click handler updates _lastSearch.selectedIdx so a return-trip lands on the user's last-clicked hit, not always the top-ranked one.",
|
||
"testStrategy": "Search 'מהי תקנה 37'; click a result other than the first; navigate to Contacts; navigate back — same hit selected, same PDF page on the right.",
|
||
"subtasks": [],
|
||
"dependencies": [],
|
||
"createdAt": "2026-04-25T11:00:00Z"
|
||
},
|
||
{
|
||
"id": 4,
|
||
"title": "fix: ask survives view switch via module-level promise + sessionStorage",
|
||
"description": "User reports asking Shira a question and switching to a different EspoCRM view loses the in-flight request — coming back shows a blank screen as if nothing was asked. Cause: the Espo.Ajax promise was view-bound, so handlers fired against a detached DOM after re-mount. Fix: hoist {question, promise, startedAt} to a module-level _activeAsk; afterRender re-attaches handlers and resumes the progress UI with the original startedAt; completed answers persist to sessionStorage and replay on remount or a hard reload.",
|
||
"status": "done",
|
||
"priority": "high",
|
||
"details": "All client-side, files/client/custom/modules/knowledge-base/src/views/kb/index.js. State is intentionally session-scoped — kept in sessionStorage so the next browser session starts clean.",
|
||
"testStrategy": "Ask a question; while the spinner shows, click Contacts (or any other navbar item); wait until the request would have finished; click back to בסיס ידע — the answer (or active spinner with correct elapsed-time) should be there.",
|
||
"subtasks": [],
|
||
"dependencies": [],
|
||
"createdAt": "2026-04-25T10:00:00Z"
|
||
}
|
||
],
|
||
"metadata": {
|
||
"created": "2026-04-24T15:47:00Z",
|
||
"updated": "2026-04-25T10:30:00Z",
|
||
"description": "KnowledgeBase extension tasks"
|
||
}
|
||
}
|
||
}
|