GenericTemplateGenerator and FreeDocumentGenerator now, when CaseFilesCore is installed (soft-detected), set the generated Document's folderId to the case "מסמכים" folder via CaseFolderService so it shows in the CaseDocs panel. Existing Case link + NetworkStorage upload unchanged. Verified on dev (P7_OK): php -l clean on both generators; relate/find junction consistency confirmed; folder placement works. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.8 KiB
SmartAssistant — Architecture (developer reference)
Internal developer doc. Not shipped to clients. Customer overview:
README.md. Security/dead-code findings:_AUDIT/SmartAssistant/findings.md.
Module: SmartAssistant · Client module: smart-assistant · Load order: 37 · Requires: EspoCRM ≥ 8.0.0, PHP ≥ 8.1
What it is
A floating AI legal assistant. A chat widget (case mode / office mode) sends the user message plus rich context (case data, case memory, behavioral rules, prompt sections, learned skills, user profile) to the shira-hermes FastAPI backend via a webhook; shira returns response text + a list of tools, which ActionExecutor runs against the CRM (task/call/meeting CRUD, status changes, document + memory ops, rule saving), optionally looping tool results back to shira (agentic loop, max 3). Also computes office-wide alerts. Owns 6 entities (AssistantPrompt, AssistantRule, AssistantSkill, CaseMemory, UserProfile, AssistantConversation) and extends Note with 3 timeline note types.
File-by-file
Lifecycle
| File | Purpose |
|---|---|
scripts/AfterInstall.php |
Idempotently seeds 7 default AssistantPrompt sections (skipAll; admin edits win). No uninstall script (seeded entities persist). |
Controllers
| File | Purpose |
|---|---|
Controllers/SmartAssistant.php |
~30 actions: chat, execute, executeTool, alerts, summary, history, conversations, caseMemory, saveMemory, document read/analyze/upload/generate/rename/list/browse/write/move. (S1–S6 — ACL fixed 2026-06-20: assertCaseAccess() on chat/caseMemory/saveMemory/history; document-read endpoints require caseId + ACL + isPathWithinCase() containment.) |
Controllers/{AssistantRule,AssistantPrompt,AssistantSkill,CaseMemory,UserProfile}.php |
Thin Record CRUD. AssistantRule has no owner field — S5. |
Services
| File | Purpose |
|---|---|
SmartAssistantService.php |
Orchestrator: webhook call, agentic loop, conversation persistence, stream notes (SmartRequest/Response/Action), office drill-down. (fixed 2026-06-20: detectDrillDown ACL-filters matched cases (S6); dead static $conversations removed (D1).) Forwards espocrmApiKey — S9 still open. |
ConversationRepository.php |
File-based conversation JSON under data/conversations/. |
ActionExecutor.php |
Executes all shira tools. (ACL fixed 2026-06-20: resolves the acting user in execute(); central CASE_TOOL_ACCESS record-ACL gate for case-bound tools (S1); assertEntityAccess(...,'delete') on every delete tool (S4); save_rule admin-only (S5); plugin tools with a caseId require case edit — also closes LegalAssistance S1.) |
CaseContextBuilder.php / OfficeContextBuilder.php |
Build case / office context dicts. Case context IDOR S3. |
CaseMemoryContextProvider.php, AssistantRuleContextProvider.php, AssistantPromptContextProvider.php, AssistantSkillContextProvider.php, UserProfileContextProvider.php |
Load memories/rules/prompts/skills/profile into the prompt. |
CaseMemoryService.php |
CaseMemory CRUD (category/importance/pinned). IDOR S3. |
DocumentAnalyzer.php |
Text extraction/analysis; uses NetworkStorageIntegration NetworkDocumentService. (fixed 2026-06-20: added isPathWithinCase() containment helper the controller calls before any read — S2.) |
CaseFolderManager.php |
Write/rename/move constrained to the case folder (resolveSafePath/sanitizeRelSegments — safe). |
GenericTemplateGenerator.php / FreeDocumentGenerator.php |
Template-based / free-form document generation. |
AlertCalculator.php |
Office alerts (inactive cases, overdue tasks, hearings without prep, unassigned new cases, deadlines). |
Hooks
| File | Trigger |
|---|---|
Hooks/Case/CaseFieldChangeMemory.php |
afterSave — auto-seed CaseMemory on status/judge/court/next-hearing change. |
Hooks/Meeting/HearingScheduledMemory.php |
afterSave — memory when a hearing Meeting is created. |
Resources / client
| Path | Purpose |
|---|---|
entityDefs/{AssistantPrompt,AssistantRule,AssistantSkill,CaseMemory,UserProfile,Note,Case}.json |
6 entities + Note.type extension + Case.caseMemories link. AssistantRule/UserProfile ACL — S5/S7. |
integrations/SmartAssistant.json |
webhookUrl, apiKey, espocrmApiKey, thresholds, agenticLoop. Keys are varchar — S8. |
routes.json (12), clientDefs/*, scopes/*, layouts/*, dashlets/SmartAssistant.json, i18n/{en_US,fa_IR}/*, data/default-prompts.json |
Routes, UI, ACL, dashlet, translations, seed prompts. |
client/.../src/views/floating-chat.js |
Main chat widget (history, memory browser, mode badge). escape-then-markdown — XSS-safe. |
client/.../src/views/dashlets/smart-assistant.js |
Alerts card. Unescaped caseId href S10. |
client/.../src/views/{case/modals/add-memory,fields/prompt-editor,site/navbar}.js, stream/notes/smart-{request,response,action}.js |
Memory modal, prompt editor, navbar inject, timeline note item views. |
Dependencies
- NetworkStorageIntegration (hard): DocumentAnalyzer document ops.
- shira-hermes (external, hard): webhook (Integration record
SmartAssistant). No chat without it. - KnowledgeBase → SmartAssistant (REVERSE, critical): KnowledgeBase reuses this extension's Integration record. Do not uninstall SmartAssistant while KnowledgeBase is installed.
- LegalCrm (soft): Note.type extension.
Post-install gotchas
- Configure the
SmartAssistantIntegration (webhookUrl + apiKey + espocrmApiKey) — scope the espocrmApiKey to a minimal API user (S9). - Known deploy gotchas: a backup-in-modules folder breaks hooks; AfterInstall needs
skipAll; new role entries need api-key role grant. - shira-hermes
/opt/datamust be a named volume (else skills/profiles/cases wiped on redeploy).