@dxos/plugin-assistant 0.13.0 → 0.14.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/PLUGIN.mdl +25 -0
- package/dist/lib/AssistantCapabilities.mjs +8 -1
- package/dist/lib/AssistantCapabilities.mjs.map +1 -1
- package/dist/lib/Settings.mjs +4 -0
- package/dist/lib/Settings.mjs.map +1 -1
- package/dist/lib/TurnReviewSkill.mjs +55 -0
- package/dist/lib/TurnReviewSkill.mjs.map +1 -0
- package/dist/lib/chunk-AgentArticle.mjs +1 -1
- package/dist/lib/chunk-AssistantSettings.mjs +1 -1
- package/dist/lib/chunk-AssistantSettings.mjs.map +1 -1
- package/dist/lib/chunk-Chat.mjs +322 -174
- package/dist/lib/chunk-Chat.mjs.map +1 -1
- package/dist/lib/chunk-ChatArticle.mjs +14 -7
- package/dist/lib/chunk-ChatArticle.mjs.map +1 -1
- package/dist/lib/chunk-ChatDialog.mjs +5 -4
- package/dist/lib/chunk-ChatDialog.mjs.map +1 -1
- package/dist/lib/chunk-IntegrationPrompt.mjs +1 -1
- package/dist/lib/chunk-PLUGIN.mjs +1 -1
- package/dist/lib/chunk-PluginUrlPrompt.mjs +1 -1
- package/dist/lib/chunk-QuestionSurface.mjs +1 -1
- package/dist/lib/chunk-SpaceHomePrompt.mjs +116 -60
- package/dist/lib/chunk-SpaceHomePrompt.mjs.map +1 -1
- package/dist/lib/chunk-TriggerStatus.mjs +1 -1
- package/dist/lib/chunk-agent-service.mjs +3 -1
- package/dist/lib/chunk-agent-service.mjs.map +1 -1
- package/dist/lib/chunk-analyze-turn.mjs +220 -0
- package/dist/lib/chunk-analyze-turn.mjs.map +1 -0
- package/dist/lib/{chunk-processor.mjs → chunk-chat-model.mjs} +95 -43
- package/dist/lib/chunk-chat-model.mjs.map +1 -0
- package/dist/lib/chunk-context.mjs.map +1 -1
- package/dist/lib/chunk-create-chat.mjs +5 -19
- package/dist/lib/chunk-create-chat.mjs.map +1 -1
- package/dist/lib/chunk-create-object.mjs +1 -1
- package/dist/lib/chunk-default-skills.mjs +28 -0
- package/dist/lib/chunk-default-skills.mjs.map +1 -0
- package/dist/lib/chunk-generate-home-suggestions.mjs +8 -6
- package/dist/lib/chunk-generate-home-suggestions.mjs.map +1 -1
- package/dist/lib/chunk-presets.mjs +1 -1
- package/dist/lib/chunk-presets.mjs.map +1 -1
- package/dist/lib/chunk-question-resumer.mjs +1 -1
- package/dist/lib/chunk-react-surface.mjs +1 -1
- package/dist/lib/chunk-run-prompt-in-chat.mjs +2 -1
- package/dist/lib/chunk-run-prompt-in-chat.mjs.map +1 -1
- package/dist/lib/chunk-run-prompt-in-new-chat.mjs +1 -1
- package/dist/lib/chunk-schema-defs.mjs +2 -2
- package/dist/lib/chunk-skill-definition.mjs +3 -2
- package/dist/lib/chunk-skill-definition.mjs.map +1 -1
- package/dist/lib/components.mjs +13 -13
- package/dist/lib/components.mjs.map +1 -1
- package/dist/lib/hooks.mjs +40 -31
- package/dist/lib/hooks.mjs.map +1 -1
- package/dist/lib/operations.mjs +3 -1
- package/dist/lib/operations.mjs.map +1 -1
- package/dist/lib/skills.mjs +2 -1
- package/dist/lib/translations.mjs +4 -2
- package/dist/lib/translations.mjs.map +1 -1
- package/dist/types/src/Chat.d.ts +1 -1
- package/dist/types/src/capabilities/agent-service.d.ts.map +1 -1
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -1
- package/dist/types/src/{processor/processor.d.ts → chat-model/chat-model.d.ts} +24 -22
- package/dist/types/src/chat-model/chat-model.d.ts.map +1 -0
- package/dist/types/src/chat-model/chat-model.edge.test.d.ts +2 -0
- package/dist/types/src/chat-model/chat-model.edge.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/chat-model.node.test.d.ts +2 -0
- package/dist/types/src/chat-model/chat-model.node.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/chat-model.scripted.node.test.d.ts +2 -0
- package/dist/types/src/chat-model/chat-model.scripted.node.test.d.ts.map +1 -0
- package/dist/types/src/{processor → chat-model}/index.d.ts +1 -1
- package/dist/types/src/chat-model/index.d.ts.map +1 -0
- package/dist/types/src/chat-model/outbox.d.ts.map +1 -0
- package/dist/types/src/chat-model/outbox.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/presets.d.ts.map +1 -0
- package/dist/types/src/chat-model/presets.test.d.ts.map +1 -0
- package/dist/types/src/{processor → chat-model}/prompt.d.ts +2 -2
- package/dist/types/src/chat-model/prompt.d.ts.map +1 -0
- package/dist/types/src/chat-model/prompt.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/streaming.node.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/testing/chat-model-recorder.d.ts +58 -0
- package/dist/types/src/chat-model/testing/chat-model-recorder.d.ts.map +1 -0
- package/dist/types/src/chat-model/testing/harness.d.ts +22 -0
- package/dist/types/src/chat-model/testing/harness.d.ts.map +1 -0
- package/dist/types/src/chat-model/thread.d.ts.map +1 -0
- package/dist/types/src/chat-model/thread.test.d.ts.map +1 -0
- package/dist/types/src/components/Chat/Chat.d.ts +6 -6
- package/dist/types/src/components/Chat/Chat.d.ts.map +1 -1
- package/dist/types/src/components/Chat/context.d.ts +5 -3
- package/dist/types/src/components/Chat/context.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatActions.d.ts +1 -1
- package/dist/types/src/components/ChatPrompt/ChatActions.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatMcpErrors.d.ts +3 -3
- package/dist/types/src/components/ChatPrompt/ChatMcpErrors.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.d.ts +3 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.stories.d.ts +4 -3
- package/dist/types/src/components/ChatPrompt/ChatOptions.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatPrompt.d.ts +15 -5
- package/dist/types/src/components/ChatPrompt/ChatPrompt.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatPrompt.stories.d.ts +1 -1
- package/dist/types/src/components/ChatPrompt/ChatStatus.d.ts +1 -1
- package/dist/types/src/components/ChatPrompt/ChatStatus.d.ts.map +1 -1
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.stories.d.ts +9 -0
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbox/Toolbox.d.ts +3 -3
- package/dist/types/src/components/Toolbox/Toolbox.d.ts.map +1 -1
- package/dist/types/src/containers/ChatArticle/ChatArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ChatArticle/ChatArticle.stories.d.ts +1 -1
- package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/{useChatProcessor.d.ts → useChatModel.d.ts} +6 -6
- package/dist/types/src/hooks/useChatModel.d.ts.map +1 -0
- package/dist/types/src/hooks/useDebug.d.ts +3 -3
- package/dist/types/src/hooks/useDebug.d.ts.map +1 -1
- package/dist/types/src/hooks/useHomeSuggestions.d.ts +3 -3
- package/dist/types/src/hooks/useHomeSuggestions.d.ts.map +1 -1
- package/dist/types/src/hooks/usePresets.d.ts +1 -1
- package/dist/types/src/hooks/usePresets.d.ts.map +1 -1
- package/dist/types/src/hooks/useSelectionContext.d.ts +3 -3
- package/dist/types/src/hooks/useSelectionContext.d.ts.map +1 -1
- package/dist/types/src/operations/analyze-turn.d.ts +5 -0
- package/dist/types/src/operations/analyze-turn.d.ts.map +1 -0
- package/dist/types/src/operations/analyze-turn.test.d.ts +2 -0
- package/dist/types/src/operations/analyze-turn.test.d.ts.map +1 -0
- package/dist/types/src/operations/create-chat.d.ts.map +1 -1
- package/dist/types/src/operations/generate-home-suggestions.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/run-prompt-in-chat.d.ts.map +1 -1
- package/dist/types/src/review/turn-review.d.ts +58 -0
- package/dist/types/src/review/turn-review.d.ts.map +1 -0
- package/dist/types/src/review/turn-review.test.d.ts +2 -0
- package/dist/types/src/review/turn-review.test.d.ts.map +1 -0
- package/dist/types/src/skills/index.d.ts +1 -0
- package/dist/types/src/skills/index.d.ts.map +1 -1
- package/dist/types/src/skills/turn-review/TurnReviewSkill.d.ts +21 -0
- package/dist/types/src/skills/turn-review/TurnReviewSkill.d.ts.map +1 -0
- package/dist/types/src/skills/turn-review/index.d.ts +2 -0
- package/dist/types/src/skills/turn-review/index.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Assistant.d.ts +1 -0
- package/dist/types/src/types/Assistant.d.ts.map +1 -1
- package/dist/types/src/types/AssistantCapabilities.d.ts +7 -1
- package/dist/types/src/types/AssistantCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/Settings.d.ts +1 -0
- package/dist/types/src/types/Settings.d.ts.map +1 -1
- package/dist/types/src/util/agent-options.d.ts +27 -0
- package/dist/types/src/util/agent-options.d.ts.map +1 -0
- package/dist/types/src/util/agent-options.test.d.ts +2 -0
- package/dist/types/src/util/agent-options.test.d.ts.map +1 -0
- package/dist/types/src/util/default-skills.d.ts +10 -0
- package/dist/types/src/util/default-skills.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +89 -80
- package/src/capabilities/agent-service.ts +2 -1
- package/src/capabilities/skill-definition.ts +2 -1
- package/src/chat-model/chat-model.edge.test.ts +301 -0
- package/src/{processor/processor.node.test.ts → chat-model/chat-model.node.test.ts} +19 -9
- package/src/chat-model/chat-model.scripted.node.test.ts +441 -0
- package/src/{processor/processor.ts → chat-model/chat-model.ts} +140 -45
- package/src/{processor → chat-model}/index.ts +1 -1
- package/src/{processor → chat-model}/prompt.ts +2 -2
- package/src/{processor → chat-model}/streaming.node.test.ts +108 -116
- package/src/chat-model/testing/chat-model-recorder.ts +249 -0
- package/src/chat-model/testing/harness.ts +81 -0
- package/src/{processor → chat-model}/thread.test.ts +1 -1
- package/src/components/Chat/Chat.tsx +44 -38
- package/src/components/Chat/Error.stories.tsx +1 -1
- package/src/components/Chat/context.ts +5 -3
- package/src/components/ChatPrompt/ChatActions.tsx +1 -1
- package/src/components/ChatPrompt/ChatMcpErrors.tsx +6 -6
- package/src/components/ChatPrompt/ChatOptions.stories.tsx +37 -3
- package/src/components/ChatPrompt/ChatOptions.tsx +118 -10
- package/src/components/ChatPrompt/ChatPrompt.stories.tsx +10 -10
- package/src/components/ChatPrompt/ChatPrompt.tsx +44 -27
- package/src/components/ChatPrompt/ChatStatus.tsx +8 -7
- package/src/components/Toolbox/Toolbox.tsx +12 -13
- package/src/containers/AssistantSettings/AssistantSettings.tsx +1 -1
- package/src/containers/ChatArticle/ChatArticle.stories.tsx +1 -1
- package/src/containers/ChatArticle/ChatArticle.tsx +16 -6
- package/src/containers/ChatDialog/ChatDialog.tsx +4 -4
- package/src/containers/SpaceHomePrompt/SpaceHomePrompt.tsx +110 -57
- package/src/hooks/index.ts +2 -2
- package/src/hooks/{useChatProcessor.ts → useChatModel.ts} +16 -14
- package/src/hooks/useDebug.ts +8 -8
- package/src/hooks/useHomeSuggestions.ts +14 -9
- package/src/hooks/usePresets.ts +2 -2
- package/src/hooks/useProcessEphemeralStatus.ts +1 -1
- package/src/hooks/useSelectionContext.ts +3 -5
- package/src/operations/analyze-turn.test.ts +194 -0
- package/src/operations/analyze-turn.ts +96 -0
- package/src/operations/create-chat.ts +4 -36
- package/src/operations/generate-home-suggestions.test.ts +1 -2
- package/src/operations/generate-home-suggestions.ts +17 -9
- package/src/operations/index.ts +2 -0
- package/src/operations/run-prompt-in-chat.ts +3 -2
- package/src/review/turn-review.test.ts +92 -0
- package/src/review/turn-review.ts +213 -0
- package/src/skills/index.ts +1 -0
- package/src/skills/turn-review/TurnReviewSkill.ts +46 -0
- package/src/skills/turn-review/index.ts +5 -0
- package/src/translations.ts +2 -0
- package/src/types/AssistantCapabilities.ts +8 -1
- package/src/types/Settings.ts +7 -0
- package/src/util/agent-options.test.ts +54 -0
- package/src/util/agent-options.ts +60 -0
- package/src/util/default-skills.ts +35 -0
- package/dist/lib/chunk-processor.mjs.map +0 -1
- package/dist/types/src/hooks/useChatProcessor.d.ts.map +0 -1
- package/dist/types/src/processor/index.d.ts.map +0 -1
- package/dist/types/src/processor/outbox.d.ts.map +0 -1
- package/dist/types/src/processor/outbox.test.d.ts.map +0 -1
- package/dist/types/src/processor/presets.d.ts.map +0 -1
- package/dist/types/src/processor/presets.test.d.ts.map +0 -1
- package/dist/types/src/processor/processor.d.ts.map +0 -1
- package/dist/types/src/processor/processor.node.test.d.ts +0 -2
- package/dist/types/src/processor/processor.node.test.d.ts.map +0 -1
- package/dist/types/src/processor/prompt.d.ts.map +0 -1
- package/dist/types/src/processor/prompt.test.d.ts.map +0 -1
- package/dist/types/src/processor/streaming.node.test.d.ts.map +0 -1
- package/dist/types/src/processor/thread.d.ts.map +0 -1
- package/dist/types/src/processor/thread.test.d.ts.map +0 -1
- /package/dist/types/src/{processor → chat-model}/outbox.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/outbox.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/presets.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/presets.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/prompt.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/streaming.node.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/thread.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/thread.test.d.ts +0 -0
- /package/src/{processor → chat-model}/outbox.test.ts +0 -0
- /package/src/{processor → chat-model}/outbox.ts +0 -0
- /package/src/{processor → chat-model}/presets.test.ts +0 -0
- /package/src/{processor → chat-model}/presets.ts +0 -0
- /package/src/{processor → chat-model}/prompt.test.ts +0 -0
- /package/src/{processor → chat-model}/thread.ts +0 -0
|
@@ -14,7 +14,7 @@ import { ChatDialog as NaturalChatDialog } from '@dxos/react-ui-chat';
|
|
|
14
14
|
import * as UiHooks from '@dxos/react-ui/Hooks';
|
|
15
15
|
|
|
16
16
|
import { Chat, type ChatRootProps } from '#components';
|
|
17
|
-
import {
|
|
17
|
+
import { useChatModel, useChatServices, usePresets } from '#hooks';
|
|
18
18
|
import { meta } from '#meta';
|
|
19
19
|
import { AssistantCapabilities } from '#types';
|
|
20
20
|
|
|
@@ -30,7 +30,7 @@ export const ChatDialog = ({ chat }: ChatDialogProps) => {
|
|
|
30
30
|
const runtime = useChatServices({ id: db?.spaceId });
|
|
31
31
|
const { preset, ...chatProps } = usePresets(settings, chat);
|
|
32
32
|
const registry = useRegistry();
|
|
33
|
-
const
|
|
33
|
+
const chatModel = useChatModel({ db, chat, preset, runtime, registry, settings });
|
|
34
34
|
// Subscribe via `useObject` so the thread re-renders when ChatOptions changes the view type.
|
|
35
35
|
const [chatViewType] = useObject(chat, 'viewType');
|
|
36
36
|
|
|
@@ -50,12 +50,12 @@ export const ChatDialog = ({ chat }: ChatDialogProps) => {
|
|
|
50
50
|
}
|
|
51
51
|
}, []);
|
|
52
52
|
|
|
53
|
-
if (!chat || !
|
|
53
|
+
if (!chat || !chatModel) {
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
return (
|
|
58
|
-
<Chat.Root chat={chat}
|
|
58
|
+
<Chat.Root chat={chat} chatModel={chatModel} onEvent={handleEvent}>
|
|
59
59
|
<NaturalChatDialog.Root open={open} expanded={expanded} onOpenChange={setOpen}>
|
|
60
60
|
<NaturalChatDialog.Header title={t('assistant-dialog.title')} />
|
|
61
61
|
<NaturalChatDialog.Content>
|
|
@@ -2,90 +2,59 @@
|
|
|
2
2
|
// Copyright 2026 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import type * as AtomRegistry from 'effect/reactivity/AtomRegistry';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
8
|
|
|
7
9
|
import * as Capabilities from '@dxos/app-framework/Capabilities';
|
|
8
10
|
import * as Hooks from '@dxos/app-framework/Hooks';
|
|
11
|
+
import * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';
|
|
9
12
|
import * as LayoutOperation from '@dxos/app-toolkit/LayoutOperation';
|
|
10
|
-
import
|
|
13
|
+
import { AiContext } from '@dxos/assistant';
|
|
14
|
+
import * as Chat from '@dxos/assistant/Chat';
|
|
11
15
|
import { Event } from '@dxos/async';
|
|
16
|
+
import { Database, Feed, Ref } from '@dxos/echo';
|
|
17
|
+
import * as EffectEx from '@dxos/effect/EffectEx';
|
|
18
|
+
import { log } from '@dxos/log';
|
|
12
19
|
import { type Space, useRegistry } from '@dxos/react-client/echo';
|
|
13
20
|
import * as UiHooks from '@dxos/react-ui/Hooks';
|
|
14
21
|
|
|
15
22
|
import { type ChatEvent, ChatPrompt } from '#components';
|
|
16
|
-
import {
|
|
23
|
+
import { usePresets } from '#hooks';
|
|
17
24
|
import { meta } from '#meta';
|
|
18
|
-
import { AssistantCapabilities
|
|
25
|
+
import { AssistantCapabilities } from '#types';
|
|
19
26
|
|
|
20
27
|
import { getChatPath } from '../../paths.ts';
|
|
28
|
+
import { bindChatDefaults, contributesPluginManager } from '../../util/default-skills.ts';
|
|
21
29
|
|
|
22
30
|
type SpaceScopedProps = {
|
|
23
31
|
space?: Space;
|
|
24
32
|
};
|
|
25
33
|
|
|
26
|
-
/**
|
|
27
|
-
* Home article pinned-bottom contributor: the assistant prompt. Backed by an ephemeral in-memory
|
|
28
|
-
* chat whose sole responsibility is to collect the user's text, context bindings, and preset
|
|
29
|
-
* choice, then on submit: persist the chat to the space, queue the text as a pending prompt, and
|
|
30
|
-
* navigate to it. AI generation runs in the opened chat view — the processor here exists only to
|
|
31
|
-
* back the context-binder UI.
|
|
32
|
-
*/
|
|
33
34
|
export const SpaceHomePrompt = ({ space }: SpaceScopedProps) => {
|
|
34
35
|
const { t } = UiHooks.useTranslation(meta.profile.key);
|
|
35
|
-
const { invokePromise } = Hooks.useOperationInvoker();
|
|
36
36
|
|
|
37
37
|
const registry = useRegistry();
|
|
38
38
|
const atomRegistry = Hooks.useCapability(Capabilities.AtomRegistry);
|
|
39
|
-
const stateAtom = Hooks.useCapability(AssistantCapabilities.State);
|
|
40
|
-
const runtime = useChatServices({ id: space?.id });
|
|
41
39
|
const settings = Hooks.useAtomCapability(AssistantCapabilities.Settings);
|
|
40
|
+
const pluginManager = contributesPluginManager(Hooks.useCapabilities(AppCapabilities.SkillDefinition));
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
const [nonce, setNonce] = useState(0);
|
|
46
|
-
const { preset, ...presetProps } = usePresets(settings, chat);
|
|
47
|
-
useEffect(() => {
|
|
42
|
+
const [draftGeneration, setDraftGeneration] = useState(0);
|
|
43
|
+
const draft = useMemo(() => {
|
|
48
44
|
if (!space) {
|
|
49
|
-
|
|
50
|
-
return;
|
|
45
|
+
return undefined;
|
|
51
46
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return () => {
|
|
59
|
-
cancelled = true;
|
|
60
|
-
};
|
|
61
|
-
}, [space, nonce, invokePromise]);
|
|
62
|
-
|
|
63
|
-
const processor = useChatProcessor({ db: space?.db, chat, preset, runtime, registry });
|
|
64
|
-
|
|
65
|
-
const event = useMemo(() => new Event<ChatEvent>(), []);
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
return event.on((ev) => {
|
|
68
|
-
if (ev.type !== 'submit') {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const text = ev.text.trim();
|
|
72
|
-
if (!space || !chat || text.length === 0) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
47
|
+
const feed = Feed.make();
|
|
48
|
+
return { feed, chat: Chat.make({ feed: Ref.make(feed) }) };
|
|
49
|
+
}, [space, draftGeneration]);
|
|
50
|
+
const chat = draft?.chat;
|
|
51
|
+
const context = useDraftContext({ db: space?.db, draft, registry: atomRegistry, pluginManager });
|
|
52
|
+
const { preset, ...presetProps } = usePresets(settings, chat);
|
|
75
53
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const chatPath = getChatPath(space.db.spaceId, chat.id);
|
|
79
|
-
atomRegistry.update(stateAtom, (current) => ({
|
|
80
|
-
...current,
|
|
81
|
-
pendingPrompts: { ...current.pendingPrompts, [chatPath]: text },
|
|
82
|
-
}));
|
|
83
|
-
void invokePromise(LayoutOperation.Open, { subject: [chatPath] });
|
|
84
|
-
setNonce((current) => current + 1);
|
|
85
|
-
});
|
|
86
|
-
}, [event, space, chat, atomRegistry, stateAtom, invokePromise]);
|
|
54
|
+
const startNewDraft = useCallback(() => setDraftGeneration((current) => current + 1), []);
|
|
55
|
+
const event = useDraftSend({ space, draft, context, onSent: startNewDraft });
|
|
87
56
|
|
|
88
|
-
if (!
|
|
57
|
+
if (!space) {
|
|
89
58
|
return null;
|
|
90
59
|
}
|
|
91
60
|
|
|
@@ -95,7 +64,8 @@ export const SpaceHomePrompt = ({ space }: SpaceScopedProps) => {
|
|
|
95
64
|
outline
|
|
96
65
|
chat={chat}
|
|
97
66
|
db={space.db}
|
|
98
|
-
|
|
67
|
+
context={context}
|
|
68
|
+
registry={registry}
|
|
99
69
|
event={event}
|
|
100
70
|
preset={preset?.id}
|
|
101
71
|
placeholder={t('space-home.prompt.placeholder')}
|
|
@@ -104,3 +74,86 @@ export const SpaceHomePrompt = ({ space }: SpaceScopedProps) => {
|
|
|
104
74
|
};
|
|
105
75
|
|
|
106
76
|
SpaceHomePrompt.displayName = 'SpaceHomePrompt';
|
|
77
|
+
|
|
78
|
+
type UseDraftSendProps = {
|
|
79
|
+
space?: Space;
|
|
80
|
+
draft?: { feed: Feed.Feed; chat: Chat.Chat };
|
|
81
|
+
context?: AiContext.Binder;
|
|
82
|
+
onSent: () => void;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** Stores the draft's chat and bindings, then opens it; a failed send removes what it stored and restores the text. */
|
|
86
|
+
const useDraftSend = ({ space, draft, context, onSent }: UseDraftSendProps) => {
|
|
87
|
+
const { invokePromise } = Hooks.useOperationInvoker();
|
|
88
|
+
const atomRegistry = Hooks.useCapability(Capabilities.AtomRegistry);
|
|
89
|
+
const stateAtom = Hooks.useCapability(AssistantCapabilities.State);
|
|
90
|
+
const event = useMemo(() => new Event<ChatEvent>(), []);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
return event.on((ev) => {
|
|
93
|
+
if (ev.type !== 'submit') {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const text = ev.text.trim();
|
|
97
|
+
if (!space || !draft || !context || text.length === 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { feed, chat } = draft;
|
|
102
|
+
space.db.add(feed);
|
|
103
|
+
space.db.add(chat);
|
|
104
|
+
const chatPath = getChatPath(space.db.spaceId, chat.id);
|
|
105
|
+
onSent();
|
|
106
|
+
void context
|
|
107
|
+
.flush()
|
|
108
|
+
.then(() => {
|
|
109
|
+
atomRegistry.update(stateAtom, (current) => ({
|
|
110
|
+
...current,
|
|
111
|
+
pendingPrompts: { ...current.pendingPrompts, [chatPath]: text },
|
|
112
|
+
}));
|
|
113
|
+
void invokePromise(LayoutOperation.Open, { subject: [chatPath] });
|
|
114
|
+
})
|
|
115
|
+
.catch((err) => {
|
|
116
|
+
log.catch(err);
|
|
117
|
+
space.db.remove(chat);
|
|
118
|
+
space.db.remove(feed);
|
|
119
|
+
event.emit({ type: 'update-prompt', text });
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}, [event, space, draft, context, atomRegistry, stateAtom, invokePromise, onSent]);
|
|
123
|
+
return event;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
type UseDraftContextProps = {
|
|
127
|
+
db?: Database.Database;
|
|
128
|
+
draft?: { feed: Feed.Feed; chat: Chat.Chat };
|
|
129
|
+
registry: AtomRegistry.AtomRegistry;
|
|
130
|
+
pluginManager: boolean;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const useDraftContext = ({ db, draft, registry, pluginManager }: UseDraftContextProps) => {
|
|
134
|
+
const [context, setContext] = useState<AiContext.Binder>();
|
|
135
|
+
UiHooks.useAsyncEffect(
|
|
136
|
+
async (controller) => {
|
|
137
|
+
if (!db || !draft) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const runtime = await EffectEx.runAndForwardErrors(
|
|
141
|
+
Effect.context<Database.Service>().pipe(Effect.provide(Database.layer(db))),
|
|
142
|
+
);
|
|
143
|
+
const binder = new AiContext.Binder({ feed: draft.feed, runtime, registry, hold: true });
|
|
144
|
+
await binder.open();
|
|
145
|
+
await bindChatDefaults(binder, { chat: draft.chat, pluginManager });
|
|
146
|
+
if (controller.signal.aborted) {
|
|
147
|
+
void binder.close();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
setContext(binder);
|
|
151
|
+
return () => {
|
|
152
|
+
setContext(undefined);
|
|
153
|
+
void binder.close();
|
|
154
|
+
};
|
|
155
|
+
},
|
|
156
|
+
[db, draft, registry, pluginManager],
|
|
157
|
+
);
|
|
158
|
+
return context;
|
|
159
|
+
};
|
package/src/hooks/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
export * from './useSkillRegistry.ts';
|
|
7
7
|
export * from './useChatKeymap.ts';
|
|
8
|
-
export * from './
|
|
8
|
+
export * from './useChatModel.ts';
|
|
9
9
|
export * from './useChatServices.ts';
|
|
10
10
|
export * from './useChatToolbarActions.ts';
|
|
11
11
|
export * from './useContextBinder.ts';
|
|
@@ -21,4 +21,4 @@ export * from './useHomeSuggestions.ts';
|
|
|
21
21
|
export * from './useProcessEphemeralStatus.ts';
|
|
22
22
|
export * from './useSessionTimeline.ts';
|
|
23
23
|
|
|
24
|
-
export { type
|
|
24
|
+
export { type ChatModel } from '../chat-model/index.ts';
|
|
@@ -23,23 +23,23 @@ import * as UiHooks from '@dxos/react-ui/Hooks';
|
|
|
23
23
|
|
|
24
24
|
import { Assistant } from '#types';
|
|
25
25
|
|
|
26
|
-
import {
|
|
26
|
+
import { type AiServicePreset, ChatModel } from '../chat-model/index.ts';
|
|
27
27
|
|
|
28
|
-
export type
|
|
28
|
+
export type UseChatModelProps = {
|
|
29
29
|
db?: Database.Database;
|
|
30
30
|
chat?: Chat.Chat;
|
|
31
31
|
preset?: AiServicePreset;
|
|
32
32
|
runtime?: Capabilities.ProcessManagerRuntime;
|
|
33
33
|
registry?: Registry.Registry;
|
|
34
34
|
settings?: Assistant.Settings;
|
|
35
|
-
/** Attributes the prompts submitted through this
|
|
35
|
+
/** Attributes the prompts submitted through this chat model to a person (see `ChatModelOptions.sender`). */
|
|
36
36
|
sender?: AgentService.PromptSender;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Configure and create
|
|
40
|
+
* Configure and create ChatModel.
|
|
41
41
|
*/
|
|
42
|
-
export const
|
|
42
|
+
export const useChatModel = ({
|
|
43
43
|
db,
|
|
44
44
|
chat,
|
|
45
45
|
preset,
|
|
@@ -47,7 +47,7 @@ export const useChatProcessor = ({
|
|
|
47
47
|
registry,
|
|
48
48
|
settings,
|
|
49
49
|
sender,
|
|
50
|
-
}:
|
|
50
|
+
}: UseChatModelProps): ChatModel | undefined => {
|
|
51
51
|
const observableRegistry = useContext(RegistryContext);
|
|
52
52
|
|
|
53
53
|
// Reactive subscription — re-renders when the feed ref resolves. Direct `.target` reads are not reactive.
|
|
@@ -79,11 +79,12 @@ export const useChatProcessor = ({
|
|
|
79
79
|
}, [db, chat, feed]);
|
|
80
80
|
|
|
81
81
|
const serviceResolver = Hooks.useCapability(Capabilities.ServiceResolver);
|
|
82
|
-
// Primitives rather than the object, so an inline `sender` literal does not rebuild the
|
|
82
|
+
// Primitives rather than the object, so an inline `sender` literal does not rebuild the chat model each render.
|
|
83
83
|
const senderName = sender?.name;
|
|
84
84
|
const senderDid = sender?.identityDid;
|
|
85
|
+
const reportStruggles = settings?.reportStruggles ?? false;
|
|
85
86
|
|
|
86
|
-
const
|
|
87
|
+
const chatModel = useMemo(() => {
|
|
87
88
|
if (!runtime || !session || !chat || !feed || !db) {
|
|
88
89
|
return undefined;
|
|
89
90
|
}
|
|
@@ -98,8 +99,8 @@ export const useChatProcessor = ({
|
|
|
98
99
|
OpaqueToolkit.OpaqueToolkitProvider,
|
|
99
100
|
).pipe(Layer.provide(Layer.succeed(ServiceResolver.ServiceResolver, serviceResolver)));
|
|
100
101
|
|
|
101
|
-
log('creating
|
|
102
|
-
return new
|
|
102
|
+
log('creating chat model', { preset, model: preset?.model, settings });
|
|
103
|
+
return new ChatModel(session, runtime, feed, spaceLayer, {
|
|
103
104
|
chat: chat ? Ref.make(chat) : undefined,
|
|
104
105
|
observableRegistry,
|
|
105
106
|
registry,
|
|
@@ -110,13 +111,14 @@ export const useChatProcessor = ({
|
|
|
110
111
|
senderName || senderDid
|
|
111
112
|
? { ...(senderName ? { name: senderName } : {}), ...(senderDid ? { identityDid: senderDid } : {}) }
|
|
112
113
|
: undefined,
|
|
114
|
+
reportStruggles,
|
|
113
115
|
});
|
|
114
|
-
}, [runtime, session, registry, preset, chat, feed, db?.spaceId, senderName, senderDid]);
|
|
116
|
+
}, [runtime, session, registry, preset, chat, feed, db?.spaceId, senderName, senderDid, reportStruggles]);
|
|
115
117
|
|
|
116
|
-
// A remount (e.g. the user navigated to another page mid-turn) gets a fresh
|
|
118
|
+
// A remount (e.g. the user navigated to another page mid-turn) gets a fresh chat model whose
|
|
117
119
|
// active/streaming state starts empty, while the agent process for the feed keeps running;
|
|
118
120
|
// adopting it restores the running indicator and the streamed blocks.
|
|
119
|
-
useEffect(() =>
|
|
121
|
+
useEffect(() => chatModel?.adopt(), [chatModel]);
|
|
120
122
|
|
|
121
|
-
return
|
|
123
|
+
return chatModel;
|
|
122
124
|
};
|
package/src/hooks/useDebug.ts
CHANGED
|
@@ -6,23 +6,23 @@ import { useCallback } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { trim } from '@dxos/util';
|
|
8
8
|
|
|
9
|
-
import { type
|
|
9
|
+
import { type ChatModel } from '../chat-model/index.ts';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Returns an async callback that logs the chat's current context, system prompt,
|
|
13
13
|
* and resolved tools to the browser console under a collapsible group.
|
|
14
14
|
* Used by the chat's debug-toggle event handler.
|
|
15
15
|
*/
|
|
16
|
-
export const useDebug = ({
|
|
16
|
+
export const useDebug = ({ chatModel }: { chatModel?: ChatModel }) => {
|
|
17
17
|
return useCallback(async () => {
|
|
18
|
-
if (!
|
|
18
|
+
if (!chatModel) {
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const objects =
|
|
23
|
-
const skills =
|
|
24
|
-
const system = await
|
|
25
|
-
const tools = (await
|
|
22
|
+
const objects = chatModel.context.getObjects();
|
|
23
|
+
const skills = chatModel.context.getSkills();
|
|
24
|
+
const system = await chatModel.getSystemPrompt();
|
|
25
|
+
const tools = (await chatModel.getTools()) ?? {};
|
|
26
26
|
console.group('Chat', { objects, skills });
|
|
27
27
|
try {
|
|
28
28
|
console.log(trim`
|
|
@@ -38,5 +38,5 @@ export const useDebug = ({ processor }: { processor?: AiChatProcessor }) => {
|
|
|
38
38
|
} finally {
|
|
39
39
|
console.groupEnd();
|
|
40
40
|
}
|
|
41
|
-
}, [
|
|
41
|
+
}, [chatModel]);
|
|
42
42
|
};
|
|
@@ -9,7 +9,7 @@ import { type Space } from '@dxos/react-client/echo';
|
|
|
9
9
|
import * as UiHooks from '@dxos/react-ui/Hooks';
|
|
10
10
|
|
|
11
11
|
import { meta } from '#meta';
|
|
12
|
-
import { AssistantOperation } from '#types';
|
|
12
|
+
import { AssistantCapabilities, AssistantOperation } from '#types';
|
|
13
13
|
|
|
14
14
|
const FALLBACK_SUGGESTION_KEYS = [
|
|
15
15
|
'space-home.suggestion-magazine.label',
|
|
@@ -17,31 +17,36 @@ const FALLBACK_SUGGESTION_KEYS = [
|
|
|
17
17
|
] as const;
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Returns starter prompts for the space Home page
|
|
21
|
-
*
|
|
22
|
-
* error
|
|
20
|
+
* Returns starter prompts for the space Home page: the space's cached prompts at once, then the
|
|
21
|
+
* operation's answer once it settles (generated prompts, or the hardcoded defaults on an empty result
|
|
22
|
+
* or error). Undefined while nothing is cached and the request is in flight.
|
|
23
23
|
*/
|
|
24
24
|
export const useHomeSuggestions = (space?: Space): readonly string[] | undefined => {
|
|
25
25
|
const { t } = UiHooks.useTranslation(meta.profile.key);
|
|
26
26
|
const { invokePromise } = Hooks.useOperationInvoker();
|
|
27
|
+
const cache = Hooks.useOptionalAtomCapability(AssistantCapabilities.HomeSuggestionsCache);
|
|
27
28
|
const fallbacks = useMemo(() => FALLBACK_SUGGESTION_KEYS.map((key) => t(key)), [t]);
|
|
28
|
-
const [
|
|
29
|
+
const [settled, setSettled] = useState<{ spaceId: string; prompts: readonly string[] }>();
|
|
29
30
|
|
|
30
31
|
UiHooks.useAsyncEffect(
|
|
31
32
|
async (controller) => {
|
|
32
|
-
setSuggestions(undefined);
|
|
33
33
|
if (!space) {
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
-
const
|
|
36
|
+
const spaceId = space.db.spaceId;
|
|
37
|
+
const result = await invokePromise(AssistantOperation.GenerateHomeSuggestions, {}, { spaceId });
|
|
37
38
|
if (controller.signal.aborted) {
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
const prompts = result.data?.prompts;
|
|
41
|
-
|
|
42
|
+
setSettled({ spaceId, prompts: prompts && prompts.length > 0 ? prompts : fallbacks });
|
|
42
43
|
},
|
|
43
44
|
[space, invokePromise],
|
|
44
45
|
);
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
const spaceId = space?.db.spaceId;
|
|
48
|
+
if (!spaceId) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return settled?.spaceId === spaceId ? settled.prompts : cache?.[spaceId]?.prompts;
|
|
47
52
|
};
|
package/src/hooks/usePresets.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
presetsForProvider,
|
|
25
25
|
providerForModel,
|
|
26
26
|
resolveProvider,
|
|
27
|
-
} from '../
|
|
27
|
+
} from '../chat-model/index.ts';
|
|
28
28
|
|
|
29
29
|
export type UsePresets = {
|
|
30
30
|
preset: AiServicePreset | undefined;
|
|
@@ -38,7 +38,7 @@ export type UsePresets = {
|
|
|
38
38
|
export const usePresets = (settings: Assistant.Settings, chat?: Chat.Chat): UsePresets => {
|
|
39
39
|
const { t } = UiHooks.useTranslation(meta.profile.key);
|
|
40
40
|
// Subscribed rather than read: the picker has to follow a selection made on another mount of the
|
|
41
|
-
// same chat, and the stamp the
|
|
41
|
+
// same chat, and the stamp the chat model writes before the first request.
|
|
42
42
|
const [session] = useObject(chat, 'session');
|
|
43
43
|
const chatModel = session?.model;
|
|
44
44
|
|
|
@@ -60,7 +60,7 @@ const resolveSubscribePids = (agentPid: Process.ID, processes: readonly Process.
|
|
|
60
60
|
const attachActiveHandle = (
|
|
61
61
|
processManager: ProcessManager.Manager,
|
|
62
62
|
pid: Process.ID,
|
|
63
|
-
): Effect.Effect<Process.
|
|
63
|
+
): Effect.Effect<Process.Process<any, any, never> | undefined> =>
|
|
64
64
|
Effect.gen(function* () {
|
|
65
65
|
const maxAttempts = 15;
|
|
66
66
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
@@ -10,7 +10,7 @@ import { Obj } from '@dxos/echo';
|
|
|
10
10
|
import * as AttentionCapabilities from '@dxos/plugin-attention/AttentionCapabilities';
|
|
11
11
|
import { Selection } from '@dxos/react-ui-attention/types';
|
|
12
12
|
|
|
13
|
-
import { type
|
|
13
|
+
import { type ChatRequestContext } from '../chat-model/index.ts';
|
|
14
14
|
|
|
15
15
|
/** Resolve `object`'s selection to text via the AnchorResolver contributed for its typename. */
|
|
16
16
|
export const getSelectionContext = ({
|
|
@@ -21,7 +21,7 @@ export const getSelectionContext = ({
|
|
|
21
21
|
object: Obj.Unknown;
|
|
22
22
|
selection: Selection.Selection | undefined;
|
|
23
23
|
resolvers: readonly AppCapabilities.AnchorResolver[];
|
|
24
|
-
}):
|
|
24
|
+
}): ChatRequestContext | undefined => {
|
|
25
25
|
const typename = Obj.getTypename(object);
|
|
26
26
|
const resolver = typename ? resolvers.find((candidate) => candidate.key === typename) : undefined;
|
|
27
27
|
if (!resolver) {
|
|
@@ -55,9 +55,7 @@ export const getSelectionContext = ({
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
/** Submit-time provider of the companion object's current selection as request context. */
|
|
58
|
-
export const useSelectionContext = (
|
|
59
|
-
companionTo: Obj.Unknown | undefined,
|
|
60
|
-
): (() => ProcessorRequestContext | undefined) => {
|
|
58
|
+
export const useSelectionContext = (companionTo: Obj.Unknown | undefined): (() => ChatRequestContext | undefined) => {
|
|
61
59
|
// getAll-style lookup: absent capabilities yield empty arrays so non-companion chats stay inert.
|
|
62
60
|
const [viewState] = Hooks.useCapabilities(AttentionCapabilities.ViewState);
|
|
63
61
|
const resolvers = Hooks.useCapabilities(AppCapabilities.AnchorResolver);
|