@devicai/ui 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +58 -0
  2. package/dist/cjs/api/types.js.map +1 -1
  3. package/dist/cjs/components/ChatDrawer/ChatDrawer.js +8 -3
  4. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
  5. package/dist/cjs/components/ChatDrawer/ChatMessages.js +41 -4
  6. package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -1
  7. package/dist/cjs/components/ChatDrawer/CompactionWidget.js +72 -0
  8. package/dist/cjs/components/ChatDrawer/CompactionWidget.js.map +1 -0
  9. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js +41 -4
  10. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  11. package/dist/cjs/hooks/useDevicChat.js +32 -1
  12. package/dist/cjs/hooks/useDevicChat.js.map +1 -1
  13. package/dist/cjs/index.js +3 -0
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/styles.css +1 -1
  16. package/dist/esm/api/types.d.ts +83 -0
  17. package/dist/esm/api/types.js.map +1 -1
  18. package/dist/esm/components/ChatDrawer/ChatDrawer.js +9 -4
  19. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
  20. package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +40 -1
  21. package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +1 -1
  22. package/dist/esm/components/ChatDrawer/ChatMessages.js +41 -4
  23. package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -1
  24. package/dist/esm/components/ChatDrawer/CompactionWidget.d.ts +47 -0
  25. package/dist/esm/components/ChatDrawer/CompactionWidget.js +70 -0
  26. package/dist/esm/components/ChatDrawer/CompactionWidget.js.map +1 -0
  27. package/dist/esm/components/ChatDrawer/index.d.ts +2 -0
  28. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.d.ts +39 -2
  29. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js +41 -5
  30. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  31. package/dist/esm/components/CoreMemoryModal/index.d.ts +2 -2
  32. package/dist/esm/hooks/useDevicChat.d.ts +13 -1
  33. package/dist/esm/hooks/useDevicChat.js +32 -1
  34. package/dist/esm/hooks/useDevicChat.js.map +1 -1
  35. package/dist/esm/index.d.ts +5 -5
  36. package/dist/esm/index.js +2 -1
  37. package/dist/esm/index.js.map +1 -1
  38. package/dist/esm/styles.css +1 -1
  39. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CoreMemoryModal.js","sources":["../../../../../src/components/CoreMemoryModal/CoreMemoryModal.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type JSX,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { DevicApiClient } from \"../../api/client\";\nimport type { CoreMemoryEntry, CoreMemoryLimits } from \"../../api/types\";\nimport { useOptionalDevicContext } from \"../../provider\";\nimport { themeVars, type DevicTheme } from \"../theme\";\nimport \"./CoreMemoryModal.css\";\n\n/** Canonical sections of the core tier, in display order. */\nconst SECTIONS = [\"persona\", \"instructions\", \"decisions\", \"profile\"] as const;\n\nexport interface CoreMemoryModalProps {\n /** Whether the modal is visible. */\n isOpen: boolean;\n onClose: () => void;\n /** Assistant whose memory bucket is shown. */\n assistantId: string;\n /** Tenant of the end user (falls back to the provider's tenantId). */\n tenantId?: string;\n /** Subtenant of the end user (falls back to the provider's subtenantId). */\n subtenantId?: string;\n /** API key override (falls back to the provider's). */\n apiKey?: string;\n /** Base URL override (falls back to the provider's). */\n baseUrl?: string;\n /**\n * Let the user add, edit and remove entries. Set false for a read-only\n * view of what the assistant remembers.\n * @default true\n */\n editable?: boolean;\n /** Modal title. @default \"Assistant memory\" */\n title?: string;\n /**\n * Colours and font. Same names as the drawer's style options, and the drawer\n * passes its own down — a dialog opening in the default light palette over a\n * themed application is the one thing this must not do.\n */\n theme?: DevicTheme;\n}\n\nfunction BrainIcon(): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M9.5 2a2.5 2.5 0 0 0-2.45 2A3.5 3.5 0 0 0 4.6 8.6 3.5 3.5 0 0 0 3 11.5c0 1.1.5 2.08 1.29 2.73A3.5 3.5 0 0 0 7 20a3 3 0 0 0 5-2.24V4.5A2.5 2.5 0 0 0 9.5 2Z\" />\n <path d=\"M14.5 2a2.5 2.5 0 0 1 2.45 2 3.5 3.5 0 0 1 2.45 4.6A3.5 3.5 0 0 1 21 11.5a3.49 3.49 0 0 1-1.29 2.73A3.5 3.5 0 0 1 17 20a3 3 0 0 1-5-2.24V4.5A2.5 2.5 0 0 1 14.5 2Z\" />\n </svg>\n );\n}\n\nfunction PinIcon(): JSX.Element {\n return (\n <svg\n width=\"11\"\n height=\"11\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n stroke=\"none\"\n aria-hidden=\"true\"\n >\n <path d=\"M16 3a1 1 0 0 1 .97 1.243l-1.2 4.8 3.937 3.938A1 1 0 0 1 19 14.688V15a1 1 0 0 1-1 1h-5v6l-1 1-1-1v-6H6a1 1 0 0 1-1-1v-.312a1 1 0 0 1 .293-.707L9.23 9.043l-1.2-4.8A1 1 0 0 1 9 3h7Z\" />\n </svg>\n );\n}\n\n/**\n * Modal showing — and, when `editable`, managing — the core memory of an\n * assistant for a tenant/subtenant combination: the standing entries\n * (persona, instructions, decisions, profile) injected into every prompt of\n * the bucket the assistant resolves there. Lets the end user see and control\n * what the assistant permanently remembers about them.\n *\n * Backed by the public memory API (`/api/v1/memory/assistants/:id/core`);\n * the API key needs that endpoint allowed.\n */\nexport function CoreMemoryModal({\n isOpen,\n onClose,\n assistantId,\n tenantId,\n subtenantId,\n apiKey,\n baseUrl,\n editable = true,\n title = \"Assistant memory\",\n theme,\n}: CoreMemoryModalProps): JSX.Element | null {\n const context = useOptionalDevicContext();\n const resolvedBaseUrl = baseUrl || context?.baseUrl || \"https://api.devic.ai\";\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedTenantSession = context?.getTenantSession;\n const onSessionExpired = context?.onSessionExpired;\n\n const client = useMemo(\n () =>\n resolvedApiKey || resolvedTenantSession\n ? new DevicApiClient({\n apiKey: resolvedApiKey,\n baseUrl: resolvedBaseUrl,\n getTenantSession: resolvedTenantSession,\n onSessionExpired,\n })\n : null,\n [resolvedApiKey, resolvedTenantSession, resolvedBaseUrl]\n );\n\n const [loading, setLoading] = useState(false);\n const [enabled, setEnabled] = useState(true);\n const [entries, setEntries] = useState<CoreMemoryEntry[]>([]);\n const [limits, setLimits] = useState<CoreMemoryLimits | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [saving, setSaving] = useState(false);\n\n // Inline composer / editor state\n const [composerOpen, setComposerOpen] = useState(false);\n const [composerSection, setComposerSection] = useState<string>(\"profile\");\n const [composerText, setComposerText] = useState(\"\");\n const [editingId, setEditingId] = useState<number | null>(null);\n const [editingText, setEditingText] = useState(\"\");\n\n const scopeOptions = useMemo(\n () => ({\n tenantId: resolvedTenantId || undefined,\n subtenantId: resolvedSubtenantId || undefined,\n }),\n [resolvedTenantId, resolvedSubtenantId]\n );\n\n const refresh = useCallback(async () => {\n if (!client) {\n setError(\"API key not configured\");\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const list = await client.getCoreMemory(assistantId, scopeOptions);\n setEnabled(list.enabled);\n setEntries(list.entries);\n setLimits(list.limits ?? null);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setLoading(false);\n }\n }, [client, assistantId, scopeOptions]);\n\n // Fetch on every open (memory may have changed since the last look).\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (isOpen && !wasOpenRef.current) {\n setComposerOpen(false);\n setComposerText(\"\");\n setEditingId(null);\n void refresh();\n }\n wasOpenRef.current = isOpen;\n }, [isOpen, refresh]);\n\n // Escape closes\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [isOpen, onClose]);\n\n const runWrite = useCallback(\n async (write: () => Promise<unknown>) => {\n setSaving(true);\n setError(null);\n try {\n await write();\n await refresh();\n return true;\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n return false;\n } finally {\n setSaving(false);\n }\n },\n [refresh]\n );\n\n const handleAdd = async () => {\n if (!client || !composerText.trim()) return;\n const ok = await runWrite(() =>\n client.addCoreMemoryEntry(\n assistantId,\n { content: composerText.trim(), section: composerSection },\n scopeOptions\n )\n );\n if (ok) {\n setComposerOpen(false);\n setComposerText(\"\");\n }\n };\n\n const handleSaveEdit = async (entry: CoreMemoryEntry) => {\n if (!client || !editingText.trim()) return;\n const ok = await runWrite(() =>\n client.updateCoreMemoryEntry(\n assistantId,\n entry.id,\n { content: editingText.trim() },\n scopeOptions\n )\n );\n if (ok) setEditingId(null);\n };\n\n const handleRemove = async (entry: CoreMemoryEntry) => {\n if (!client) return;\n await runWrite(() =>\n client.deleteCoreMemoryEntry(assistantId, entry.id, scopeOptions)\n );\n };\n\n if (!isOpen) return null;\n\n // Group entries by section, canonical sections first.\n const sections: Array<{ name: string; entries: CoreMemoryEntry[] }> = [];\n const bySection = new Map<string, CoreMemoryEntry[]>();\n for (const entry of entries) {\n const list = bySection.get(entry.section);\n if (list) list.push(entry);\n else bySection.set(entry.section, [entry]);\n }\n for (const name of SECTIONS) {\n const list = bySection.get(name);\n if (list) {\n sections.push({ name, entries: list });\n bySection.delete(name);\n }\n }\n for (const [name, list] of bySection) sections.push({ name, entries: list });\n\n return createPortal(\n // The variables go on the overlay: a portal inherits nothing from the\n // drawer that opened it, so without this the dialog ignores the theme.\n <div\n className=\"devic-cm-overlay\"\n style={themeVars(theme)}\n onClick={onClose}\n >\n <div\n className=\"devic-cm-modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"devic-cm-header\">\n <h3 className=\"devic-cm-title\">\n <BrainIcon />\n {title}\n </h3>\n <button\n className=\"devic-cm-close\"\n onClick={onClose}\n type=\"button\"\n aria-label=\"Close\"\n >\n ×\n </button>\n </div>\n\n <div className=\"devic-cm-body\">\n {error && <div className=\"devic-cm-error\">{error}</div>}\n\n {loading ? (\n <div className=\"devic-cm-loading\">Loading memory…</div>\n ) : !enabled ? (\n <div className=\"devic-cm-empty\">\n Memory is not enabled for this assistant.\n </div>\n ) : entries.length === 0 && !composerOpen ? (\n <div className=\"devic-cm-empty\">\n Nothing remembered yet. What the assistant learns and is told to\n keep will appear here.\n </div>\n ) : (\n sections.map((section) => (\n <div key={section.name} className=\"devic-cm-section\">\n <div className=\"devic-cm-section-title\">{section.name}</div>\n {section.entries.map((entry) => (\n <div key={entry.id} className=\"devic-cm-entry\">\n {editingId === entry.id ? (\n <div className=\"devic-cm-editor\">\n <textarea\n className=\"devic-cm-textarea\"\n value={editingText}\n maxLength={limits?.maxEntryChars || undefined}\n onChange={(e) => setEditingText(e.target.value)}\n disabled={saving}\n autoFocus\n />\n <div className=\"devic-cm-editor-actions\">\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-primary\"\n onClick={() => handleSaveEdit(entry)}\n disabled={saving || !editingText.trim()}\n >\n Save\n </button>\n <button\n type=\"button\"\n className=\"devic-cm-btn\"\n onClick={() => setEditingId(null)}\n disabled={saving}\n >\n Cancel\n </button>\n </div>\n </div>\n ) : (\n <>\n <div className=\"devic-cm-entry-content\">\n {entry.pinned && (\n <span\n className=\"devic-cm-pin\"\n title=\"Pinned: always kept, never changed by the assistant\"\n >\n <PinIcon />\n </span>\n )}\n <span>{entry.content}</span>\n </div>\n {editable && (\n <div className=\"devic-cm-entry-actions\">\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-small\"\n onClick={() => {\n setEditingId(entry.id);\n setEditingText(entry.content);\n }}\n disabled={saving}\n >\n Edit\n </button>\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-small devic-cm-btn-danger\"\n onClick={() => handleRemove(entry)}\n disabled={saving}\n >\n Remove\n </button>\n </div>\n )}\n </>\n )}\n </div>\n ))}\n </div>\n ))\n )}\n\n {editable && enabled && !loading && (\n <div className=\"devic-cm-composer\">\n {composerOpen ? (\n <>\n <div className=\"devic-cm-composer-row\">\n <select\n className=\"devic-cm-select\"\n value={composerSection}\n onChange={(e) => setComposerSection(e.target.value)}\n disabled={saving}\n >\n {SECTIONS.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </div>\n <textarea\n className=\"devic-cm-textarea\"\n placeholder=\"Something the assistant should always remember…\"\n value={composerText}\n maxLength={limits?.maxEntryChars || undefined}\n onChange={(e) => setComposerText(e.target.value)}\n disabled={saving}\n autoFocus\n />\n <div className=\"devic-cm-editor-actions\">\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-primary\"\n onClick={handleAdd}\n disabled={saving || !composerText.trim()}\n >\n Add\n </button>\n <button\n type=\"button\"\n className=\"devic-cm-btn\"\n onClick={() => {\n setComposerOpen(false);\n setComposerText(\"\");\n }}\n disabled={saving}\n >\n Cancel\n </button>\n </div>\n </>\n ) : (\n <button\n type=\"button\"\n className=\"devic-cm-btn\"\n onClick={() => setComposerOpen(true)}\n disabled={saving}\n >\n + Add memory\n </button>\n )}\n </div>\n )}\n </div>\n\n {limits && enabled && (\n <div className=\"devic-cm-footer\">\n {entries.length}/{limits.maxEntries} entries · up to{\" \"}\n {limits.maxEntryChars} characters each\n </div>\n )}\n </div>\n </div>,\n document.body\n );\n}\n\nexport default CoreMemoryModal;\n"],"names":["_jsxs","_jsx","theme","useOptionalDevicContext","client","useMemo","DevicApiClient","useState","useCallback","useRef","useEffect","createPortal","themeVars","_Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"CoreMemoryModal.js","sources":["../../../../../src/components/CoreMemoryModal/CoreMemoryModal.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type JSX,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { DevicApiClient } from \"../../api/client\";\nimport type { CoreMemoryEntry, CoreMemoryLimits } from \"../../api/types\";\nimport { useOptionalDevicContext } from \"../../provider\";\nimport { themeVars, type DevicTheme } from \"../theme\";\nimport \"./CoreMemoryModal.css\";\n\n/** Canonical sections of the core tier, in display order. */\nconst SECTIONS = [\"persona\", \"instructions\", \"decisions\", \"profile\"] as const;\n\n/**\n * Every piece of text the modal shows, so a host can render it in its own\n * language. Any subset can be given; the rest keeps the English default.\n */\nexport interface CoreMemoryLabels {\n /** Modal title; the drawer also uses it for its brain button tooltip. */\n title: string;\n /** Accessible name of the close button. */\n close: string;\n loading: string;\n /** Shown when the assistant has no core memory tier enabled. */\n disabled: string;\n /** Shown when the bucket holds no entries yet. */\n empty: string;\n /** Tooltip of the pin mark. */\n pinned: string;\n edit: string;\n remove: string;\n save: string;\n cancel: string;\n /** Confirms the composer. */\n add: string;\n /** Opens the composer. */\n addMemory: string;\n /** Composer placeholder. */\n placeholder: string;\n /** Footer; `{count}`, `{max}` and `{chars}` are replaced. */\n footer: string;\n /** Display names of the sections, by section key. */\n sections: Record<string, string>;\n}\n\nexport const DEFAULT_CORE_MEMORY_LABELS: CoreMemoryLabels = {\n title: \"Assistant memory\",\n close: \"Close\",\n loading: \"Loading memory…\",\n disabled: \"Memory is not enabled for this assistant.\",\n empty:\n \"Nothing remembered yet. What the assistant learns and is told to keep will appear here.\",\n pinned: \"Pinned: always kept, never changed by the assistant\",\n edit: \"Edit\",\n remove: \"Remove\",\n save: \"Save\",\n cancel: \"Cancel\",\n add: \"Add\",\n addMemory: \"+ Add memory\",\n placeholder: \"Something the assistant should always remember…\",\n footer: \"{count}/{max} entries · up to {chars} characters each\",\n sections: {\n persona: \"persona\",\n instructions: \"instructions\",\n decisions: \"decisions\",\n profile: \"profile\",\n },\n};\n\nconst fillTemplate = (template: string, values: Record<string, string>) =>\n template.replace(/\\{(\\w+)\\}/g, (_, key: string) => values[key] ?? \"\");\n\nexport interface CoreMemoryModalProps {\n /** Whether the modal is visible. */\n isOpen: boolean;\n onClose: () => void;\n /** Assistant whose memory bucket is shown. */\n assistantId: string;\n /** Tenant of the end user (falls back to the provider's tenantId). */\n tenantId?: string;\n /** Subtenant of the end user (falls back to the provider's subtenantId). */\n subtenantId?: string;\n /** API key override (falls back to the provider's). */\n apiKey?: string;\n /** Base URL override (falls back to the provider's). */\n baseUrl?: string;\n /**\n * Let the user add, edit and remove entries. Set false for a read-only\n * view of what the assistant remembers.\n * @default true\n */\n editable?: boolean;\n /**\n * Modal title. @default \"Assistant memory\"\n * @deprecated Prefer `labels.title`; kept so existing hosts keep working.\n */\n title?: string;\n /** Texts of the modal, for a host that renders it in its own language. */\n labels?: Partial<CoreMemoryLabels>;\n /**\n * Colours and font. Same names as the drawer's style options, and the drawer\n * passes its own down — a dialog opening in the default light palette over a\n * themed application is the one thing this must not do.\n */\n theme?: DevicTheme;\n}\n\nfunction BrainIcon(): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M9.5 2a2.5 2.5 0 0 0-2.45 2A3.5 3.5 0 0 0 4.6 8.6 3.5 3.5 0 0 0 3 11.5c0 1.1.5 2.08 1.29 2.73A3.5 3.5 0 0 0 7 20a3 3 0 0 0 5-2.24V4.5A2.5 2.5 0 0 0 9.5 2Z\" />\n <path d=\"M14.5 2a2.5 2.5 0 0 1 2.45 2 3.5 3.5 0 0 1 2.45 4.6A3.5 3.5 0 0 1 21 11.5a3.49 3.49 0 0 1-1.29 2.73A3.5 3.5 0 0 1 17 20a3 3 0 0 1-5-2.24V4.5A2.5 2.5 0 0 1 14.5 2Z\" />\n </svg>\n );\n}\n\nfunction PinIcon(): JSX.Element {\n return (\n <svg\n width=\"11\"\n height=\"11\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n stroke=\"none\"\n aria-hidden=\"true\"\n >\n <path d=\"M16 3a1 1 0 0 1 .97 1.243l-1.2 4.8 3.937 3.938A1 1 0 0 1 19 14.688V15a1 1 0 0 1-1 1h-5v6l-1 1-1-1v-6H6a1 1 0 0 1-1-1v-.312a1 1 0 0 1 .293-.707L9.23 9.043l-1.2-4.8A1 1 0 0 1 9 3h7Z\" />\n </svg>\n );\n}\n\n/**\n * Modal showing — and, when `editable`, managing — the core memory of an\n * assistant for a tenant/subtenant combination: the standing entries\n * (persona, instructions, decisions, profile) injected into every prompt of\n * the bucket the assistant resolves there. Lets the end user see and control\n * what the assistant permanently remembers about them.\n *\n * Backed by the public memory API (`/api/v1/memory/assistants/:id/core`);\n * the API key needs that endpoint allowed.\n */\nexport function CoreMemoryModal({\n isOpen,\n onClose,\n assistantId,\n tenantId,\n subtenantId,\n apiKey,\n baseUrl,\n editable = true,\n title,\n labels,\n theme,\n}: CoreMemoryModalProps): JSX.Element | null {\n const l = useMemo<CoreMemoryLabels>(\n () => ({\n ...DEFAULT_CORE_MEMORY_LABELS,\n ...labels,\n title: labels?.title ?? title ?? DEFAULT_CORE_MEMORY_LABELS.title,\n sections: {\n ...DEFAULT_CORE_MEMORY_LABELS.sections,\n ...labels?.sections,\n },\n }),\n [labels, title]\n );\n const context = useOptionalDevicContext();\n const resolvedBaseUrl = baseUrl || context?.baseUrl || \"https://api.devic.ai\";\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedSubtenantId = subtenantId || context?.subtenantId;\n\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedTenantSession = context?.getTenantSession;\n const onSessionExpired = context?.onSessionExpired;\n\n const client = useMemo(\n () =>\n resolvedApiKey || resolvedTenantSession\n ? new DevicApiClient({\n apiKey: resolvedApiKey,\n baseUrl: resolvedBaseUrl,\n getTenantSession: resolvedTenantSession,\n onSessionExpired,\n })\n : null,\n [resolvedApiKey, resolvedTenantSession, resolvedBaseUrl]\n );\n\n const [loading, setLoading] = useState(false);\n const [enabled, setEnabled] = useState(true);\n const [entries, setEntries] = useState<CoreMemoryEntry[]>([]);\n const [limits, setLimits] = useState<CoreMemoryLimits | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [saving, setSaving] = useState(false);\n\n // Inline composer / editor state\n const [composerOpen, setComposerOpen] = useState(false);\n const [composerSection, setComposerSection] = useState<string>(\"profile\");\n const [composerText, setComposerText] = useState(\"\");\n const [editingId, setEditingId] = useState<number | null>(null);\n const [editingText, setEditingText] = useState(\"\");\n\n const scopeOptions = useMemo(\n () => ({\n tenantId: resolvedTenantId || undefined,\n subtenantId: resolvedSubtenantId || undefined,\n }),\n [resolvedTenantId, resolvedSubtenantId]\n );\n\n const refresh = useCallback(async () => {\n if (!client) {\n setError(\"API key not configured\");\n return;\n }\n setLoading(true);\n setError(null);\n try {\n const list = await client.getCoreMemory(assistantId, scopeOptions);\n setEnabled(list.enabled);\n setEntries(list.entries);\n setLimits(list.limits ?? null);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setLoading(false);\n }\n }, [client, assistantId, scopeOptions]);\n\n // Fetch on every open (memory may have changed since the last look).\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (isOpen && !wasOpenRef.current) {\n setComposerOpen(false);\n setComposerText(\"\");\n setEditingId(null);\n void refresh();\n }\n wasOpenRef.current = isOpen;\n }, [isOpen, refresh]);\n\n // Escape closes\n useEffect(() => {\n if (!isOpen) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [isOpen, onClose]);\n\n const runWrite = useCallback(\n async (write: () => Promise<unknown>) => {\n setSaving(true);\n setError(null);\n try {\n await write();\n await refresh();\n return true;\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n return false;\n } finally {\n setSaving(false);\n }\n },\n [refresh]\n );\n\n const handleAdd = async () => {\n if (!client || !composerText.trim()) return;\n const ok = await runWrite(() =>\n client.addCoreMemoryEntry(\n assistantId,\n { content: composerText.trim(), section: composerSection },\n scopeOptions\n )\n );\n if (ok) {\n setComposerOpen(false);\n setComposerText(\"\");\n }\n };\n\n const handleSaveEdit = async (entry: CoreMemoryEntry) => {\n if (!client || !editingText.trim()) return;\n const ok = await runWrite(() =>\n client.updateCoreMemoryEntry(\n assistantId,\n entry.id,\n { content: editingText.trim() },\n scopeOptions\n )\n );\n if (ok) setEditingId(null);\n };\n\n const handleRemove = async (entry: CoreMemoryEntry) => {\n if (!client) return;\n await runWrite(() =>\n client.deleteCoreMemoryEntry(assistantId, entry.id, scopeOptions)\n );\n };\n\n if (!isOpen) return null;\n\n // Group entries by section, canonical sections first.\n const sections: Array<{ name: string; entries: CoreMemoryEntry[] }> = [];\n const bySection = new Map<string, CoreMemoryEntry[]>();\n for (const entry of entries) {\n const list = bySection.get(entry.section);\n if (list) list.push(entry);\n else bySection.set(entry.section, [entry]);\n }\n for (const name of SECTIONS) {\n const list = bySection.get(name);\n if (list) {\n sections.push({ name, entries: list });\n bySection.delete(name);\n }\n }\n for (const [name, list] of bySection) sections.push({ name, entries: list });\n\n return createPortal(\n // The variables go on the overlay: a portal inherits nothing from the\n // drawer that opened it, so without this the dialog ignores the theme.\n <div\n className=\"devic-cm-overlay\"\n style={themeVars(theme)}\n onClick={onClose}\n >\n <div\n className=\"devic-cm-modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={l.title}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"devic-cm-header\">\n <h3 className=\"devic-cm-title\">\n <BrainIcon />\n {l.title}\n </h3>\n <button\n className=\"devic-cm-close\"\n onClick={onClose}\n type=\"button\"\n aria-label={l.close}\n >\n ×\n </button>\n </div>\n\n <div className=\"devic-cm-body\">\n {error && <div className=\"devic-cm-error\">{error}</div>}\n\n {loading ? (\n <div className=\"devic-cm-loading\">{l.loading}</div>\n ) : !enabled ? (\n <div className=\"devic-cm-empty\">{l.disabled}</div>\n ) : entries.length === 0 && !composerOpen ? (\n <div className=\"devic-cm-empty\">{l.empty}</div>\n ) : (\n sections.map((section) => (\n <div key={section.name} className=\"devic-cm-section\">\n <div className=\"devic-cm-section-title\">\n {l.sections[section.name] ?? section.name}\n </div>\n {section.entries.map((entry) => (\n <div key={entry.id} className=\"devic-cm-entry\">\n {editingId === entry.id ? (\n <div className=\"devic-cm-editor\">\n <textarea\n className=\"devic-cm-textarea\"\n value={editingText}\n maxLength={limits?.maxEntryChars || undefined}\n onChange={(e) => setEditingText(e.target.value)}\n disabled={saving}\n autoFocus\n />\n <div className=\"devic-cm-editor-actions\">\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-primary\"\n onClick={() => handleSaveEdit(entry)}\n disabled={saving || !editingText.trim()}\n >\n {l.save}\n </button>\n <button\n type=\"button\"\n className=\"devic-cm-btn\"\n onClick={() => setEditingId(null)}\n disabled={saving}\n >\n {l.cancel}\n </button>\n </div>\n </div>\n ) : (\n <>\n <div className=\"devic-cm-entry-content\">\n {entry.pinned && (\n <span\n className=\"devic-cm-pin\"\n title={l.pinned}\n >\n <PinIcon />\n </span>\n )}\n <span>{entry.content}</span>\n </div>\n {editable && (\n <div className=\"devic-cm-entry-actions\">\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-small\"\n onClick={() => {\n setEditingId(entry.id);\n setEditingText(entry.content);\n }}\n disabled={saving}\n >\n {l.edit}\n </button>\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-small devic-cm-btn-danger\"\n onClick={() => handleRemove(entry)}\n disabled={saving}\n >\n {l.remove}\n </button>\n </div>\n )}\n </>\n )}\n </div>\n ))}\n </div>\n ))\n )}\n\n {editable && enabled && !loading && (\n <div className=\"devic-cm-composer\">\n {composerOpen ? (\n <>\n <div className=\"devic-cm-composer-row\">\n <select\n className=\"devic-cm-select\"\n value={composerSection}\n onChange={(e) => setComposerSection(e.target.value)}\n disabled={saving}\n >\n {SECTIONS.map((s) => (\n <option key={s} value={s}>\n {l.sections[s] ?? s}\n </option>\n ))}\n </select>\n </div>\n <textarea\n className=\"devic-cm-textarea\"\n placeholder={l.placeholder}\n value={composerText}\n maxLength={limits?.maxEntryChars || undefined}\n onChange={(e) => setComposerText(e.target.value)}\n disabled={saving}\n autoFocus\n />\n <div className=\"devic-cm-editor-actions\">\n <button\n type=\"button\"\n className=\"devic-cm-btn devic-cm-btn-primary\"\n onClick={handleAdd}\n disabled={saving || !composerText.trim()}\n >\n {l.add}\n </button>\n <button\n type=\"button\"\n className=\"devic-cm-btn\"\n onClick={() => {\n setComposerOpen(false);\n setComposerText(\"\");\n }}\n disabled={saving}\n >\n {l.cancel}\n </button>\n </div>\n </>\n ) : (\n <button\n type=\"button\"\n className=\"devic-cm-btn\"\n onClick={() => setComposerOpen(true)}\n disabled={saving}\n >\n {l.addMemory}\n </button>\n )}\n </div>\n )}\n </div>\n\n {limits && enabled && (\n <div className=\"devic-cm-footer\">\n {fillTemplate(l.footer, {\n count: String(entries.length),\n max: String(limits.maxEntries),\n chars: String(limits.maxEntryChars),\n })}\n </div>\n )}\n </div>\n </div>,\n document.body\n );\n}\n\nexport default CoreMemoryModal;\n"],"names":["_jsxs","_jsx","theme","useMemo","useOptionalDevicContext","client","DevicApiClient","useState","useCallback","useRef","useEffect","createPortal","themeVars","_Fragment"],"mappings":"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"}
