@jini-ai/chat 0.3.11 → 0.5.1
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/CHANGELOG.md +130 -0
- package/README.md +152 -6
- package/dist/core/ag-ui/entry.d.ts +53 -0
- package/dist/core/ag-ui/entry.js +135 -0
- package/dist/core/agentic/chat-capabilities.d.ts +1 -1
- package/dist/core/agentic/index.d.ts +1 -1
- package/dist/core/agentic/index.js +1 -1
- package/dist/core/assistant-content.d.ts +6 -2
- package/dist/core/assistant-content.js +2 -2
- package/dist/core/compact-events.d.ts +3 -1
- package/dist/core/compact-events.js +1 -1
- package/dist/core/events.d.ts +1 -1
- package/dist/core/events.js +1 -1
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +3 -3
- package/dist/core/messages.d.ts +4 -2
- package/dist/core/messages.js +2 -2
- package/dist/core/partial-json.d.ts +6 -2
- package/dist/core/partial-json.js +3 -3
- package/dist/core/persistence/index.d.ts +1 -1
- package/dist/core/persistence/index.js +1 -1
- package/dist/core/persistence/ports.d.ts +2 -123
- package/dist/core/persistence/title.d.ts +3 -1
- package/dist/core/persistence/title.js +1 -1
- package/dist/core/question-form/format.d.ts +16 -7
- package/dist/core/question-form/format.js +3 -3
- package/dist/core/question-form/normalize.d.ts +7 -2
- package/dist/core/question-form/normalize.js +5 -5
- package/dist/core/question-form/scan.d.ts +18 -6
- package/dist/core/question-form/scan.js +14 -14
- package/dist/core/run-activity.d.ts +16 -4
- package/dist/core/run-activity.js +11 -11
- package/dist/core/run-events/entry.d.ts +121 -0
- package/dist/core/run-events/entry.js +290 -0
- package/dist/core/todos.d.ts +20 -8
- package/dist/core/todos.js +11 -11
- package/dist/core/tool-events.d.ts +3 -1
- package/dist/core/tool-events.js +1 -1
- package/dist/core/tool-output.d.ts +3 -1
- package/dist/core/tool-output.js +1 -1
- package/dist/core/tools.d.ts +14 -3
- package/dist/core/tools.js +3 -3
- package/dist/core/transcript.d.ts +13 -5
- package/dist/core/transcript.js +5 -5
- package/dist/core/util/manifest.d.ts +9 -3
- package/dist/core/util/manifest.js +3 -3
- package/dist/core/util/markdown-context.d.ts +11 -3
- package/dist/core/util/markdown-context.js +3 -3
- package/dist/core/util/markup-attributes.d.ts +3 -1
- package/dist/core/util/markup-attributes.js +1 -1
- package/dist/core/util/parser.d.ts +9 -5
- package/dist/core/util/parser.js +13 -13
- package/dist/core/util/recover.d.ts +6 -2
- package/dist/core/util/recover.js +6 -6
- package/dist/core/util/strip.d.ts +19 -5
- package/dist/core/util/strip.js +17 -17
- package/dist/core/util/validate.d.ts +3 -1
- package/dist/core/util/validate.js +1 -1
- package/dist/embed-widget/browser/page-actions.d.ts +121 -0
- package/dist/embed-widget/browser/page-actions.js +113 -0
- package/dist/embed-widget/browser/session-store.d.ts +44 -0
- package/dist/embed-widget/browser/session-store.js +103 -0
- package/dist/embed-widget/react/embed.d.ts +45 -0
- package/dist/embed-widget/react/embed.js +87 -0
- package/dist/embed-widget/react/header.d.ts +21 -0
- package/dist/embed-widget/react/header.js +18 -0
- package/dist/embed-widget/transports/fetch-sse.d.ts +75 -0
- package/dist/embed-widget/transports/fetch-sse.js +175 -0
- package/dist/react/agent-bridge/frontend-session-bridge.d.ts +15 -3
- package/dist/react/agent-bridge/frontend-session-bridge.js +13 -6
- package/dist/react/artifact-types.d.ts +3 -3
- package/dist/react/artifact-types.js +3 -3
- package/dist/react/components/A2uiSurfaceCard.js +34 -13
- package/dist/react/components/AttachmentPreviewModal.hooks.d.ts +7 -2
- package/dist/react/components/AttachmentPreviewModal.hooks.js +5 -5
- package/dist/react/components/AttachmentPreviewModal.js +2 -2
- package/dist/react/components/AttachmentTray.d.ts +3 -1
- package/dist/react/components/AttachmentTray.js +2 -2
- package/dist/react/components/ChatFab.js +1 -1
- package/dist/react/components/Composer.js +9 -9
- package/dist/react/components/ConversationList.js +1 -1
- package/dist/react/components/McpUiSurfaceCard.d.ts +4 -2
- package/dist/react/components/McpUiSurfaceCard.js +5 -5
- package/dist/react/components/MessageList.js +1 -1
- package/dist/react/components/MessageRow.js +9 -9
- package/dist/react/components/QuestionForm.js +5 -5
- package/dist/react/components/ToolCard.js +9 -9
- package/dist/react/components/composer-discovery.d.ts +29 -8
- package/dist/react/components/composer-discovery.js +10 -10
- package/dist/react/ext-event-renderer-registry.d.ts +15 -5
- package/dist/react/ext-event-renderer-registry.js +4 -4
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.d.ts +3 -1
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +3 -3
- package/dist/react/features/chat-pane/components/ChatPane.js +43 -43
- package/dist/react/features/chat-pane/create-daemon-attachment-uploader.d.ts +4 -1
- package/dist/react/features/chat-pane/create-daemon-attachment-uploader.js +5 -35
- package/dist/react/features/chat-pane/create-mcp-ui-tool-caller.d.ts +5 -2
- package/dist/react/features/chat-pane/create-mcp-ui-tool-caller.js +1 -1
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.d.ts +38 -10
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +15 -15
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +31 -31
- package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.d.ts +3 -1
- package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.js +3 -3
- package/dist/react/features/chat-pane/hooks/useChatPaneComposerPlaceholder.hooks.d.ts +4 -1
- package/dist/react/features/chat-pane/hooks/useChatPaneComposerPlaceholder.hooks.js +1 -1
- package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.js +30 -30
- package/dist/react/features/chat-pane/hooks/useChatPaneWorkingDirectory.hooks.js +57 -57
- package/dist/react/features/chat-pane/rules.d.ts +13 -4
- package/dist/react/features/chat-pane/rules.js +5 -5
- package/dist/react/features/chat-pane/types.d.ts +1 -1
- package/dist/react/hooks/attachment-preview-cache.d.ts +7 -2
- package/dist/react/hooks/attachment-preview-cache.js +2 -2
- package/dist/react/hooks/composer-draft-cache.d.ts +17 -5
- package/dist/react/hooks/composer-draft-cache.js +6 -6
- package/dist/react/hooks/useArtifactStream.d.ts +5 -1
- package/dist/react/hooks/useArtifactStream.js +3 -3
- package/dist/react/hooks/useChatFabDrag.d.ts +9 -4
- package/dist/react/hooks/useChatFabDrag.js +4 -4
- package/dist/react/hooks/useComposer.js +8 -8
- package/dist/react/hooks/useConversation.js +56 -4
- package/dist/react/hooks/useExtEventGroups.d.ts +5 -1
- package/dist/react/hooks/useExtEventGroups.js +1 -1
- package/dist/react/hooks/useLatestOperation.d.ts +8 -3
- package/dist/react/hooks/useLatestOperation.js +4 -4
- package/dist/react/hooks/usePinnedTodos.d.ts +3 -1
- package/dist/react/hooks/usePinnedTodos.js +3 -3
- package/dist/react/hooks/useQuestionForms.d.ts +7 -2
- package/dist/react/hooks/useQuestionForms.js +7 -7
- package/dist/react/hooks/useRunActivity.d.ts +6 -1
- package/dist/react/hooks/useRunActivity.js +3 -3
- package/dist/react/hooks/useRunStream.d.ts +3 -1
- package/dist/react/hooks/useRunStream.js +1 -1
- package/dist/react/hooks/useToolTimeline.d.ts +3 -1
- package/dist/react/hooks/useToolTimeline.js +3 -3
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +6 -6
- package/dist/react/message-blocks.d.ts +10 -4
- package/dist/react/message-blocks.js +2 -2
- package/dist/react/styles/reference.css +3 -3
- package/dist/react/tool-renderer-registry.d.ts +8 -3
- package/dist/react/tool-renderer-registry.js +3 -3
- package/dist/react/util/defined-props.d.ts +3 -1
- package/dist/react/util/defined-props.js +1 -1
- package/dist/server/run-finalizer/entry.d.ts +47 -0
- package/dist/server/run-finalizer/entry.js +156 -0
- package/dist/server/run-finalizer/ports.d.ts +52 -0
- package/dist/store/contracts/index.d.ts +5 -0
- package/dist/store/contracts/index.js +5 -0
- package/dist/store/errors.d.ts +12 -0
- package/dist/store/errors.js +18 -0
- package/dist/store/index.d.ts +4 -0
- package/dist/store/index.js +2 -0
- package/dist/store/legacy/index.d.ts +3 -0
- package/dist/store/legacy/index.js +2 -0
- package/dist/store/legacy/sqlite/conversations.d.ts +129 -0
- package/dist/store/legacy/sqlite/conversations.js +274 -0
- package/dist/store/legacy/sqlite/index.d.ts +6 -0
- package/dist/store/legacy/sqlite/index.js +5 -0
- package/dist/store/legacy/sqlite/messages.d.ts +156 -0
- package/dist/store/legacy/sqlite/messages.js +246 -0
- package/dist/store/legacy/sqlite/schema.d.ts +3 -0
- package/dist/store/legacy/sqlite/schema.js +40 -0
- package/dist/store/pglite/index.d.ts +21 -0
- package/dist/store/pglite/index.js +17 -0
- package/dist/store/ports.d.ts +121 -0
- package/dist/store/ports.js +2 -0
- package/dist/store/postgres/index.d.ts +21 -0
- package/dist/store/postgres/index.js +17 -0
- package/dist/store/sql/boundary.d.ts +28 -0
- package/dist/store/sql/boundary.js +32 -0
- package/dist/store/sql/cursor.d.ts +24 -0
- package/dist/store/sql/cursor.js +49 -0
- package/dist/store/sql/maintenance.d.ts +9 -0
- package/dist/store/sql/maintenance.js +16 -0
- package/dist/store/sql/store.d.ts +22 -0
- package/dist/store/sql/store.js +340 -0
- package/dist/store/sql/tables.d.ts +34 -0
- package/dist/store/sql/tables.js +2 -0
- package/dist/store/sqlite/index.d.ts +36 -0
- package/dist/store/sqlite/index.js +29 -0
- package/dist/store/sqlite/schema.d.ts +49 -0
- package/dist/store/sqlite/schema.js +80 -0
- package/package.json +211 -14
- package/dist/react/features/model-picker/components/CredentialStatusBadge.d.ts +0 -7
- package/dist/react/features/model-picker/components/CredentialStatusBadge.js +0 -20
- package/dist/react/features/model-picker/components/ModelPicker.d.ts +0 -9
- package/dist/react/features/model-picker/components/ModelPicker.js +0 -34
- package/dist/react/features/model-picker/constants.d.ts +0 -6
- package/dist/react/features/model-picker/constants.js +0 -9
- package/dist/react/features/model-picker/dependencies.d.ts +0 -11
- package/dist/react/features/model-picker/dependencies.js +0 -10
- package/dist/react/features/model-picker/hooks/useModelPicker.hooks.d.ts +0 -27
- package/dist/react/features/model-picker/hooks/useModelPicker.hooks.js +0 -62
- package/dist/react/features/model-picker/index.d.ts +0 -32
- package/dist/react/features/model-picker/index.js +0 -29
- package/dist/react/features/model-picker/ports.d.ts +0 -11
- package/dist/react/features/model-picker/rules.d.ts +0 -26
- package/dist/react/features/model-picker/rules.js +0 -84
- package/dist/react/features/model-picker/types.d.ts +0 -38
- package/dist/react/features/model-picker/types.js +0 -2
- package/dist/react/poc-mcp-ui-official/PocMcpUiCard.d.ts +0 -9
- package/dist/react/poc-mcp-ui-official/PocMcpUiCard.js +0 -29
- package/dist/react/poc-mcp-ui-official/create-poc-resource.d.ts +0 -30
- package/dist/react/poc-mcp-ui-official/create-poc-resource.js +0 -44
- /package/dist/{react/features/model-picker → server/run-finalizer}/ports.js +0 -0
|
@@ -34,8 +34,8 @@ export function useChatPaneRuntimeInventory({ access, initialAgents = EMPTY_AGEN
|
|
|
34
34
|
const [connectingAgents, setConnectingAgents] = useState(false);
|
|
35
35
|
const [daemonOnline, setDaemonOnline] = useState(false);
|
|
36
36
|
const [runtimeInventoryError, setRuntimeInventoryError] = useState(null);
|
|
37
|
-
const inventory = useLatestOperation();
|
|
38
|
-
const health = useLatestOperation();
|
|
37
|
+
const inventory = useLatestOperation({});
|
|
38
|
+
const health = useLatestOperation({});
|
|
39
39
|
const retry = useInventoryRetry(retryDelaysMs);
|
|
40
40
|
useEffect(() => {
|
|
41
41
|
if (access !== undefined)
|
|
@@ -53,24 +53,24 @@ export function useChatPaneRuntimeInventory({ access, initialAgents = EMPTY_AGEN
|
|
|
53
53
|
retry.cancel();
|
|
54
54
|
setScanningAgents(true);
|
|
55
55
|
setRuntimeInventoryError(null);
|
|
56
|
-
await inventory.run(async (token) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
56
|
+
await inventory.run({ body: async (token) => {
|
|
57
|
+
const nextAgents = await (rescan ? access.rescanAgents() : access.listAgents());
|
|
58
|
+
token.ensureCurrent();
|
|
59
|
+
retry.answered();
|
|
60
|
+
setAgents([...nextAgents]);
|
|
61
|
+
setConnectingAgents(false);
|
|
62
|
+
setScanningAgents(false);
|
|
63
|
+
}, onError: (error) => {
|
|
64
|
+
// A failed load after a good answer keeps that inventory on screen. Before one there is no
|
|
65
|
+
// last-good to keep: clear to empty, report "connecting", and try again on the backoff.
|
|
66
|
+
if (!retry.hasAnswer()) {
|
|
67
|
+
setAgents([]);
|
|
68
|
+
setConnectingAgents(true);
|
|
69
|
+
retry.schedule(() => void loadAgents(false));
|
|
70
|
+
}
|
|
71
|
+
setRuntimeInventoryError(error);
|
|
72
|
+
setScanningAgents(false);
|
|
73
|
+
} });
|
|
74
74
|
}, [access, inventory, retry]);
|
|
75
75
|
/** A fresh attempt now, with the backoff restarted — only while nothing has answered yet. */
|
|
76
76
|
const reloadIfUnanswered = useCallback(() => {
|
|
@@ -86,16 +86,16 @@ export function useChatPaneRuntimeInventory({ access, initialAgents = EMPTY_AGEN
|
|
|
86
86
|
// below) all sit behind their own `if (!access) return` — `access` is guaranteed defined by
|
|
87
87
|
// the time any one runs.
|
|
88
88
|
const runtimeAccess = access;
|
|
89
|
-
await health.run(async (token) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
await health.run({ body: async (token) => {
|
|
90
|
+
const online = await runtimeAccess.daemonOnline();
|
|
91
|
+
token.ensureCurrent();
|
|
92
|
+
setDaemonOnline(online);
|
|
93
|
+
if (retry.observeOnline(online))
|
|
94
|
+
reloadIfUnanswered();
|
|
95
|
+
}, onError: () => {
|
|
96
|
+
retry.observeOnline(false);
|
|
97
|
+
setDaemonOnline(false);
|
|
98
|
+
} });
|
|
99
99
|
}, [access, health, reloadIfUnanswered, retry]);
|
|
100
100
|
useEffect(() => {
|
|
101
101
|
if (!access)
|
|
@@ -25,7 +25,7 @@ export function useChatPaneWorkingDirectory(options) {
|
|
|
25
25
|
const [workingDirectoryInvalid, setWorkingDirectoryInvalid] = useState(false);
|
|
26
26
|
const [workingDirectoryPending, setWorkingDirectoryPending] = useState(false);
|
|
27
27
|
const [workingDirectoryError, setWorkingDirectoryError] = useState(null);
|
|
28
|
-
const operation = useLatestOperation();
|
|
28
|
+
const operation = useLatestOperation({});
|
|
29
29
|
const observedDirectoryRef = useRef(undefined);
|
|
30
30
|
const workingDirectory = controlled
|
|
31
31
|
? options.workingDirectory ?? null
|
|
@@ -55,29 +55,29 @@ export function useChatPaneWorkingDirectory(options) {
|
|
|
55
55
|
}
|
|
56
56
|
let validationSettled = false;
|
|
57
57
|
setWorkingDirectoryPending(true);
|
|
58
|
-
void operation.run(async (token) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
void operation.run({ body: async (token) => {
|
|
59
|
+
const normalized = access.normalizeWorkingDirectory
|
|
60
|
+
? await access.normalizeWorkingDirectory(workingDirectory)
|
|
61
|
+
: workingDirectory;
|
|
62
|
+
token.ensureCurrent();
|
|
63
|
+
if (normalized === null) {
|
|
64
|
+
validationSettled = true;
|
|
65
|
+
setWorkingDirectoryInvalid(true);
|
|
66
|
+
setWorkingDirectoryPending(false);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const exists = await access.directoryExists(normalized);
|
|
70
|
+
token.ensureCurrent();
|
|
71
|
+
if (normalized !== workingDirectory)
|
|
72
|
+
reportWorkingDirectory(normalized);
|
|
64
73
|
validationSettled = true;
|
|
65
|
-
setWorkingDirectoryInvalid(
|
|
74
|
+
setWorkingDirectoryInvalid(!exists);
|
|
66
75
|
setWorkingDirectoryPending(false);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
reportWorkingDirectory(normalized);
|
|
73
|
-
validationSettled = true;
|
|
74
|
-
setWorkingDirectoryInvalid(!exists);
|
|
75
|
-
setWorkingDirectoryPending(false);
|
|
76
|
-
}, (error) => {
|
|
77
|
-
validationSettled = true;
|
|
78
|
-
setWorkingDirectoryInvalid(true);
|
|
79
|
-
reportFailure(error);
|
|
80
|
-
});
|
|
76
|
+
}, onError: (error) => {
|
|
77
|
+
validationSettled = true;
|
|
78
|
+
setWorkingDirectoryInvalid(true);
|
|
79
|
+
reportFailure(error);
|
|
80
|
+
} });
|
|
81
81
|
return () => {
|
|
82
82
|
operation.supersede();
|
|
83
83
|
// React Strict Mode replays this effect while preserving refs. Release
|
|
@@ -102,18 +102,18 @@ export function useChatPaneWorkingDirectory(options) {
|
|
|
102
102
|
return;
|
|
103
103
|
setWorkingDirectoryError(null);
|
|
104
104
|
setWorkingDirectoryPending(true);
|
|
105
|
-
await operation.run(async (token) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
105
|
+
await operation.run({ body: async (token) => {
|
|
106
|
+
const [recent, exists] = await Promise.all([
|
|
107
|
+
access.recentDirectories(),
|
|
108
|
+
workingDirectory === null
|
|
109
|
+
? Promise.resolve(true)
|
|
110
|
+
: access.directoryExists(workingDirectory),
|
|
111
|
+
]);
|
|
112
|
+
token.ensureCurrent();
|
|
113
|
+
setRecentDirectories([...recent]);
|
|
114
|
+
setWorkingDirectoryInvalid(!exists);
|
|
115
|
+
setWorkingDirectoryPending(false);
|
|
116
|
+
}, onError: reportFailure });
|
|
117
117
|
}, [operation, options.workingDirectoryAccess, reportFailure, workingDirectory]);
|
|
118
118
|
const pickWorkingDirectory = useCallback(async () => {
|
|
119
119
|
const access = options.workingDirectoryAccess;
|
|
@@ -121,23 +121,23 @@ export function useChatPaneWorkingDirectory(options) {
|
|
|
121
121
|
return;
|
|
122
122
|
setWorkingDirectoryError(null);
|
|
123
123
|
setWorkingDirectoryPending(true);
|
|
124
|
-
await operation.run(async (token) => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
await operation.run({ body: async (token) => {
|
|
125
|
+
const selected = await access.pickWorkingDirectory(workingDirectory ?? undefined);
|
|
126
|
+
token.ensureCurrent();
|
|
127
|
+
if (selected === null) {
|
|
128
|
+
setWorkingDirectoryPending(false);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const [exists, recent] = await Promise.all([
|
|
132
|
+
access.directoryExists(selected),
|
|
133
|
+
access.recentDirectories(),
|
|
134
|
+
]);
|
|
135
|
+
token.ensureCurrent();
|
|
136
|
+
reportWorkingDirectory(selected);
|
|
137
|
+
setWorkingDirectoryInvalid(!exists);
|
|
138
|
+
setRecentDirectories([...recent]);
|
|
128
139
|
setWorkingDirectoryPending(false);
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
const [exists, recent] = await Promise.all([
|
|
132
|
-
access.directoryExists(selected),
|
|
133
|
-
access.recentDirectories(),
|
|
134
|
-
]);
|
|
135
|
-
token.ensureCurrent();
|
|
136
|
-
reportWorkingDirectory(selected);
|
|
137
|
-
setWorkingDirectoryInvalid(!exists);
|
|
138
|
-
setRecentDirectories([...recent]);
|
|
139
|
-
setWorkingDirectoryPending(false);
|
|
140
|
-
}, reportFailure);
|
|
140
|
+
}, onError: reportFailure });
|
|
141
141
|
}, [
|
|
142
142
|
operation,
|
|
143
143
|
options.workingDirectoryAccess,
|
|
@@ -154,13 +154,13 @@ export function useChatPaneWorkingDirectory(options) {
|
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
156
156
|
setWorkingDirectoryPending(true);
|
|
157
|
-
await operation.run(async (token) => {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
await operation.run({ body: async (token) => {
|
|
158
|
+
const exists = await access.directoryExists(directory);
|
|
159
|
+
token.ensureCurrent();
|
|
160
|
+
reportWorkingDirectory(directory);
|
|
161
|
+
setWorkingDirectoryInvalid(!exists);
|
|
162
|
+
setWorkingDirectoryPending(false);
|
|
163
|
+
}, onError: reportFailure });
|
|
164
164
|
}, [operation, options.workingDirectoryAccess, reportFailure, reportWorkingDirectory]);
|
|
165
165
|
const clearWorkingDirectory = useCallback(() => {
|
|
166
166
|
operation.supersede();
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { ByokRuntimeSummary, ChatPaneAgent, ChatPaneAgentSelection } from './types.js';
|
|
2
|
-
export declare function defaultChatPaneSelection(agent
|
|
3
|
-
|
|
2
|
+
export declare function defaultChatPaneSelection({ agent }: {
|
|
3
|
+
agent: ChatPaneAgent;
|
|
4
|
+
}): ChatPaneAgentSelection;
|
|
5
|
+
export declare function resolveChatPaneSelection({ agents, requested }: {
|
|
6
|
+
agents: readonly ChatPaneAgent[];
|
|
7
|
+
requested: ChatPaneAgentSelection;
|
|
8
|
+
}): ChatPaneAgentSelection;
|
|
4
9
|
/**
|
|
5
10
|
* Why a send would be refused, or `null` when the pane is ready to send.
|
|
6
11
|
*
|
|
@@ -63,6 +68,10 @@ export declare function describeChatPaneSendBlocker(blocker: ChatPaneSendBlocker
|
|
|
63
68
|
* those are clear. A flush path must therefore wait for a fully `null` blocker before sending,
|
|
64
69
|
* not merely for streaming to end.
|
|
65
70
|
*/
|
|
66
|
-
export declare function isChatPaneQueueableBlocker(blocker
|
|
67
|
-
|
|
71
|
+
export declare function isChatPaneQueueableBlocker({ blocker }: {
|
|
72
|
+
blocker: ChatPaneSendBlocker | null;
|
|
73
|
+
}): boolean;
|
|
74
|
+
export declare function orderChatPaneAgents({ agents }: {
|
|
75
|
+
agents: readonly ChatPaneAgent[];
|
|
76
|
+
}): ChatPaneAgent[];
|
|
68
77
|
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -6,7 +6,7 @@ function validatedOptionId(options, requested, fallback) {
|
|
|
6
6
|
return requested;
|
|
7
7
|
return fallback;
|
|
8
8
|
}
|
|
9
|
-
export function defaultChatPaneSelection(agent) {
|
|
9
|
+
export function defaultChatPaneSelection({ agent }) {
|
|
10
10
|
const model = preferredOptionId(agent.models);
|
|
11
11
|
const reasoning = preferredOptionId(agent.reasoningOptions);
|
|
12
12
|
return {
|
|
@@ -15,12 +15,12 @@ export function defaultChatPaneSelection(agent) {
|
|
|
15
15
|
...(reasoning === undefined ? {} : { reasoning }),
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
-
export function resolveChatPaneSelection(agents, requested) {
|
|
18
|
+
export function resolveChatPaneSelection({ agents, requested }) {
|
|
19
19
|
const requestedAgent = agents.find((agent) => agent.id === requested.agentId && agent.available !== false);
|
|
20
20
|
const agent = requestedAgent ?? agents.find((candidate) => candidate.available !== false);
|
|
21
21
|
if (!agent)
|
|
22
22
|
return { agentId: '' };
|
|
23
|
-
const defaults = defaultChatPaneSelection(agent);
|
|
23
|
+
const defaults = defaultChatPaneSelection({ agent: agent });
|
|
24
24
|
if (agent !== requestedAgent)
|
|
25
25
|
return defaults;
|
|
26
26
|
const model = requested.model
|
|
@@ -102,10 +102,10 @@ export function describeChatPaneSendBlocker(blocker) {
|
|
|
102
102
|
* those are clear. A flush path must therefore wait for a fully `null` blocker before sending,
|
|
103
103
|
* not merely for streaming to end.
|
|
104
104
|
*/
|
|
105
|
-
export function isChatPaneQueueableBlocker(blocker) {
|
|
105
|
+
export function isChatPaneQueueableBlocker({ blocker }) {
|
|
106
106
|
return blocker === 'streaming';
|
|
107
107
|
}
|
|
108
|
-
export function orderChatPaneAgents(agents) {
|
|
108
|
+
export function orderChatPaneAgents({ agents }) {
|
|
109
109
|
return [...agents].sort((left, right) => {
|
|
110
110
|
const availability = Number(left.available === false) - Number(right.available === false);
|
|
111
111
|
return availability
|
|
@@ -22,7 +22,7 @@ export interface ChatPaneAgent {
|
|
|
22
22
|
supportsCustomModel?: boolean;
|
|
23
23
|
diagnostic?: string;
|
|
24
24
|
/**
|
|
25
|
-
* Whether this runtime can receive external MCP servers (
|
|
25
|
+
* Whether this runtime can receive external MCP servers (host/Jini tools) at all — mirrors
|
|
26
26
|
* `@jini-ai/http-kit`'s `AgentSummary.supportsTools`, itself derived from
|
|
27
27
|
* `@jini-ai/agent-runtime`'s `runtimeSupportsExternalTools(def)`. `AgentRuntimePicker` reads this
|
|
28
28
|
* to show a "No tools" badge; `undefined` (a host on an older wire payload) is treated the same
|
|
@@ -34,14 +34,19 @@ export declare const MAX_CACHED_ATTACHMENT_PREVIEWS = 50;
|
|
|
34
34
|
* if this would introduce a new entry past {@link MAX_CACHED_ATTACHMENT_PREVIEWS}.
|
|
35
35
|
* @complexity Time/space: O(1) amortized.
|
|
36
36
|
*/
|
|
37
|
-
export declare function cacheAttachmentPreviewSource(path
|
|
37
|
+
export declare function cacheAttachmentPreviewSource({ path, file }: {
|
|
38
|
+
path: string;
|
|
39
|
+
file: File;
|
|
40
|
+
}): void;
|
|
38
41
|
/**
|
|
39
42
|
* Reads back the `File` cached for `path`, or `undefined` when this browser never staged it (a
|
|
40
43
|
* different session, a reload, or eviction past the cap) - the only signal a preview needs to fall
|
|
41
44
|
* back to an honest metadata view instead of pretending to render content it does not have.
|
|
42
45
|
* @complexity Time/space: O(1).
|
|
43
46
|
*/
|
|
44
|
-
export declare function getAttachmentPreviewSource(path
|
|
47
|
+
export declare function getAttachmentPreviewSource({ path }: {
|
|
48
|
+
path: string;
|
|
49
|
+
}): File | undefined;
|
|
45
50
|
/** Test-only: empties the module-level cache so test cases cannot leak attachments into each other. */
|
|
46
51
|
export declare function __resetAttachmentPreviewCacheForTests(): void;
|
|
47
52
|
//# sourceMappingURL=attachment-preview-cache.d.ts.map
|
|
@@ -35,7 +35,7 @@ const sources = new Map();
|
|
|
35
35
|
* if this would introduce a new entry past {@link MAX_CACHED_ATTACHMENT_PREVIEWS}.
|
|
36
36
|
* @complexity Time/space: O(1) amortized.
|
|
37
37
|
*/
|
|
38
|
-
export function cacheAttachmentPreviewSource(path, file) {
|
|
38
|
+
export function cacheAttachmentPreviewSource({ path, file }) {
|
|
39
39
|
if (!sources.has(path) && sources.size >= MAX_CACHED_ATTACHMENT_PREVIEWS) {
|
|
40
40
|
const oldest = sources.keys().next().value;
|
|
41
41
|
if (oldest !== undefined)
|
|
@@ -49,7 +49,7 @@ export function cacheAttachmentPreviewSource(path, file) {
|
|
|
49
49
|
* back to an honest metadata view instead of pretending to render content it does not have.
|
|
50
50
|
* @complexity Time/space: O(1).
|
|
51
51
|
*/
|
|
52
|
-
export function getAttachmentPreviewSource(path) {
|
|
52
|
+
export function getAttachmentPreviewSource({ path }) {
|
|
53
53
|
return sources.get(path);
|
|
54
54
|
}
|
|
55
55
|
/** Test-only: empties the module-level cache so test cases cannot leak attachments into each other. */
|
|
@@ -72,7 +72,9 @@ export declare const COMPOSER_ATTACHMENTS_STORAGE_PREFIX = "jini.chat.composer-a
|
|
|
72
72
|
* treat `null` as "nothing to restore".
|
|
73
73
|
* @complexity Time/space: O(1) on an in-memory hit, O(n) in the stored draft's length otherwise.
|
|
74
74
|
*/
|
|
75
|
-
export declare function readCachedDraft(conversationId
|
|
75
|
+
export declare function readCachedDraft({ conversationId }: {
|
|
76
|
+
conversationId: string | null | undefined;
|
|
77
|
+
}): string | null;
|
|
76
78
|
/**
|
|
77
79
|
* Stores `draft` for `conversationId` in both tiers.
|
|
78
80
|
*
|
|
@@ -83,7 +85,10 @@ export declare function readCachedDraft(conversationId: string | null | undefine
|
|
|
83
85
|
* writes `''` here.
|
|
84
86
|
* @complexity Time/space: O(n) in the draft's length; see {@link writeStoredDraft}.
|
|
85
87
|
*/
|
|
86
|
-
export declare function writeCachedDraft(conversationId
|
|
88
|
+
export declare function writeCachedDraft({ conversationId, draft }: {
|
|
89
|
+
conversationId: string | null | undefined;
|
|
90
|
+
draft: string;
|
|
91
|
+
}): void;
|
|
87
92
|
/**
|
|
88
93
|
* Explicitly evicts `conversationId`'s draft from both tiers, for a host that wants to free it
|
|
89
94
|
* immediately (e.g. on conversation delete) rather than waiting for the cap-triggered eviction.
|
|
@@ -91,7 +96,9 @@ export declare function writeCachedDraft(conversationId: string | null | undefin
|
|
|
91
96
|
* follow-up caller, out of scope here (that flow lives outside this package).
|
|
92
97
|
* @complexity Time/space: O(1).
|
|
93
98
|
*/
|
|
94
|
-
export declare function clearCachedDraft(conversationId
|
|
99
|
+
export declare function clearCachedDraft({ conversationId }: {
|
|
100
|
+
conversationId: string | null | undefined;
|
|
101
|
+
}): void;
|
|
95
102
|
/**
|
|
96
103
|
* Reads the cached attachment references for `conversationId`, in memory first, storage second.
|
|
97
104
|
*
|
|
@@ -105,7 +112,9 @@ export declare function clearCachedDraft(conversationId: string | null | undefin
|
|
|
105
112
|
* @returns The cached references, or `null` when there are none.
|
|
106
113
|
* @complexity Time/space: O(1) on an in-memory hit, O(n) in the stored count otherwise.
|
|
107
114
|
*/
|
|
108
|
-
export declare function readCachedAttachments(conversationId
|
|
115
|
+
export declare function readCachedAttachments({ conversationId }: {
|
|
116
|
+
conversationId: string | null | undefined;
|
|
117
|
+
}): readonly ChatAttachment[] | null;
|
|
109
118
|
/**
|
|
110
119
|
* Stores `attachments` for `conversationId` in both tiers.
|
|
111
120
|
*
|
|
@@ -113,7 +122,10 @@ export declare function readCachedAttachments(conversationId: string | null | un
|
|
|
113
122
|
* restore — the same rule the draft text follows.
|
|
114
123
|
* @complexity Time/space: O(n) in the number of references.
|
|
115
124
|
*/
|
|
116
|
-
export declare function writeCachedAttachments(conversationId
|
|
125
|
+
export declare function writeCachedAttachments({ conversationId, attachments }: {
|
|
126
|
+
conversationId: string | null | undefined;
|
|
127
|
+
attachments: readonly ChatAttachment[];
|
|
128
|
+
}): void;
|
|
117
129
|
/**
|
|
118
130
|
* Test-only: empties the cache so test cases cannot leak drafts into each other.
|
|
119
131
|
*
|
|
@@ -210,7 +210,7 @@ function rememberInMemory(conversationId, draft) {
|
|
|
210
210
|
* treat `null` as "nothing to restore".
|
|
211
211
|
* @complexity Time/space: O(1) on an in-memory hit, O(n) in the stored draft's length otherwise.
|
|
212
212
|
*/
|
|
213
|
-
export function readCachedDraft(conversationId) {
|
|
213
|
+
export function readCachedDraft({ conversationId }) {
|
|
214
214
|
if (!conversationId)
|
|
215
215
|
return null;
|
|
216
216
|
const remembered = drafts.get(conversationId);
|
|
@@ -232,7 +232,7 @@ export function readCachedDraft(conversationId) {
|
|
|
232
232
|
* writes `''` here.
|
|
233
233
|
* @complexity Time/space: O(n) in the draft's length; see {@link writeStoredDraft}.
|
|
234
234
|
*/
|
|
235
|
-
export function writeCachedDraft(conversationId, draft) {
|
|
235
|
+
export function writeCachedDraft({ conversationId, draft }) {
|
|
236
236
|
if (!conversationId)
|
|
237
237
|
return;
|
|
238
238
|
if (draft.trim() === '') {
|
|
@@ -250,12 +250,12 @@ export function writeCachedDraft(conversationId, draft) {
|
|
|
250
250
|
* follow-up caller, out of scope here (that flow lives outside this package).
|
|
251
251
|
* @complexity Time/space: O(1).
|
|
252
252
|
*/
|
|
253
|
-
export function clearCachedDraft(conversationId) {
|
|
253
|
+
export function clearCachedDraft({ conversationId }) {
|
|
254
254
|
if (!conversationId)
|
|
255
255
|
return;
|
|
256
256
|
drafts.delete(conversationId);
|
|
257
257
|
writeStoredDraft(conversationId, '');
|
|
258
|
-
writeCachedAttachments(conversationId, []);
|
|
258
|
+
writeCachedAttachments({ conversationId: conversationId, attachments: [] });
|
|
259
259
|
}
|
|
260
260
|
/**
|
|
261
261
|
* Narrows one parsed array element to a `ChatAttachment`.
|
|
@@ -336,7 +336,7 @@ function readStoredAttachments(conversationId) {
|
|
|
336
336
|
* @returns The cached references, or `null` when there are none.
|
|
337
337
|
* @complexity Time/space: O(1) on an in-memory hit, O(n) in the stored count otherwise.
|
|
338
338
|
*/
|
|
339
|
-
export function readCachedAttachments(conversationId) {
|
|
339
|
+
export function readCachedAttachments({ conversationId }) {
|
|
340
340
|
if (!conversationId)
|
|
341
341
|
return null;
|
|
342
342
|
const remembered = stagedAttachments.get(conversationId);
|
|
@@ -355,7 +355,7 @@ export function readCachedAttachments(conversationId) {
|
|
|
355
355
|
* restore — the same rule the draft text follows.
|
|
356
356
|
* @complexity Time/space: O(n) in the number of references.
|
|
357
357
|
*/
|
|
358
|
-
export function writeCachedAttachments(conversationId, attachments) {
|
|
358
|
+
export function writeCachedAttachments({ conversationId, attachments }) {
|
|
359
359
|
if (!conversationId)
|
|
360
360
|
return;
|
|
361
361
|
const key = `${COMPOSER_ATTACHMENTS_STORAGE_PREFIX}${conversationId}`;
|
|
@@ -14,5 +14,9 @@ export interface UseArtifactStreamResult {
|
|
|
14
14
|
/** The last item — the one most likely to be "the artifact this turn produced". */
|
|
15
15
|
current: ArtifactStreamItem | null;
|
|
16
16
|
}
|
|
17
|
-
export declare function useArtifactStream(content
|
|
17
|
+
export declare function useArtifactStream({ content }: {
|
|
18
|
+
content: string;
|
|
19
|
+
}, { registry }?: {
|
|
20
|
+
registry?: (RendererRegistry) | undefined;
|
|
21
|
+
}): UseArtifactStreamResult;
|
|
18
22
|
//# sourceMappingURL=useArtifactStream.d.ts.map
|
|
@@ -17,7 +17,7 @@ import { parseArtifacts, splitStreamingArtifact } from '../../core/index.js';
|
|
|
17
17
|
function toFile(item) {
|
|
18
18
|
return { name: item.identifier || item.title || 'artifact', kind: item.artifactType, content: item.content };
|
|
19
19
|
}
|
|
20
|
-
export function useArtifactStream(content, registry) {
|
|
20
|
+
export function useArtifactStream({ content }, { registry } = {}) {
|
|
21
21
|
return useMemo(() => {
|
|
22
22
|
const items = [];
|
|
23
23
|
// `splitStreamingArtifact` is the authority on "is there a trailing,
|
|
@@ -28,9 +28,9 @@ export function useArtifactStream(content, registry) {
|
|
|
28
28
|
// Running it on the raw `content` would double-count a live artifact:
|
|
29
29
|
// once (wrongly) as "complete" via the synthetic flush, and again (correctly)
|
|
30
30
|
// as "streaming" below.
|
|
31
|
-
const { head, live } = splitStreamingArtifact(content);
|
|
31
|
+
const { head, live } = splitStreamingArtifact({ content: content });
|
|
32
32
|
let current = null;
|
|
33
|
-
for (const ev of parseArtifacts(head)) {
|
|
33
|
+
for (const ev of parseArtifacts({ content: head })) {
|
|
34
34
|
if (ev.type === 'artifact:start') {
|
|
35
35
|
current = { identifier: ev.identifier, artifactType: ev.artifactType, title: ev.title, content: '' };
|
|
36
36
|
}
|
|
@@ -17,9 +17,14 @@ export interface UseChatFabDragResult {
|
|
|
17
17
|
onPointerCancel: (event: ReactPointerEvent<HTMLButtonElement>) => void;
|
|
18
18
|
}
|
|
19
19
|
/** Keeps a dragged position fully on screen, re-clamped on drag and on viewport resize. */
|
|
20
|
-
export declare function clampChatFabToViewport(position
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
export declare function clampChatFabToViewport({ position, size }: {
|
|
21
|
+
position: ChatFabPosition;
|
|
22
|
+
size: {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
};
|
|
23
26
|
}): ChatFabPosition;
|
|
24
|
-
export declare function useChatFabDrag(onClick
|
|
27
|
+
export declare function useChatFabDrag({ onClick }: {
|
|
28
|
+
onClick: () => void;
|
|
29
|
+
}): UseChatFabDragResult;
|
|
25
30
|
//# sourceMappingURL=useChatFabDrag.d.ts.map
|
|
@@ -13,7 +13,7 @@ export const CHAT_FAB_DRAG_THRESHOLD_PX = 4;
|
|
|
13
13
|
/** Keeps the button fully on screen with a small margin. */
|
|
14
14
|
export const CHAT_FAB_EDGE_MARGIN_PX = 8;
|
|
15
15
|
/** Keeps a dragged position fully on screen, re-clamped on drag and on viewport resize. */
|
|
16
|
-
export function clampChatFabToViewport(position, size) {
|
|
16
|
+
export function clampChatFabToViewport({ position, size }) {
|
|
17
17
|
const maxX = Math.max(CHAT_FAB_EDGE_MARGIN_PX, globalThis.innerWidth - size.width - CHAT_FAB_EDGE_MARGIN_PX);
|
|
18
18
|
const maxY = Math.max(CHAT_FAB_EDGE_MARGIN_PX, globalThis.innerHeight - size.height - CHAT_FAB_EDGE_MARGIN_PX);
|
|
19
19
|
return {
|
|
@@ -21,7 +21,7 @@ export function clampChatFabToViewport(position, size) {
|
|
|
21
21
|
y: Math.min(Math.max(position.y, CHAT_FAB_EDGE_MARGIN_PX), maxY),
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
export function useChatFabDrag(onClick) {
|
|
24
|
+
export function useChatFabDrag({ onClick }) {
|
|
25
25
|
const buttonRef = useRef(null);
|
|
26
26
|
const [position, setPosition] = useState(null);
|
|
27
27
|
const drag = useRef(null);
|
|
@@ -32,7 +32,7 @@ export function useChatFabDrag(onClick) {
|
|
|
32
32
|
return;
|
|
33
33
|
setPosition((current) => (current === null
|
|
34
34
|
? null
|
|
35
|
-
: clampChatFabToViewport(current, { width: element.offsetWidth, height: element.offsetHeight })));
|
|
35
|
+
: clampChatFabToViewport({ position: current, size: { width: element.offsetWidth, height: element.offsetHeight } })));
|
|
36
36
|
};
|
|
37
37
|
globalThis.addEventListener('resize', onResize);
|
|
38
38
|
return () => globalThis.removeEventListener('resize', onResize);
|
|
@@ -54,7 +54,7 @@ export function useChatFabDrag(onClick) {
|
|
|
54
54
|
if (state === null || state.pointerId !== event.pointerId)
|
|
55
55
|
return;
|
|
56
56
|
const element = event.currentTarget;
|
|
57
|
-
const next = clampChatFabToViewport({ x: event.clientX - state.offsetX, y: event.clientY - state.offsetY }, { width: element.offsetWidth, height: element.offsetHeight });
|
|
57
|
+
const next = clampChatFabToViewport({ position: { x: event.clientX - state.offsetX, y: event.clientY - state.offsetY }, size: { width: element.offsetWidth, height: element.offsetHeight } });
|
|
58
58
|
const rect = element.getBoundingClientRect();
|
|
59
59
|
if (Math.abs(next.x - rect.left) > CHAT_FAB_DRAG_THRESHOLD_PX || Math.abs(next.y - rect.top) > CHAT_FAB_DRAG_THRESHOLD_PX) {
|
|
60
60
|
state.moved = true;
|
|
@@ -33,14 +33,14 @@ import { cacheAttachmentPreviewSource } from './attachment-preview-cache.js';
|
|
|
33
33
|
const EMPTY_MENTION = { open: false, query: '', results: [] };
|
|
34
34
|
export function useComposer(options = {}) {
|
|
35
35
|
const { project, composerSlots, persistence, conversationId, validateAttachments } = options;
|
|
36
|
-
const [draft, setDraftState] = useState(() => options.initialDraft ?? persistence?.read() ?? readCachedDraft(conversationId) ?? '');
|
|
36
|
+
const [draft, setDraftState] = useState(() => options.initialDraft ?? persistence?.read() ?? readCachedDraft({ conversationId: conversationId }) ?? '');
|
|
37
37
|
const [attachments, setAttachments] = useState([]);
|
|
38
38
|
const [agent, setAgent] = useState(options.initialAgent);
|
|
39
39
|
const [mention, setMention] = useState(EMPTY_MENTION);
|
|
40
40
|
const setDraft = useCallback((next) => {
|
|
41
41
|
setDraftState(next);
|
|
42
42
|
persistence?.write(next);
|
|
43
|
-
writeCachedDraft(conversationId, next);
|
|
43
|
+
writeCachedDraft({ conversationId: conversationId, draft: next });
|
|
44
44
|
}, [persistence, conversationId]);
|
|
45
45
|
// Lets the conversation-change effect below read the live draft without taking `draft` as a
|
|
46
46
|
// dependency, which would re-run it on every keystroke.
|
|
@@ -57,7 +57,7 @@ export function useComposer(options = {}) {
|
|
|
57
57
|
if (conversationId === previousConversationIdRef.current)
|
|
58
58
|
return;
|
|
59
59
|
previousConversationIdRef.current = conversationId;
|
|
60
|
-
const restored = readCachedDraft(conversationId);
|
|
60
|
+
const restored = readCachedDraft({ conversationId: conversationId });
|
|
61
61
|
// An id arriving where there was none is NOT a switch between two conversations — it is the one
|
|
62
62
|
// the operator is already looking at finally getting a key (a new chat created server-side
|
|
63
63
|
// mid-compose, or a host that resolves the active id asynchronously after mount). Adopt what
|
|
@@ -68,7 +68,7 @@ export function useComposer(options = {}) {
|
|
|
68
68
|
// message into another. Attachments and the mention popover are left alone here for the same
|
|
69
69
|
// reason — nothing was switched away from.
|
|
70
70
|
if (previousConversationId == null && conversationId != null && restored === null && draftRef.current.trim() !== '') {
|
|
71
|
-
writeCachedDraft(conversationId, draftRef.current);
|
|
71
|
+
writeCachedDraft({ conversationId: conversationId, draft: draftRef.current });
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
74
|
setDraftState(restored ?? '');
|
|
@@ -93,7 +93,7 @@ export function useComposer(options = {}) {
|
|
|
93
93
|
attachmentsHydratedForRef.current = conversationId;
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
|
-
const cached = readCachedAttachments(conversationId);
|
|
96
|
+
const cached = readCachedAttachments({ conversationId: conversationId });
|
|
97
97
|
if (cached === null || cached.length === 0) {
|
|
98
98
|
attachmentsHydratedForRef.current = conversationId;
|
|
99
99
|
return;
|
|
@@ -118,7 +118,7 @@ export function useComposer(options = {}) {
|
|
|
118
118
|
}
|
|
119
119
|
else {
|
|
120
120
|
// Every reference was dead. Purge them so the next load does not pay for this again.
|
|
121
|
-
writeCachedAttachments(conversationId, []);
|
|
121
|
+
writeCachedAttachments({ conversationId: conversationId, attachments: [] });
|
|
122
122
|
}
|
|
123
123
|
attachmentsHydratedForRef.current = conversationId;
|
|
124
124
|
})();
|
|
@@ -135,7 +135,7 @@ export function useComposer(options = {}) {
|
|
|
135
135
|
return;
|
|
136
136
|
if (attachmentsHydratedForRef.current !== conversationId)
|
|
137
137
|
return;
|
|
138
|
-
writeCachedAttachments(conversationId, attachments);
|
|
138
|
+
writeCachedAttachments({ conversationId: conversationId, attachments: attachments });
|
|
139
139
|
}, [attachments, conversationId]);
|
|
140
140
|
const addAttachment = useCallback((attachment) => {
|
|
141
141
|
setAttachments((prev) => [...prev, attachment]);
|
|
@@ -157,7 +157,7 @@ export function useComposer(options = {}) {
|
|
|
157
157
|
uploaded.forEach((a, i) => {
|
|
158
158
|
const file = files[i];
|
|
159
159
|
if (file)
|
|
160
|
-
cacheAttachmentPreviewSource(a.path, file);
|
|
160
|
+
cacheAttachmentPreviewSource({ path: a.path, file });
|
|
161
161
|
});
|
|
162
162
|
for (const a of uploaded)
|
|
163
163
|
composerSlots?.onAttach?.(a);
|