@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
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
9
|
+
import type * as Scope from 'effect/Scope';
|
|
10
|
+
|
|
11
|
+
import { AiService, OpaqueToolkit } from '@dxos/ai';
|
|
12
|
+
import type * as Capabilities from '@dxos/app-framework/Capabilities';
|
|
13
|
+
import * as Capability from '@dxos/app-framework/Capability';
|
|
14
|
+
import * as Plugin from '@dxos/app-framework/Plugin';
|
|
15
|
+
import * as PluginManager from '@dxos/app-framework/PluginManager';
|
|
16
|
+
import { ProcessManager } from '@dxos/compute-runtime';
|
|
17
|
+
import * as AgentService from '@dxos/compute/AgentService';
|
|
18
|
+
import * as Credential from '@dxos/compute/Credential';
|
|
19
|
+
import * as Operation from '@dxos/compute/Operation';
|
|
20
|
+
import * as ServiceResolver from '@dxos/compute/ServiceResolver';
|
|
21
|
+
import { Database, Registry } from '@dxos/echo';
|
|
22
|
+
|
|
23
|
+
import { type SpaceServices } from '../chat-model.ts';
|
|
24
|
+
|
|
25
|
+
type BaseSpaceServices = Exclude<SpaceServices, AgentService.AgentService>;
|
|
26
|
+
|
|
27
|
+
/** The ambient services a chat model needs besides the agent service. */
|
|
28
|
+
const pickBaseServices = Effect.map(Effect.context<BaseSpaceServices>(), (services) =>
|
|
29
|
+
Layer.succeedContext(
|
|
30
|
+
Context.pick(
|
|
31
|
+
Database.Service,
|
|
32
|
+
Credential.CredentialsService,
|
|
33
|
+
AiService.AiService,
|
|
34
|
+
Registry.Service,
|
|
35
|
+
OpaqueToolkit.OpaqueToolkitProvider,
|
|
36
|
+
)(services),
|
|
37
|
+
),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/** The chat model's space layer over the ambient services, including the real agent service. */
|
|
41
|
+
export const makeSpaceLayer: Effect.Effect<Layer.Layer<SpaceServices>, never, SpaceServices> = Effect.gen(function* () {
|
|
42
|
+
const base = yield* pickBaseServices;
|
|
43
|
+
const agentService = yield* AgentService.AgentService;
|
|
44
|
+
return Layer.mergeAll(base, Layer.succeed(AgentService.AgentService, agentService));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/** The chat model's space layer with a stub agent service, to script the trace stream directly. */
|
|
48
|
+
export const makeStubSpaceLayer = (
|
|
49
|
+
agentService: AgentService.Service,
|
|
50
|
+
): Effect.Effect<Layer.Layer<SpaceServices>, never, BaseSpaceServices> =>
|
|
51
|
+
Effect.map(pickBaseServices, (base) => Layer.mergeAll(base, Layer.succeed(AgentService.AgentService, agentService)));
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A sound {@link Capabilities.ProcessManagerRuntime} for tests: a `ManagedRuntime` over the
|
|
55
|
+
* assistant test layer's process services plus a bare `PluginManager` for the capability/plugin
|
|
56
|
+
* tags. Scoped so the runtime is disposed with the test.
|
|
57
|
+
*/
|
|
58
|
+
export const makeTestRuntime: Effect.Effect<
|
|
59
|
+
Capabilities.ProcessManagerRuntime,
|
|
60
|
+
never,
|
|
61
|
+
ProcessManager.Service | Operation.Service | ServiceResolver.ServiceResolver | Scope.Scope
|
|
62
|
+
> = Effect.gen(function* () {
|
|
63
|
+
const services = yield* Effect.context<
|
|
64
|
+
ProcessManager.Service | Operation.Service | ServiceResolver.ServiceResolver
|
|
65
|
+
>();
|
|
66
|
+
const manager = PluginManager.make({
|
|
67
|
+
pluginLoader: (id: string) => Effect.die(new Error(`No plugins in test runtime: ${id}`)),
|
|
68
|
+
plugins: [],
|
|
69
|
+
});
|
|
70
|
+
const runtime: Capabilities.ProcessManagerRuntime = ManagedRuntime.make(
|
|
71
|
+
Layer.mergeAll(
|
|
72
|
+
Layer.succeedContext(services),
|
|
73
|
+
Layer.succeed(Capability.Service, manager.capabilities),
|
|
74
|
+
Layer.succeed(Plugin.Service, manager),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
yield* Effect.addFinalizer(() =>
|
|
78
|
+
Effect.promise(() => (runtime as ManagedRuntime.ManagedRuntime<never, never>).dispose()),
|
|
79
|
+
);
|
|
80
|
+
return runtime;
|
|
81
|
+
});
|
|
@@ -578,7 +578,7 @@ const sortText = (messages: Message.Message[]) => text(Array.sort(messages, byAp
|
|
|
578
578
|
|
|
579
579
|
const statusOf = (message: Message.Message) => getDelivery(message);
|
|
580
580
|
|
|
581
|
-
/** A prompt as `
|
|
581
|
+
/** A prompt as `ChatModel.send` holds it, submitted while the feed held `known`. */
|
|
582
582
|
const outboxEntry = (text: string, known: readonly Message.Message[]): OutboxEntry => ({
|
|
583
583
|
id: Obj.ID.random(),
|
|
584
584
|
created: new Date(clock++).toISOString(),
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import { ActionToolbar, type ActionToolbarProps, createMenuAction } from '@dxos/react-ui-menu';
|
|
36
36
|
import { TaskList, TaskQuestion } from '@dxos/react-ui-task';
|
|
37
37
|
import * as UiHooks from '@dxos/react-ui/Hooks';
|
|
38
|
+
import * as Layout from '@dxos/react-ui/Layout';
|
|
38
39
|
import * as Toast from '@dxos/react-ui/Toast';
|
|
39
40
|
import * as Util from '@dxos/react-ui/Util';
|
|
40
41
|
import { Message, Task } from '@dxos/types';
|
|
@@ -44,15 +45,15 @@ import { type ChatSwitcher, useChatToolbarActions, useDebug } from '#hooks';
|
|
|
44
45
|
import { meta } from '#meta';
|
|
45
46
|
import { AssistantOperation } from '#types';
|
|
46
47
|
|
|
47
|
-
import { TaskSlashCommands } from '../../commands/index.ts';
|
|
48
48
|
import {
|
|
49
49
|
AiUsageQuotaError,
|
|
50
|
-
type
|
|
51
|
-
|
|
50
|
+
type ChatRequestContext,
|
|
51
|
+
getChatModelState,
|
|
52
52
|
projectAlarms,
|
|
53
53
|
projectSelfWakes,
|
|
54
54
|
resolveRewind,
|
|
55
|
-
} from '../../
|
|
55
|
+
} from '../../chat-model/index.ts';
|
|
56
|
+
import { TaskSlashCommands } from '../../commands/index.ts';
|
|
56
57
|
import {
|
|
57
58
|
ChatStatus,
|
|
58
59
|
DEFAULT_MAX_QUEUE,
|
|
@@ -78,7 +79,7 @@ import { SurfaceWidget } from './SurfaceWidget.tsx';
|
|
|
78
79
|
//
|
|
79
80
|
|
|
80
81
|
type ChatRootProps = PropsWithChildren<
|
|
81
|
-
Pick<ChatContextValue, 'chat' | '
|
|
82
|
+
Pick<ChatContextValue, 'chat' | 'chatModel' | 'debug'> & {
|
|
82
83
|
/** Fallback database when the chat is transient (not yet persisted). */
|
|
83
84
|
db?: Database.Database;
|
|
84
85
|
onEvent?: (event: ChatEvent) => void;
|
|
@@ -88,14 +89,14 @@ type ChatRootProps = PropsWithChildren<
|
|
|
88
89
|
*/
|
|
89
90
|
onSubmit?: (text: string) => Promise<void> | void;
|
|
90
91
|
/** Called at submit time to capture ephemeral request context (e.g. companion selection). */
|
|
91
|
-
getContext?: () =>
|
|
92
|
+
getContext?: () => ChatRequestContext | undefined;
|
|
92
93
|
}
|
|
93
94
|
>;
|
|
94
95
|
|
|
95
96
|
const ChatRoot = ({
|
|
96
97
|
children,
|
|
97
98
|
chat,
|
|
98
|
-
|
|
99
|
+
chatModel,
|
|
99
100
|
db: dbFallback,
|
|
100
101
|
debug: debugProp,
|
|
101
102
|
onEvent,
|
|
@@ -106,12 +107,12 @@ const ChatRoot = ({
|
|
|
106
107
|
const [debug, setDebug] = useState(debugProp ?? false);
|
|
107
108
|
// Slash commands run their operations through the same invoker the rest of the UI uses.
|
|
108
109
|
const { invokePromise } = Hooks.useOperationInvoker();
|
|
109
|
-
const
|
|
110
|
-
const streaming = useAtomValue(
|
|
111
|
-
const active = useAtomValue(
|
|
110
|
+
const chatModelState = getChatModelState(chatModel);
|
|
111
|
+
const streaming = useAtomValue(chatModelState.streaming);
|
|
112
|
+
const active = useAtomValue(chatModelState.active);
|
|
112
113
|
const requestTiming = useRequestTiming({ active });
|
|
113
114
|
const lastPrompt = useRef<string | undefined>(undefined);
|
|
114
|
-
// A slash command runs outside the
|
|
115
|
+
// A slash command runs outside the chat model, so `streaming` does not cover it.
|
|
115
116
|
const commandPending = useRef(false);
|
|
116
117
|
// Transient chats have no database of their own; fall back to the supplied space db so
|
|
117
118
|
// the message query and context controls operate before the chat is persisted.
|
|
@@ -133,15 +134,15 @@ const ChatRoot = ({
|
|
|
133
134
|
db,
|
|
134
135
|
feed ? Query.select(Filter.type(Alarm.Alarm)).from(feed) : Query.select(Filter.nothing()),
|
|
135
136
|
);
|
|
136
|
-
// The
|
|
137
|
-
const { messages, delivery, queued, tail } = useAtomValue(
|
|
137
|
+
// The chat model queries the feed and reconciles it with the streamed turn and the outbox.
|
|
138
|
+
const { messages, delivery, queued, tail } = useAtomValue(chatModelState.thread);
|
|
138
139
|
const alarms = useMemo(() => projectAlarms({ feedAlarms }), [feedAlarms]);
|
|
139
140
|
const selfWakes = useMemo(() => projectSelfWakes({ feedAlarms, messages }), [feedAlarms, messages]);
|
|
140
141
|
|
|
141
|
-
const dump = useDebug({
|
|
142
|
+
const dump = useDebug({ chatModel });
|
|
142
143
|
|
|
143
|
-
// Surface
|
|
144
|
-
const error = useAtomValue(
|
|
144
|
+
// Surface chat model failures (e.g., AI service unavailable) to subscribers via the event bus.
|
|
145
|
+
const error = useAtomValue(chatModelState.error);
|
|
145
146
|
useEffect(() => {
|
|
146
147
|
if (Option.isSome(error)) {
|
|
147
148
|
event.emit({ type: 'error', error: error.value });
|
|
@@ -188,7 +189,7 @@ const ChatRoot = ({
|
|
|
188
189
|
void db.removeFeedItemsByIds(feed, [row.entryId]).catch((err) => log.catch(err));
|
|
189
190
|
}
|
|
190
191
|
if (row.outboxId) {
|
|
191
|
-
|
|
192
|
+
chatModel?.removePrompt(row.outboxId);
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
195
|
break;
|
|
@@ -199,7 +200,7 @@ const ChatRoot = ({
|
|
|
199
200
|
});
|
|
200
201
|
// `feed`, `messages` and `delivery` are dependencies because the rewind and prompt branches read
|
|
201
202
|
// them: without them the handler would keep resolving against whatever was mounted first.
|
|
202
|
-
}, [event, dump, onEvent, db, feed, messages, delivery,
|
|
203
|
+
}, [event, dump, onEvent, db, feed, messages, delivery, chatModel]);
|
|
203
204
|
|
|
204
205
|
useEffect(() => {
|
|
205
206
|
return event.on((ev) => {
|
|
@@ -222,7 +223,7 @@ const ChatRoot = ({
|
|
|
222
223
|
}, [event, chat, invokePromise]);
|
|
223
224
|
|
|
224
225
|
useEffect(() => {
|
|
225
|
-
if (!
|
|
226
|
+
if (!chatModel) {
|
|
226
227
|
return;
|
|
227
228
|
}
|
|
228
229
|
|
|
@@ -275,7 +276,7 @@ const ChatRoot = ({
|
|
|
275
276
|
if (result.followUp) {
|
|
276
277
|
// Some effects run on the supervisor loop (delegation spawns post-turn), so the
|
|
277
278
|
// command wakes the conversation with a short synthetic prompt.
|
|
278
|
-
void
|
|
279
|
+
void chatModel.request({ message: result.followUp });
|
|
279
280
|
}
|
|
280
281
|
})()
|
|
281
282
|
.catch((error) => {
|
|
@@ -293,9 +294,9 @@ const ChatRoot = ({
|
|
|
293
294
|
markWork('chat.submit');
|
|
294
295
|
lastPrompt.current = ev.text;
|
|
295
296
|
// Optimistic: the prompt is in the thread from this call on, before `onSubmit` persists a
|
|
296
|
-
// transient chat and before the agent acknowledges it. The
|
|
297
|
+
// transient chat and before the agent acknowledges it. The chat model requests it when the
|
|
297
298
|
// agent is idle and queues it behind a running turn otherwise.
|
|
298
|
-
|
|
299
|
+
chatModel.send({ message: text, context: getContext?.() }, { prepare: () => onSubmit?.(text) });
|
|
299
300
|
}
|
|
300
301
|
break;
|
|
301
302
|
}
|
|
@@ -307,8 +308,8 @@ const ChatRoot = ({
|
|
|
307
308
|
// content is synthetic — nobody typed it.
|
|
308
309
|
void Promise.resolve(onSubmit?.(text)).then(() =>
|
|
309
310
|
active
|
|
310
|
-
?
|
|
311
|
-
:
|
|
311
|
+
? chatModel.enqueue({ message: text, disposition: 'synthetic' })
|
|
312
|
+
: chatModel.request({ message: text, disposition: 'synthetic' }),
|
|
312
313
|
);
|
|
313
314
|
}
|
|
314
315
|
break;
|
|
@@ -316,13 +317,13 @@ const ChatRoot = ({
|
|
|
316
317
|
|
|
317
318
|
case 'retry': {
|
|
318
319
|
if (!streaming) {
|
|
319
|
-
void
|
|
320
|
+
void chatModel.retry();
|
|
320
321
|
}
|
|
321
322
|
break;
|
|
322
323
|
}
|
|
323
324
|
|
|
324
325
|
case 'cancel': {
|
|
325
|
-
void
|
|
326
|
+
void chatModel.cancel();
|
|
326
327
|
if (streaming) {
|
|
327
328
|
if (lastPrompt.current) {
|
|
328
329
|
event.emit({ type: 'update-prompt', text: lastPrompt.current });
|
|
@@ -332,7 +333,7 @@ const ChatRoot = ({
|
|
|
332
333
|
}
|
|
333
334
|
}
|
|
334
335
|
});
|
|
335
|
-
}, [event,
|
|
336
|
+
}, [event, chatModel, streaming, active, queued, onSubmit, getContext, invokePromise, chat, db, feed]);
|
|
336
337
|
|
|
337
338
|
// An inline surface (connector prompt, plugin prompt) reports its completed flow as a synthetic
|
|
338
339
|
// turn, so the agent resumes without the report reading as something the user typed.
|
|
@@ -344,8 +345,9 @@ const ChatRoot = ({
|
|
|
344
345
|
event={event}
|
|
345
346
|
db={db}
|
|
346
347
|
chat={chat}
|
|
347
|
-
|
|
348
|
+
chatModel={chatModel}
|
|
348
349
|
queueSize={queued}
|
|
350
|
+
started={messages.length > 0 || queued > 0}
|
|
349
351
|
setController={setController}
|
|
350
352
|
setVisibleRange={setVisibleRange}
|
|
351
353
|
{...props}
|
|
@@ -537,7 +539,7 @@ type ChatThreadProps = Util.ThemedClassName<{
|
|
|
537
539
|
|
|
538
540
|
const ChatThread = ({ classNames, viewType, tailLines, userHue: userHueProp, onViewUsage }: ChatThreadProps) => {
|
|
539
541
|
const { t } = UiHooks.useTranslation(meta.profile.key);
|
|
540
|
-
const { chat, db, debug, event,
|
|
542
|
+
const { chat, db, debug, event, chatModel, setController, setVisibleRange } = useChatContext(CHAT_THREAD_NAME);
|
|
541
543
|
const { messages, tail } = useChatThreadContext(CHAT_THREAD_NAME);
|
|
542
544
|
const identity = useIdentity();
|
|
543
545
|
// Embedded objects resolve against the chat's database (the fallback one while it is transient).
|
|
@@ -565,7 +567,7 @@ const ChatThread = ({ classNames, viewType, tailLines, userHue: userHueProp, onV
|
|
|
565
567
|
// arrive as updates on one identity, and the window is told — the old `MessageSyncer`'s cursor
|
|
566
568
|
// and range table have no equivalent left.
|
|
567
569
|
const model = useFeedModel(messages, { stops: 'prompt' });
|
|
568
|
-
const streaming = useAtomValue(
|
|
570
|
+
const streaming = useAtomValue(getChatModelState(chatModel).streaming);
|
|
569
571
|
useEffect(() => {
|
|
570
572
|
// The answer streams above any prompts still waiting for the agent, which end the thread.
|
|
571
573
|
const last = messages[messages.length - 1 - tail];
|
|
@@ -717,7 +719,10 @@ ChatOutline.displayName = CHAT_OUTLINE_NAME;
|
|
|
717
719
|
|
|
718
720
|
const CHAT_PROMPT_NAME = 'Chat.Prompt';
|
|
719
721
|
|
|
720
|
-
type ChatPromptProps = Omit<
|
|
722
|
+
type ChatPromptProps = Omit<
|
|
723
|
+
NaturalChatPromptProps,
|
|
724
|
+
'chat' | 'db' | 'chatModel' | 'event' | 'tasksVisible' | 'started'
|
|
725
|
+
> & {
|
|
721
726
|
/** Whether the checklist is disclosed on mount. */
|
|
722
727
|
defaultTasksVisible?: boolean;
|
|
723
728
|
};
|
|
@@ -734,7 +739,7 @@ type ChatPromptProps = Omit<NaturalChatPromptProps, 'chat' | 'db' | 'processor'
|
|
|
734
739
|
* event rather than being wrapped in a `Collapsible.Trigger` it cannot reach.
|
|
735
740
|
*/
|
|
736
741
|
const ChatPrompt = ({ classNames, defaultTasksVisible = false, ...props }: ChatPromptProps) => {
|
|
737
|
-
const { chat, db,
|
|
742
|
+
const { chat, db, chatModel, event, queueSize, started } = useChatContext(CHAT_PROMPT_NAME);
|
|
738
743
|
|
|
739
744
|
// A chat with no checklist at all has nothing to disclose, so the toggle is withheld rather than
|
|
740
745
|
// shown pointing at nothing — `ChatActions` renders it only when `tasksVisible` is defined.
|
|
@@ -774,9 +779,10 @@ const ChatPrompt = ({ classNames, defaultTasksVisible = false, ...props }: ChatP
|
|
|
774
779
|
classNames={[tasksVisible && 'rounded-t-none', classNames]}
|
|
775
780
|
db={db}
|
|
776
781
|
chat={chat}
|
|
777
|
-
|
|
782
|
+
chatModel={chatModel}
|
|
778
783
|
event={event}
|
|
779
784
|
queueSize={queueSize}
|
|
785
|
+
started={started}
|
|
780
786
|
tasksVisible={hasTasks ? tasksVisible : undefined}
|
|
781
787
|
/>
|
|
782
788
|
</Collapsible.Root>
|
|
@@ -939,7 +945,7 @@ const ChatTaskQuestions = ({ tasks }: { tasks: readonly Task.Task[] }) => {
|
|
|
939
945
|
}
|
|
940
946
|
|
|
941
947
|
return (
|
|
942
|
-
<
|
|
948
|
+
<Layout.Flex column gap='sm' classNames='p-2' data-testid='chat.taskQuestions'>
|
|
943
949
|
{threads.map(({ task, thread }) => (
|
|
944
950
|
<TaskQuestion
|
|
945
951
|
key={thread.question.id}
|
|
@@ -947,7 +953,7 @@ const ChatTaskQuestions = ({ tasks }: { tasks: readonly Task.Task[] }) => {
|
|
|
947
953
|
onAnswer={(answer) => handleAnswer(task, thread.question.id, answer)}
|
|
948
954
|
/>
|
|
949
955
|
))}
|
|
950
|
-
</
|
|
956
|
+
</Layout.Flex>
|
|
951
957
|
);
|
|
952
958
|
};
|
|
953
959
|
|
|
@@ -960,14 +966,14 @@ ChatTaskQuestions.displayName = 'Chat.TaskQuestions';
|
|
|
960
966
|
const CHAT_ACTIVITY_NAME = 'Chat.Activity';
|
|
961
967
|
|
|
962
968
|
/**
|
|
963
|
-
* The activity line bound to the chat's
|
|
969
|
+
* The activity line bound to the chat's chat model and the chat's pending alarms: what the agent is
|
|
964
970
|
* doing, for as long as it is doing anything. The line itself takes resolved values, so it lives
|
|
965
971
|
* beside the prompt with the rest of the presentational parts and only the binding is here.
|
|
966
972
|
*/
|
|
967
973
|
const ChatActivity = ({ classNames }: Util.ThemedClassName) => {
|
|
968
|
-
const {
|
|
974
|
+
const { chatModel } = useChatContext(CHAT_ACTIVITY_NAME);
|
|
969
975
|
const { alarms } = useChatThreadContext(CHAT_ACTIVITY_NAME);
|
|
970
|
-
const activity = useAtomValue(
|
|
976
|
+
const activity = useAtomValue(getChatModelState(chatModel).activity);
|
|
971
977
|
|
|
972
978
|
// Earliest pending alarm: the agent wakes at the first one, so a later one says nothing about the
|
|
973
979
|
// wait in front of the reader.
|
|
@@ -12,7 +12,7 @@ import * as Toast from '@dxos/react-ui/Toast';
|
|
|
12
12
|
import { meta as pluginMeta } from '#meta';
|
|
13
13
|
import { translations } from '#translations';
|
|
14
14
|
|
|
15
|
-
import { AiUsageQuotaError, parseError } from '../../
|
|
15
|
+
import { AiUsageQuotaError, parseError } from '../../chat-model/index.ts';
|
|
16
16
|
|
|
17
17
|
type FailureToastProps = {
|
|
18
18
|
/**
|
|
@@ -11,7 +11,7 @@ import { type ChatThreadController } from '@dxos/react-ui-assistant';
|
|
|
11
11
|
import { type MessageRange } from '@dxos/react-ui-feed';
|
|
12
12
|
import { type Message } from '@dxos/types';
|
|
13
13
|
|
|
14
|
-
import { type
|
|
14
|
+
import { type ChatModel } from '../../chat-model/index.ts';
|
|
15
15
|
import { type ChatEvent } from './events.ts';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -36,8 +36,10 @@ export type ChatContextValue = {
|
|
|
36
36
|
event: Event<ChatEvent>;
|
|
37
37
|
db?: Database.Database;
|
|
38
38
|
chat?: Chat.Chat;
|
|
39
|
-
/** Undefined while the
|
|
40
|
-
|
|
39
|
+
/** Undefined while the chat model is still opening; the chat renders from the feed meanwhile. */
|
|
40
|
+
chatModel?: ChatModel;
|
|
41
|
+
/** Whether the conversation has begun; a boolean, so it changes once rather than per message. */
|
|
42
|
+
started: boolean;
|
|
41
43
|
/** How many prompts wait behind the running turn; a count, so it changes per enqueue rather than per block. */
|
|
42
44
|
queueSize: number;
|
|
43
45
|
setController: (controller: ChatThreadController | null) => void;
|
|
@@ -37,7 +37,7 @@ export type ChatActionsProps = Util.ThemedClassName<
|
|
|
37
37
|
customActions?: Atom.Atom<ActionGraphProps>;
|
|
38
38
|
processing?: boolean;
|
|
39
39
|
debug?: boolean;
|
|
40
|
-
/** Whether the prompt holds text and the
|
|
40
|
+
/** Whether the prompt holds text and the chat model would accept it; drives the send control's enablement. */
|
|
41
41
|
canSend?: boolean;
|
|
42
42
|
/** Whether the checklist beside the prompt is shown; the toggle renders only when provided. */
|
|
43
43
|
tasksVisible?: boolean;
|
|
@@ -12,23 +12,23 @@ import type * as Util from '@dxos/react-ui/Util';
|
|
|
12
12
|
|
|
13
13
|
import { meta } from '#meta';
|
|
14
14
|
|
|
15
|
-
import { type
|
|
15
|
+
import { type ChatModel } from '../../chat-model/index.ts';
|
|
16
16
|
|
|
17
17
|
export type ChatMcpErrorsProps = Util.ThemedClassName<{
|
|
18
|
-
|
|
18
|
+
chatModel: ChatModel;
|
|
19
19
|
}>;
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Inline banner that lists MCP servers that failed to connect during the most recent request.
|
|
23
23
|
* The chat itself keeps working without these servers — this just lets the user see what was dropped.
|
|
24
24
|
*/
|
|
25
|
-
export const ChatMcpErrors = ({ classNames,
|
|
25
|
+
export const ChatMcpErrors = ({ classNames, chatModel }: ChatMcpErrorsProps) => {
|
|
26
26
|
const { t } = Hooks.useTranslation(meta.profile.key);
|
|
27
|
-
const errors = useAtomValue(
|
|
27
|
+
const errors = useAtomValue(chatModel.mcpErrors);
|
|
28
28
|
|
|
29
29
|
const handleDismiss = useCallback(() => {
|
|
30
|
-
|
|
31
|
-
}, [
|
|
30
|
+
chatModel.dismissMcpErrors();
|
|
31
|
+
}, [chatModel]);
|
|
32
32
|
|
|
33
33
|
if (errors.length === 0) {
|
|
34
34
|
return null;
|
|
@@ -7,6 +7,7 @@ import * as Effect from 'effect/Effect';
|
|
|
7
7
|
import * as Atom from 'effect/reactivity/Atom';
|
|
8
8
|
import React, { useState } from 'react';
|
|
9
9
|
|
|
10
|
+
import { SessionConfig } from '@dxos/ai';
|
|
10
11
|
import * as Capability from '@dxos/app-framework/Capability';
|
|
11
12
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
12
13
|
import { capabilities } from '@dxos/assistant-toolkit/testing';
|
|
@@ -29,6 +30,19 @@ import { type Assistant, AssistantCapabilities } from '#types';
|
|
|
29
30
|
|
|
30
31
|
import { ChatOptions, type ChatOptionsProps, ObjectsPanel } from './ChatOptions.tsx';
|
|
31
32
|
|
|
33
|
+
/** Stands in for an agent another plugin registers: listed in the picker, never run by the story. */
|
|
34
|
+
const stubAgent = (
|
|
35
|
+
id: string,
|
|
36
|
+
label: string,
|
|
37
|
+
availability: AssistantCapabilities.AgentAvailability,
|
|
38
|
+
): AssistantCapabilities.Agent => ({
|
|
39
|
+
id,
|
|
40
|
+
label,
|
|
41
|
+
icon: id === SessionConfig.COMPOSER_HARNESS ? 'ph--sparkle--regular' : 'px--anthropic--regular',
|
|
42
|
+
availability: Atom.make(availability).pipe(Atom.keepAlive),
|
|
43
|
+
makeTurnProducer: () => Effect.succeed({ runTurn: () => Effect.succeed([]), getSkills: () => [] }),
|
|
44
|
+
});
|
|
45
|
+
|
|
32
46
|
const presets = [
|
|
33
47
|
{
|
|
34
48
|
id: 'edge-claude-sonnet',
|
|
@@ -44,9 +58,9 @@ const presets = [
|
|
|
44
58
|
},
|
|
45
59
|
];
|
|
46
60
|
|
|
47
|
-
type StoryArgs = Pick<ChatOptionsProps, 'presets'>;
|
|
61
|
+
type StoryArgs = Pick<ChatOptionsProps, 'presets' | 'started'>;
|
|
48
62
|
|
|
49
|
-
const DefaultStory = ({ presets }: StoryArgs) => {
|
|
63
|
+
const DefaultStory = ({ presets, started }: StoryArgs) => {
|
|
50
64
|
const [space] = useSpaces();
|
|
51
65
|
const [feed] = useQuery(space?.db, Filter.type(Feed.Feed));
|
|
52
66
|
const [chat] = useQuery(space?.db, Filter.type(Chat.Chat));
|
|
@@ -63,6 +77,7 @@ const DefaultStory = ({ presets }: StoryArgs) => {
|
|
|
63
77
|
db={space.db}
|
|
64
78
|
context={binder}
|
|
65
79
|
registry={registry}
|
|
80
|
+
started={started}
|
|
66
81
|
presets={presets}
|
|
67
82
|
preset={preset}
|
|
68
83
|
onPresetChange={setPreset}
|
|
@@ -72,7 +87,6 @@ const DefaultStory = ({ presets }: StoryArgs) => {
|
|
|
72
87
|
|
|
73
88
|
const meta = {
|
|
74
89
|
title: 'plugins/plugin-assistant/components/ChatOptions',
|
|
75
|
-
component: ChatOptions as any,
|
|
76
90
|
render: DefaultStory,
|
|
77
91
|
decorators: [
|
|
78
92
|
withTheme(),
|
|
@@ -107,6 +121,18 @@ const meta = {
|
|
|
107
121
|
...capabilities,
|
|
108
122
|
// The Models tab's online switch reads the assistant settings; without them it would suspend forever.
|
|
109
123
|
Capability.contribute(AssistantCapabilities.Settings, Atom.make<Assistant.Settings>({}).pipe(Atom.keepAlive)),
|
|
124
|
+
Capability.contribute(
|
|
125
|
+
AssistantCapabilities.Agent,
|
|
126
|
+
stubAgent(SessionConfig.COMPOSER_HARNESS, 'Composer', { available: true }),
|
|
127
|
+
),
|
|
128
|
+
Capability.contribute(
|
|
129
|
+
AssistantCapabilities.Agent,
|
|
130
|
+
stubAgent('claude-code', 'Claude Code', { available: false, reason: 'needs the Composer desktop app' }),
|
|
131
|
+
),
|
|
132
|
+
Capability.contribute(
|
|
133
|
+
AssistantCapabilities.Agent,
|
|
134
|
+
stubAgent('claude-code-edge', 'Claude Code (cloud)', { available: true }),
|
|
135
|
+
),
|
|
110
136
|
],
|
|
111
137
|
}),
|
|
112
138
|
],
|
|
@@ -126,6 +152,14 @@ export const Default: Story = {
|
|
|
126
152
|
},
|
|
127
153
|
};
|
|
128
154
|
|
|
155
|
+
/** A chat that has begun shows its agent but no longer offers the others. */
|
|
156
|
+
export const Started: Story = {
|
|
157
|
+
args: {
|
|
158
|
+
presets,
|
|
159
|
+
started: true,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
129
163
|
export const _ObjectsPanel: Story = {
|
|
130
164
|
render: () => {
|
|
131
165
|
const [space] = useSpaces();
|