@@ -92,6 +92,22 @@ function useDevicChat(options) {
92
92
  return fresh.length ? [...prev, ...fresh] : prev;
93
93
  });
94
94
  }, []);
95
+ // Compaction checkpoints of the conversation, and the one being written
96
+ // right now. Same merge rule as the recalls: the realtime blob only carries
97
+ // the in-flight run's checkpoints, so incoming batches merge by uid.
98
+ const [compactions, setCompactions] = React.useState([]);
99
+ const mergeCompactions = React.useCallback((incoming) => {
100
+ if (!incoming?.length)
101
+ return;
102
+ setCompactions((prev) => {
103
+ const known = new Set(prev.map((c) => c.uid));
104
+ const fresh = incoming.filter((c) => !known.has(c.uid));
105
+ return fresh.length ? [...prev, ...fresh] : prev;
106
+ });
107
+ }, []);
108
+ // Absent on every ordinary realtime write, which is how a finished
109
+ // compaction stops being reported.
110
+ const [compaction, setCompaction] = React.useState(null);
95
111
  // Handoff state
96
112
  const [handedOff, setHandedOff] = React.useState(false);
97
113
  const [handedOffSubThreadId, setHandedOffSubThreadId] = React.useState(null);
@@ -194,6 +210,8 @@ function useDevicChat(options) {
194
210
  setMessages([...(realtime.chatHistory ?? []), ...queuedOnServer]);
195
211
  }
