@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.
- package/README.md +58 -0
- package/dist/cjs/api/types.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js +8 -3
- package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/ChatMessages.js +41 -4
- package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -1
- package/dist/cjs/components/ChatDrawer/CompactionWidget.js +72 -0
- package/dist/cjs/components/ChatDrawer/CompactionWidget.js.map +1 -0
- package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js +41 -4
- package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
- package/dist/cjs/hooks/useDevicChat.js +32 -1
- package/dist/cjs/hooks/useDevicChat.js.map +1 -1
- package/dist/cjs/index.js +3 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/styles.css +1 -1
- package/dist/esm/api/types.d.ts +83 -0
- package/dist/esm/api/types.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.js +9 -4
- package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
- package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +40 -1
- package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +1 -1
- package/dist/esm/components/ChatDrawer/ChatMessages.js +41 -4
- package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -1
- package/dist/esm/components/ChatDrawer/CompactionWidget.d.ts +47 -0
- package/dist/esm/components/ChatDrawer/CompactionWidget.js +70 -0
- package/dist/esm/components/ChatDrawer/CompactionWidget.js.map +1 -0
- package/dist/esm/components/ChatDrawer/index.d.ts +2 -0
- package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.d.ts +39 -2
- package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js +41 -5
- package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
- package/dist/esm/components/CoreMemoryModal/index.d.ts +2 -2
- package/dist/esm/hooks/useDevicChat.d.ts +13 -1
- package/dist/esm/hooks/useDevicChat.js +32 -1
- package/dist/esm/hooks/useDevicChat.js.map +1 -1
- package/dist/esm/index.d.ts +5 -5
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/styles.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompactionWidget.js","sources":["../../../../src/components/ChatDrawer/CompactionWidget.tsx"],"sourcesContent":["import { useState, type JSX, type ReactNode } from \"react\";\nimport type {\n CompactionActivity,\n CompactionCheckpoint,\n CompactionSummary,\n} from \"../../api/types\";\n\n/** Data handed to a custom compaction renderer. */\nexport interface CompactionRendererProps {\n /**\n * The checkpoint at this point of the conversation. Null while a compaction\n * is being written and there is nothing to show yet.\n */\n checkpoint: CompactionCheckpoint | null;\n /**\n * True for the checkpoint that currently governs the context. Each\n * compaction merges the previous summary into itself, so the earlier ones\n * are a record rather than something still being sent.\n */\n isActive: boolean;\n /**\n * The compaction happening right now, or null. Present without a checkpoint\n * means one is being written; the numbers say what it is folding.\n */\n activity: CompactionActivity | null;\n}\n\n/** Replaces the built-in compaction marker. Return null to hide it. */\nexport type CompactionRenderer = (props: CompactionRendererProps) => ReactNode;\n\nfunction formatTokens(value: number): string {\n if (!value) return \"0\";\n if (value < 1000) return String(value);\n if (value < 1_000_000) return `${(value / 1000).toFixed(1)}k`;\n return `${(value / 1_000_000).toFixed(2)}M`;\n}\n\nfunction CompressIcon(): JSX.Element {\n return (\n <svg\n className=\"devic-compaction-icon\"\n width=\"13\"\n height=\"13\"\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 <polyline points=\"4 14 10 14 10 20\" />\n <polyline points=\"20 10 14 10 14 4\" />\n <line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </svg>\n );\n}\n\nfunction ChevronIcon({ up }: { up: boolean }): JSX.Element {\n return (\n <svg\n className=\"devic-compaction-chevron\"\n width=\"12\"\n height=\"12\"\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 style={{ transform: up ? \"rotate(180deg)\" : undefined }}\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n );\n}\n\nfunction Section({\n title,\n children,\n}: {\n title: string;\n children: ReactNode;\n}): JSX.Element {\n return (\n <div className=\"devic-compaction-section\">\n <span className=\"devic-compaction-section-title\">{title}</span>\n {children}\n </div>\n );\n}\n\nfunction Bullets({ items }: { items?: string[] }): JSX.Element | null {\n if (!items?.length) return null;\n return (\n <ul className=\"devic-compaction-list\">\n {items.map((item, i) => (\n <li key={i}>{item}</li>\n ))}\n </ul>\n );\n}\n\nfunction hasStructure(summary: CompactionSummary): boolean {\n return Boolean(\n summary.goal ||\n summary.constraints?.length ||\n summary.inProgress ||\n summary.pending?.length ||\n summary.decisions?.length ||\n summary.data?.length ||\n summary.done?.length ||\n summary.openQuestions?.length\n );\n}\n\nexport interface CompactionWidgetProps {\n checkpoint: CompactionCheckpoint | null;\n isActive?: boolean;\n activity?: CompactionActivity | null;\n renderer?: CompactionRenderer;\n}\n\n/**\n * The cut line in the conversation.\n *\n * Anchored to the last message a checkpoint folded, it marks the exact point\n * where the assistant's view of the conversation stops: everything above it\n * is still here, still readable, and no longer sent. Collapsed it is a rule\n * across the thread with the headline numbers; expanded it shows what the\n * assistant reads in place of those messages.\n *\n * With no checkpoint yet and a compaction in flight it says so instead — that\n * is a model call of its own, and without it the conversation just appears to\n * have gone quiet.\n *\n * Deliberately not a message bubble: a checkpoint is not something anyone\n * said.\n */\nexport function CompactionWidget({\n checkpoint,\n isActive = true,\n activity = null,\n renderer,\n}: CompactionWidgetProps): JSX.Element | null {\n const [expanded, setExpanded] = useState(false);\n\n if (renderer) {\n return <>{renderer({ checkpoint, isActive, activity })}</>;\n }\n\n const running = activity?.state === \"running\";\n\n if (!checkpoint) {\n if (!running) return null;\n return (\n <div className=\"devic-compaction devic-compaction-running\">\n <span className=\"devic-compaction-rule\" />\n <span className=\"devic-compaction-pill\">\n <CompressIcon />\n <span className=\"devic-compaction-title\">Compacting context</span>\n <span className=\"devic-compaction-meta\">\n {activity!.messageCount} message\n {activity!.messageCount === 1 ? \"\" : \"s\"} ·{\" \"}\n {formatTokens(activity!.tokensBefore)} tokens\n </span>\n <span className=\"devic-compaction-dots\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n </span>\n </span>\n <span className=\"devic-compaction-rule\" />\n </div>\n );\n }\n\n const summary = checkpoint.summary || {};\n const structured = hasStructure(summary);\n\n return (\n <div className=\"devic-compaction\">\n <div className=\"devic-compaction-head\">\n <span className=\"devic-compaction-rule\" />\n <button\n type=\"button\"\n className=\"devic-compaction-pill\"\n onClick={() => setExpanded((v) => !v)}\n aria-expanded={expanded}\n title={`${checkpoint.compactedMessageCount} message${\n checkpoint.compactedMessageCount === 1 ? \"\" : \"s\"\n } are still in this conversation but no longer sent to the assistant`}\n >\n <CompressIcon />\n <span className=\"devic-compaction-title\">\n Context compacted\n {checkpoint.index > 1 ? ` (#${checkpoint.index})` : \"\"}\n </span>\n <span className=\"devic-compaction-meta\">\n {checkpoint.compactedMessageCount} messages ·{\" \"}\n {formatTokens(checkpoint.tokensBefore)} →{\" \"}\n {formatTokens(checkpoint.tokensAfter)} tokens\n </span>\n {!isActive && (\n <span\n className=\"devic-compaction-tag\"\n title=\"Superseded by a later compaction, which merged this summary into itself. Kept for the record.\"\n >\n superseded\n </span>\n )}\n <ChevronIcon up={expanded} />\n </button>\n <span className=\"devic-compaction-rule\" />\n </div>\n\n {expanded && (\n <div className=\"devic-compaction-body\">\n <div className=\"devic-compaction-note\">\n This is what the assistant reads in place of the messages above.\n The messages themselves are still here.\n </div>\n\n {structured && (\n <>\n {summary.goal && <Section title=\"Goal\">{summary.goal}</Section>}\n {!!summary.constraints?.length && (\n <Section title=\"Constraints\">\n <Bullets items={summary.constraints} />\n </Section>\n )}\n {summary.inProgress && (\n <Section title=\"In progress\">{summary.inProgress}</Section>\n )}\n {!!summary.pending?.length && (\n <Section title=\"Pending\">\n <Bullets items={summary.pending} />\n </Section>\n )}\n {!!summary.decisions?.length && (\n <Section title=\"Decisions\">\n <Bullets items={summary.decisions} />\n </Section>\n )}\n {!!summary.data?.length && (\n <Section title=\"Key data\">\n <Bullets\n items={summary.data.map((entry) =>\n entry.label ? `${entry.label}: ${entry.value}` : entry.value\n )}\n />\n </Section>\n )}\n {!!summary.done?.length && (\n <Section title=\"Done\">\n <Bullets items={summary.done} />\n </Section>\n )}\n {!!summary.openQuestions?.length && (\n <Section title=\"Open questions\">\n <Bullets items={summary.openQuestions} />\n </Section>\n )}\n </>\n )}\n\n {summary.raw && (\n <Section title={structured ? \"Notes\" : \"Summary\"}>\n <div className=\"devic-compaction-raw\">{summary.raw}</div>\n </Section>\n )}\n\n {!!checkpoint.facts?.length && (\n <Section title=\"Preserved exactly\">\n <div className=\"devic-compaction-facts\">\n {checkpoint.facts.map((fact, i) => (\n <span key={i} className=\"devic-compaction-fact\">\n {fact.label ? (\n <span className=\"devic-compaction-fact-label\">\n {fact.label}:{\" \"}\n </span>\n ) : null}\n {fact.value}\n </span>\n ))}\n </div>\n </Section>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport default CompactionWidget;\n"],"names":["_jsxs","_jsx","_Fragment"],"mappings":"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"}
|
|
@@ -13,6 +13,8 @@ export type { LimitBannerProps } from './LimitBanner';
|
|
|
13
13
|
export { QueueNotice } from './QueueNotice';
|
|
14
14
|
export type { QueueNoticeProps } from './QueueNotice';
|
|
15
15
|
export { RecalledMemoriesWidget } from './RecalledMemoriesWidget';
|
|
16
|
+
export type { CompactionWidgetProps, CompactionRenderer, CompactionRendererProps, } from './CompactionWidget';
|
|
17
|
+
export { CompactionWidget } from './CompactionWidget';
|
|
16
18
|
export type { RecalledMemoriesWidgetProps, RecalledMemoriesRenderer, RecalledMemoriesRendererProps, } from './RecalledMemoriesWidget';
|
|
17
19
|
export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, MessageBubbleRenderer, MessageBubbleRendererProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, SuggestedMessage, } from './ChatDrawer.types';
|
|
18
20
|
export type { HandoffSubagentWidgetProps } from './HandoffSubagentWidget';
|
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
import { type JSX } from "react";
|
|
2
2
|
import { type DevicTheme } from "../theme";
|
|
3
3
|
import "./CoreMemoryModal.css";
|
|
4
|
+
/**
|
|
5
|
+
* Every piece of text the modal shows, so a host can render it in its own
|
|
6
|
+
* language. Any subset can be given; the rest keeps the English default.
|
|
7
|
+
*/
|
|
8
|
+
export interface CoreMemoryLabels {
|
|
9
|
+
/** Modal title; the drawer also uses it for its brain button tooltip. */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Accessible name of the close button. */
|
|
12
|
+
close: string;
|
|
13
|
+
loading: string;
|
|
14
|
+
/** Shown when the assistant has no core memory tier enabled. */
|
|
15
|
+
disabled: string;
|
|
16
|
+
/** Shown when the bucket holds no entries yet. */
|
|
17
|
+
empty: string;
|
|
18
|
+
/** Tooltip of the pin mark. */
|
|
19
|
+
pinned: string;
|
|
20
|
+
edit: string;
|
|
21
|
+
remove: string;
|
|
22
|
+
save: string;
|
|
23
|
+
cancel: string;
|
|
24
|
+
/** Confirms the composer. */
|
|
25
|
+
add: string;
|
|
26
|
+
/** Opens the composer. */
|
|
27
|
+
addMemory: string;
|
|
28
|
+
/** Composer placeholder. */
|
|
29
|
+
placeholder: string;
|
|
30
|
+
/** Footer; `{count}`, `{max}` and `{chars}` are replaced. */
|
|
31
|
+
footer: string;
|
|
32
|
+
/** Display names of the sections, by section key. */
|
|
33
|
+
sections: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
export declare const DEFAULT_CORE_MEMORY_LABELS: CoreMemoryLabels;
|
|
4
36
|
export interface CoreMemoryModalProps {
|
|
5
37
|
/** Whether the modal is visible. */
|
|
6
38
|
isOpen: boolean;
|
|
@@ -21,8 +53,13 @@ export interface CoreMemoryModalProps {
|
|
|
21
53
|
* @default true
|
|
22
54
|
*/
|
|
23
55
|
editable?: boolean;
|
|
24
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Modal title. @default "Assistant memory"
|
|
58
|
+
* @deprecated Prefer `labels.title`; kept so existing hosts keep working.
|
|
59
|
+
*/
|
|
25
60
|
title?: string;
|
|
61
|
+
/** Texts of the modal, for a host that renders it in its own language. */
|
|
62
|
+
labels?: Partial<CoreMemoryLabels>;
|
|
26
63
|
/**
|
|
27
64
|
* Colours and font. Same names as the drawer's style options, and the drawer
|
|
28
65
|
* passes its own down — a dialog opening in the default light palette over a
|
|
@@ -40,5 +77,5 @@ export interface CoreMemoryModalProps {
|
|
|
40
77
|
* Backed by the public memory API (`/api/v1/memory/assistants/:id/core`);
|
|
41
78
|
* the API key needs that endpoint allowed.
|
|
42
79
|
*/
|
|
43
|
-
export declare function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable, title, theme, }: CoreMemoryModalProps): JSX.Element | null;
|
|
80
|
+
export declare function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable, title, labels, theme, }: CoreMemoryModalProps): JSX.Element | null;
|
|
44
81
|
export default CoreMemoryModal;
|
|
@@ -7,6 +7,29 @@ import { themeVars } from '../theme.js';
|
|
|
7
7
|
|
|
8
8
|
/** Canonical sections of the core tier, in display order. */
|
|
9
9
|
const SECTIONS = ["persona", "instructions", "decisions", "profile"];
|
|
10
|
+
const DEFAULT_CORE_MEMORY_LABELS = {
|
|
11
|
+
title: "Assistant memory",
|
|
12
|
+
close: "Close",
|
|
13
|
+
loading: "Loading memory…",
|
|
14
|
+
disabled: "Memory is not enabled for this assistant.",
|
|
15
|
+
empty: "Nothing remembered yet. What the assistant learns and is told to keep will appear here.",
|
|
16
|
+
pinned: "Pinned: always kept, never changed by the assistant",
|
|
17
|
+
edit: "Edit",
|
|
18
|
+
remove: "Remove",
|
|
19
|
+
save: "Save",
|
|
20
|
+
cancel: "Cancel",
|
|
21
|
+
add: "Add",
|
|
22
|
+
addMemory: "+ Add memory",
|
|
23
|
+
placeholder: "Something the assistant should always remember…",
|
|
24
|
+
footer: "{count}/{max} entries · up to {chars} characters each",
|
|
25
|
+
sections: {
|
|
26
|
+
persona: "persona",
|
|
27
|
+
instructions: "instructions",
|
|
28
|
+
decisions: "decisions",
|
|
29
|
+
profile: "profile",
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const fillTemplate = (template, values) => template.replace(/\{(\w+)\}/g, (_, key) => values[key] ?? "");
|
|
10
33
|
function BrainIcon() {
|
|
11
34
|
return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [jsx("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" }), jsx("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" })] }));
|
|
12
35
|
}
|
|
@@ -23,7 +46,16 @@ function PinIcon() {
|
|
|
23
46
|
* Backed by the public memory API (`/api/v1/memory/assistants/:id/core`);
|
|
24
47
|
* the API key needs that endpoint allowed.
|
|
25
48
|
*/
|
|
26
|
-
function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable = true, title
|
|
49
|
+
function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId, apiKey, baseUrl, editable = true, title, labels, theme, }) {
|
|
50
|
+
const l = useMemo(() => ({
|
|
51
|
+
...DEFAULT_CORE_MEMORY_LABELS,
|
|
52
|
+
...labels,
|
|
53
|
+
title: labels?.title ?? title ?? DEFAULT_CORE_MEMORY_LABELS.title,
|
|
54
|
+
sections: {
|
|
55
|
+
...DEFAULT_CORE_MEMORY_LABELS.sections,
|
|
56
|
+
...labels?.sections,
|
|
57
|
+
},
|
|
58
|
+
}), [labels, title]);
|
|
27
59
|
const context = useOptionalDevicContext();
|
|
28
60
|
const resolvedBaseUrl = baseUrl || context?.baseUrl || "https://api.devic.ai";
|
|
29
61
|
const resolvedTenantId = tenantId || context?.tenantId;
|
|
@@ -158,14 +190,18 @@ function CoreMemoryModal({ isOpen, onClose, assistantId, tenantId, subtenantId,
|
|
|
158
190
|
return createPortal(
|
|
159
191
|
// The variables go on the overlay: a portal inherits nothing from the
|
|
160
192
|
// drawer that opened it, so without this the dialog ignores the theme.
|
|
161
|
-
jsx("div", { className: "devic-cm-overlay", style: themeVars(theme), onClick: onClose, children: jsxs("div", { className: "devic-cm-modal", role: "dialog", "aria-modal": "true", "aria-label": title, onClick: (e) => e.stopPropagation(), children: [jsxs("div", { className: "devic-cm-header", children: [jsxs("h3", { className: "devic-cm-title", children: [jsx(BrainIcon, {}), title] }), jsx("button", { className: "devic-cm-close", onClick: onClose, type: "button", "aria-label":
|
|
193
|
+
jsx("div", { className: "devic-cm-overlay", style: themeVars(theme), onClick: onClose, children: jsxs("div", { className: "devic-cm-modal", role: "dialog", "aria-modal": "true", "aria-label": l.title, onClick: (e) => e.stopPropagation(), children: [jsxs("div", { className: "devic-cm-header", children: [jsxs("h3", { className: "devic-cm-title", children: [jsx(BrainIcon, {}), l.title] }), jsx("button", { className: "devic-cm-close", onClick: onClose, type: "button", "aria-label": l.close, children: "\u00D7" })] }), jsxs("div", { className: "devic-cm-body", children: [error && jsx("div", { className: "devic-cm-error", children: error }), loading ? (jsx("div", { className: "devic-cm-loading", children: l.loading })) : !enabled ? (jsx("div", { className: "devic-cm-empty", children: l.disabled })) : entries.length === 0 && !composerOpen ? (jsx("div", { className: "devic-cm-empty", children: l.empty })) : (sections.map((section) => (jsxs("div", { className: "devic-cm-section", children: [jsx("div", { className: "devic-cm-section-title", children: l.sections[section.name] ?? section.name }), section.entries.map((entry) => (jsx("div", { className: "devic-cm-entry", children: editingId === entry.id ? (jsxs("div", { className: "devic-cm-editor", children: [jsx("textarea", { className: "devic-cm-textarea", value: editingText, maxLength: limits?.maxEntryChars || undefined, onChange: (e) => setEditingText(e.target.value), disabled: saving, autoFocus: true }), jsxs("div", { className: "devic-cm-editor-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-primary", onClick: () => handleSaveEdit(entry), disabled: saving || !editingText.trim(), children: l.save }), jsx("button", { type: "button", className: "devic-cm-btn", onClick: () => setEditingId(null), disabled: saving, children: l.cancel })] })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "devic-cm-entry-content", children: [entry.pinned && (jsx("span", { className: "devic-cm-pin", title: l.pinned, children: jsx(PinIcon, {}) })), jsx("span", { children: entry.content })] }), editable && (jsxs("div", { className: "devic-cm-entry-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-small", onClick: () => {
|
|
162
194
|
setEditingId(entry.id);
|
|
163
195
|
setEditingText(entry.content);
|
|
164
|
-
}, disabled: saving, children:
|
|
196
|
+
}, disabled: saving, children: l.edit }), jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-small devic-cm-btn-danger", onClick: () => handleRemove(entry), disabled: saving, children: l.remove })] }))] })) }, entry.id)))] }, section.name)))), editable && enabled && !loading && (jsx("div", { className: "devic-cm-composer", children: composerOpen ? (jsxs(Fragment, { children: [jsx("div", { className: "devic-cm-composer-row", children: jsx("select", { className: "devic-cm-select", value: composerSection, onChange: (e) => setComposerSection(e.target.value), disabled: saving, children: SECTIONS.map((s) => (jsx("option", { value: s, children: l.sections[s] ?? s }, s))) }) }), jsx("textarea", { className: "devic-cm-textarea", placeholder: l.placeholder, value: composerText, maxLength: limits?.maxEntryChars || undefined, onChange: (e) => setComposerText(e.target.value), disabled: saving, autoFocus: true }), jsxs("div", { className: "devic-cm-editor-actions", children: [jsx("button", { type: "button", className: "devic-cm-btn devic-cm-btn-primary", onClick: handleAdd, disabled: saving || !composerText.trim(), children: l.add }), jsx("button", { type: "button", className: "devic-cm-btn", onClick: () => {
|
|
165
197
|
setComposerOpen(false);
|
|
166
198
|
setComposerText("");
|
|
167
|
-
}, disabled: saving, children:
|
|
199
|
+
}, disabled: saving, children: l.cancel })] })] })) : (jsx("button", { type: "button", className: "devic-cm-btn", onClick: () => setComposerOpen(true), disabled: saving, children: l.addMemory })) }))] }), limits && enabled && (jsx("div", { className: "devic-cm-footer", children: fillTemplate(l.footer, {
|
|
200
|
+
count: String(entries.length),
|
|
201
|
+
max: String(limits.maxEntries),
|
|
202
|
+
chars: String(limits.maxEntryChars),
|
|
203
|
+
}) }))] }) }), document.body);
|
|
168
204
|
}
|
|
169
205
|
|
|
170
|
-
export { CoreMemoryModal };
|
|
206
|
+
export { CoreMemoryModal, DEFAULT_CORE_MEMORY_LABELS };
|
|
171
207
|
//# sourceMappingURL=CoreMemoryModal.js.map
|
|
@@ -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","_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","_Fragment"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { CoreMemoryModal, default } from "./CoreMemoryModal";
|
|
2
|
-
export type { CoreMemoryModalProps } from "./CoreMemoryModal";
|
|
1
|
+
export { CoreMemoryModal, DEFAULT_CORE_MEMORY_LABELS, default, } from "./CoreMemoryModal";
|
|
2
|
+
export type { CoreMemoryModalProps, CoreMemoryLabels } from "./CoreMemoryModal";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TenantMetadata, SubtenantMetadata } from '../provider';
|
|
2
2
|
import { type PendingWidgetCall } from './useModelInterface';
|
|
3
|
-
import type { ChatMessage, ChatFile, ModelInterfaceTool, QueueDisposition, RealtimeStatus, RecalledMemoryRecord, TenantLimitExceeded } from '../api/types';
|
|
3
|
+
import type { ChatMessage, ChatFile, CompactionActivity, CompactionCheckpoint, ModelInterfaceTool, QueueDisposition, RealtimeStatus, RecalledMemoryRecord, TenantLimitExceeded } from '../api/types';
|
|
4
4
|
export interface UseDevicChatOptions {
|
|
5
5
|
/**
|
|
6
6
|
* Assistant identifier
|
|
@@ -177,6 +177,18 @@ export interface UseDevicChatResult {
|
|
|
177
177
|
* without memory.
|
|
178
178
|
*/
|
|
179
179
|
recalledMemories: RecalledMemoryRecord[];
|
|
180
|
+
/**
|
|
181
|
+
* Compaction checkpoints of the conversation, oldest first. Each one folds
|
|
182
|
+
* the messages before its boundary into a summary the model reads instead
|
|
183
|
+
* of them; the messages themselves stay in `messages`.
|
|
184
|
+
*/
|
|
185
|
+
compactions: CompactionCheckpoint[];
|
|
186
|
+
/**
|
|
187
|
+
* The compaction being written right now, or null. A compaction is a model
|
|
188
|
+
* call of its own between two assistant messages, so this is what tells a
|
|
189
|
+
* UI why the conversation has gone quiet.
|
|
190
|
+
*/
|
|
191
|
+
compaction: CompactionActivity | null;
|
|
180
192
|
/**
|
|
181
193
|
* Whether the assistant has handed off to a subagent
|
|
182
194
|
*/
|
|
@@ -90,6 +90,22 @@ function useDevicChat(options) {
|
|
|
90
90
|
return fresh.length ? [...prev, ...fresh] : prev;
|
|
91
91
|
});
|
|
92
92
|
}, []);
|
|
93
|
+
// Compaction checkpoints of the conversation, and the one being written
|
|
94
|
+
// right now. Same merge rule as the recalls: the realtime blob only carries
|
|
95
|
+
// the in-flight run's checkpoints, so incoming batches merge by uid.
|
|
96
|
+
const [compactions, setCompactions] = useState([]);
|
|
97
|
+
const mergeCompactions = useCallback((incoming) => {
|
|
98
|
+
if (!incoming?.length)
|
|
99
|
+
return;
|
|
100
|
+
setCompactions((prev) => {
|
|
101
|
+
const known = new Set(prev.map((c) => c.uid));
|
|
102
|
+
const fresh = incoming.filter((c) => !known.has(c.uid));
|
|
103
|
+
return fresh.length ? [...prev, ...fresh] : prev;
|
|
104
|
+
});
|
|
105
|
+
}, []);
|
|
106
|
+
// Absent on every ordinary realtime write, which is how a finished
|
|
107
|
+
// compaction stops being reported.
|
|
108
|
+
const [compaction, setCompaction] = useState(null);
|
|
93
109
|
// Handoff state
|
|
94
110
|
const [handedOff, setHandedOff] = useState(false);
|
|
95
111
|
const [handedOffSubThreadId, setHandedOffSubThreadId] = useState(null);
|
|
@@ -192,6 +208,8 @@ function useDevicChat(options) {
|
|
|
192
208
|
setMessages([...(realtime.chatHistory ?? []), ...queuedOnServer]);
|
|
193
209
|
}
|
|
194
210
|
mergeRecalledMemories(realtime.recalledMemories);
|
|
211
|
+
mergeCompactions(realtime.compactions);
|
|
212
|
+
setCompaction(realtime.compaction ?? null);
|
|
195
213
|
setStatus(realtime.status);
|
|
196
214
|
setQueuedCount(realtime.queuedMessages ?? 0);
|
|
197
215
|
if (realtime.status === 'processing') {
|
|
@@ -231,7 +249,7 @@ function useDevicChat(options) {
|
|
|
231
249
|
logRef.current.warn('[useDevicChat] resumeFromRealtimeStatus failed:', err);
|
|
232
250
|
setIsLoading(false);
|
|
233
251
|
}
|
|
234
|
-
}, [assistantId, mergeRecalledMemories]);
|
|
252
|
+
}, [assistantId, mergeRecalledMemories, mergeCompactions]);
|
|
235
253
|
// Load initial chat history if chatUid prop is provided
|
|
236
254
|
// This runs once on mount (or when initialChatUid changes) to fetch existing conversation
|
|
237
255
|
const initialChatLoadedRef = useRef(false);
|
|
@@ -245,6 +263,7 @@ function useDevicChat(options) {
|
|
|
245
263
|
const history = await clientRef.current.getChatHistory(assistantId, initialChatUid, { tenantId: resolvedTenantId });
|
|
246
264
|
setMessages(history.chatContent);
|
|
247
265
|
mergeRecalledMemories(history.recalledMemories);
|
|
266
|
+
mergeCompactions(history.compactions);
|
|
248
267
|
setChatUid(initialChatUid);
|
|
249
268
|
// Check realtime status to resume in-progress conversations
|
|
250
269
|
await resumeFromRealtimeStatus(initialChatUid);
|
|
@@ -373,6 +392,10 @@ function useDevicChat(options) {
|
|
|
373
392
|
// Surface recall events while the run is still processing, so the
|
|
374
393
|
// "recalled memories" strip shows before the first response lands.
|
|
375
394
|
mergeRecalledMemories(data.recalledMemories);
|
|
395
|
+
// A compaction runs between two assistant messages: without this the
|
|
396
|
+
// conversation looks stalled while it is being written.
|
|
397
|
+
mergeCompactions(data.compactions);
|
|
398
|
+
setCompaction(data.compaction ?? null);
|
|
376
399
|
setStatus(data.status);
|
|
377
400
|
// Notify about new messages
|
|
378
401
|
const lastMessage = data.chatHistory[data.chatHistory.length - 1];
|
|
@@ -717,6 +740,8 @@ function useDevicChat(options) {
|
|
|
717
740
|
setError(null);
|
|
718
741
|
setLimitExceeded(null);
|
|
719
742
|
setRecalledMemories([]);
|
|
743
|
+
setCompactions([]);
|
|
744
|
+
setCompaction(null);
|
|
720
745
|
resetQueueState();
|
|
721
746
|
pendingWidgetCallsRef.current = [];
|
|
722
747
|
setPendingWidgetCalls([]);
|
|
@@ -742,12 +767,15 @@ function useDevicChat(options) {
|
|
|
742
767
|
setIsLoading(true);
|
|
743
768
|
setError(null);
|
|
744
769
|
setRecalledMemories([]);
|
|
770
|
+
setCompactions([]);
|
|
771
|
+
setCompaction(null);
|
|
745
772
|
// The queue belongs to the conversation being left behind.
|
|
746
773
|
resetQueueState();
|
|
747
774
|
try {
|
|
748
775
|
const history = await clientRef.current.getChatHistory(assistantId, loadChatUid, { tenantId: resolvedTenantId });
|
|
749
776
|
setMessages(history.chatContent);
|
|
750
777
|
mergeRecalledMemories(history.recalledMemories);
|
|
778
|
+
mergeCompactions(history.compactions);
|
|
751
779
|
setChatUid(loadChatUid);
|
|
752
780
|
// Check realtime status to resume in-progress conversations
|
|
753
781
|
await resumeFromRealtimeStatus(loadChatUid);
|
|
@@ -763,6 +791,7 @@ function useDevicChat(options) {
|
|
|
763
791
|
resolvedTenantId,
|
|
764
792
|
resumeFromRealtimeStatus,
|
|
765
793
|
mergeRecalledMemories,
|
|
794
|
+
mergeCompactions,
|
|
766
795
|
resetQueueState,
|
|
767
796
|
]);
|
|
768
797
|
// Handoff polling: while handedOff is true, poll the realtime endpoint every
|
|
@@ -891,6 +920,8 @@ function useDevicChat(options) {
|
|
|
891
920
|
error,
|
|
892
921
|
limitExceeded,
|
|
893
922
|
recalledMemories,
|
|
923
|
+
compactions,
|
|
924
|
+
compaction,
|
|
894
925
|
handedOff,
|
|
895
926
|
handedOffSubThreadId,
|
|
896
927
|
queuedCount,
|