Commit Graph

5 Commits

Author SHA1 Message Date
chaim e7b21919c2 feat: add 'caselaw' (פסיקה) kind alongside חוק/תקנות/חוזרים
Court rulings get their own kind so users can filter search results
to "פסיקה" specifically and upload case-law PDFs from the ניהול tab.
PHP validators in Controller + Service accept the new kind; the search
dropdown and upload kind dropdown gain a "פסיקה" option; kindHe in
index.js maps caselaw → "פסיקה" so jobs list, search results, and
browse view all label it consistently.

Backend: depends on shira-hermes commit 16eeeff (kind validators +
chunker fallback) and migration 003_caselaw_kind.sql (already applied
on dev — alters CHECK constraints on kb_source.kind and
kb_ingest_job.kind to include 'caselaw').

Refs Task Master #18

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 17:01:12 +00:00
chaim 6781ac4e37 feat: Phase 2 — document upload from KB UI
Adds a "ניהול" tab with multipart file upload, async job tracking, and
a recent-jobs list with live status polling. Browser POSTs to
/KnowledgeBase/action/upload (PHP proxy), which forwards as multipart
to shira-hermes /admin/kb/upload. shira-hermes returns a job_id
immediately and processes parse/chunk/embed in a background task; the
browser polls every 2s until status hits done|failed.

New EspoCRM endpoints:
  POST /KnowledgeBase/action/upload   (multipart, $_FILES['file'])
  GET  /KnowledgeBase/action/jobs     (list, filtered by topicId/status)
  GET  /KnowledgeBase/action/job?id   (single-job detail)

The X-User-Name header is forwarded so kb_ingest_job records who
uploaded each file. Cross-topic guard in switchTopic stops polling
when the user changes topics mid-upload (the job continues server-side).

Depends on shira-hermes commit 0cb89fb (admin upload endpoints +
migration 002).

Refs Task Master #13

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 16:46:42 +00:00
chaim ba75463661 feat(kb): topic picker + topic-scoped client (Phase 1, no manifest bump)
Wires the EspoCRM extension to the multi-topic backend introduced in
shira-hermes commit f03721e. The KB page header now shows a topic
<select> ('נושא:'); the user's selection persists in localStorage
('kb-topic') and is sent with every search/ask/sources call so cross-
domain bleed-over is impossible. Single seeded topic ('ביטוח לאומי')
means existing users see no functional change until a second topic is
added in Phase 4 (Task Master #15).

- Resources/routes.json: GET /KnowledgeBase/action/topics.
- Controllers/KnowledgeBase.php: actionTopics + topicId passthrough on
  search/sources/ask. Numeric coercion for the request payload.
- Services/KnowledgeBaseService.php: listTopics(); search/listSources/
  ask take an optional topicId and forward it as topic_id to upstream.
- EntryPoints/KnowledgeBaseAskStream.php: ?topicId=N becomes topic_id
  in the JSON body sent to /kb/ask/stream.
- res/templates/kb/index.tpl: topic <select> in the page header,
  with a kb-topic-name-suffix span that JS fills with the active name.
- src/views/kb/index.js: module-level _topics cache + LS_TOPIC. setup
  reads localStorage; afterRender gates the picker fill + sources fetch
  on topics being loaded so a stale id from a deleted topic doesn't
  fire a 400-ing /sources call. switchTopic clears _activeAsk/Search +
  _lastAsk/Search + sessionStorage entries + this._sources, then
  reRenders. Cross-topic guard in afterRender drops cached state whose
  topicId !== this.topicId. _activeAsk / _lastAsk / _activeSearch /
  _lastSearch all carry topicId. EventSource URL gains &topicId.

Refs Task Master #12.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 14:15:36 +00:00
chaim e80ccb8bdf fix(kb): RTL-correct pane order + new-result button + 30-min auto-clear
Three issues from the v0.2.0 user test:

1. Sides flipped relative to expectation
   In our Hebrew/RTL CRM the user reads primary content (the answer or
   the hit list) on the visual right and the supporting reference
   (the PDF) on the visual left — that's how Hebrew layouts stage
   "main + sidebar". v0.1.10's _buildSplitShell forced direction:ltr on
   the splitter container (correct, for mouseX math) but laid the
   children in the order [primary, handle, reference], which under LTR
   put primary on the LEFT and PDF on the RIGHT. Fixed by renaming the
   helper params to {primaryHtml, referenceHtml} and ordering the
   children as [reference, handle, primary] — visual LEFT is now the
   PDF, visual RIGHT is the answer/list. Default split moved from 42%
   to 58% so the reference pane (now on the left) keeps the same
   absolute width the PDF column had under v0.1.9's bootstrap rows.

2. No way to start a new query
   afterRender replays _lastSearch / _lastAsk on every remount, which
   means the prior result hangs around forever. Added a "חיפוש חדש" /
   "שאלה חדשה" button next to the submit button. clearResults() cancels
   any in-flight request (closes the EventSource for ask, drops
   _activeSearch reference for search), removes the cached entry from
   sessionStorage, empties the results pane, and refocuses the input.

3. Stale results from another session
   Cached results now auto-expire after 30 minutes — _loadJson checks
   completedAt against STALE_AFTER_MS and silently drops anything
   older. So coming back tomorrow the KB tab opens clean instead of
   showing yesterday's answer to whatever you asked then.

Refs Task Master #4, #6
2026-04-25 13:16:30 +00:00
chaim 8829a2e93a feat: KnowledgeBase extension v0.1.6 — inline PDF viewer in browse tab
KnowledgeBase extension for EspoCRM: UI on top of the shira-hermes KB of
Israeli National Insurance law, regulations, and circulars.

Three modes:
- חיפוש — Hybrid (pgvector + tsvector) + Voyage rerank-2.5, returns ranked
  chunks with heading_path and citations.
- שאל את שירה — Full agent loop; Shira picks up search_insurance_kb as
  needed and returns a summary with citations.
- עיון — Browse all active sources. Click a source:
  - PDF source (ספר הליקויים, ספר המבחנים, circulars): renders the
    original PDF inline via an iframe proxied through the
    KnowledgeBasePdf EntryPoint, so the layout/columns/tables are
    preserved and Ctrl+F works natively.
  - TXT source (חוק הביטוח הלאומי scraped from Wikisource): falls back
    to the hierarchical chunk list with RTL styling.

Architecture:
- Controller: KnowledgeBase.php — thin proxy to shira-hermes /kb/*.
- Service: KnowledgeBaseService.php — shared curl plumbing; derives the
  shira-hermes base URL from the SmartAssistant integration record so
  there is no second admin config.
- EntryPoint: KnowledgeBasePdf.php — streams the PDF inline, wraps the
  body in a php://temp stream for setBody, applies a locked-down CSP.
- JS: views/kb/index.js branches on source.original_path; modes wired
  through the SmartAssistant fa_IR i18n convention.

Auth model:
- Browser → EspoCRM: session cookie / X-Api-Key (EspoCRM's existing auth).
- EspoCRM → shira-hermes: X-Api-Key from the SmartAssistant integration
  (never exposed to the browser).
- Portal users are blocked at both the Controller and the EntryPoint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:57:23 +00:00