196
212
  mergeRecalledMemories(realtime.recalledMemories);
213
+ mergeCompactions(realtime.compactions);
214
+ setCompaction(realtime.compaction ?? null);
197
215
  setStatus(realtime.status);
198
216
  setQueuedCount(realtime.queuedMessages ?? 0);
199
217
  if (realtime.status === 'processing') {
@@ -233,7 +251,7 @@ function useDevicChat(options) {
233
251
  logRef.current.warn('[useDevicChat] resumeFromRealtimeStatus failed:', err);
234
252
  setIsLoading(false);
235
253
  }
236
- }, [assistantId, mergeRecalledMemories]);
254
+ }, [assistantId, mergeRecalledMemories, mergeCompactions]);
237
255
  // Load initial chat history if chatUid prop is provided
238
256
  // This runs once on mount (or when initialChatUid changes) to fetch existing conversation
239
257
  const initialChatLoadedRef = React.useRef(false);
@@ -247,6 +265,7 @@ function useDevicChat(options) {
247
265
  const history = await clientRef.current.getChatHistory(assistantId, initialChatUid, { tenantId: resolvedTenantId });
248
266
  setMessages(history.chatContent);
249
267
  mergeRecalledMemories(history.recalledMemories);
268
+ mergeCompactions(history.compactions);
250
269
  setChatUid(initialChatUid);
251
270
  // Check realtime status to resume in-progress conversations
252
271
  await resumeFromRealtimeStatus(initialChatUid);
@@ -375,6 +394,10 @@ function useDevicChat(options) {
375
394
  // Surface recall events while the run is still processing, so the
376
395
  // "recalled memories" strip shows before the first response lands.
377
396
  mergeRecalledMemories(data.recalledMemories);
397
+ // A compaction runs between two assistant messages: without this the
398
+ // conversation looks stalled while it is being written.
399
+ mergeCompactions(data.compactions);
400
+ setCompaction(data.compaction ?? null);
378
401
  setStatus(data.status);
379
402
  // Notify about new messages
380
403
  const lastMessage = data.chatHistory[data.chatHistory.length - 1];
@@ -719,6 +742,8 @@ function useDevicChat(options) {
719
742
  setError(null);
720
743
  setLimitExceeded(null);
721
744
  setRecalledMemories([]);
745
+ setCompactions([]);
746
+ setCompaction(null);
722
747
  resetQueueState();
723
748
  pendingWidgetCallsRef.current = [];
724
749
  setPendingWidgetCalls([]);
@@ -744,12 +769,15 @@ function useDevicChat(options) {
744
769
  setIsLoading(true);
745
770
  setError(null);
746
771
  setRecalledMemories([]);
772
+ setCompactions([]);
773
+ setCompaction(null);
747
774
  // The queue belongs to the conversation being left behind.
748
775
  resetQueueState();
749
776
  try {
750
777
  const history = await clientRef.current.getChatHistory(assistantId, loadChatUid, { tenantId: resolvedTenantId });
751
778
  setMessages(history.chatContent);
752
779
  mergeRecalledMemories(history.recalledMemories);
780
+ mergeCompactions(history.compactions);
753
781
  setChatUid(loadChatUid);
754
782
  // Check realtime status to resume in-progress conversations
755
783
  await resumeFromRealtimeStatus(loadChatUid);
@@ -765,6 +793,7 @@ function useDevicChat(options) {
765
793
  resolvedTenantId,
766
794
  resumeFromRealtimeStatus,
767
795
  mergeRecalledMemories,
796
+ mergeCompactions,
768
797
  resetQueueState,
769
798
  ]);
770
799
  // Handoff polling: while handedOff is true, poll the realtime endpoint every
@@ -893,6 +922,8 @@ function useDevicChat(options) {
893
922
  error,
894
923
  limitExceeded,
895
924
  recalledMemories,
925
+ compactions,
926
+ compaction,
896
927
  handedOff,
897
928
  handedOffSubThreadId,
898
929
  queuedCount,