@dxos/plugin-automation 0.7.5-labs.5f04cf6 → 0.7.5-labs.e27f9b9
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/dist/lib/browser/AutomationPanel-WFJZAW4F.mjs +8 -0
- package/dist/lib/browser/AutomationPanel-WFJZAW4F.mjs.map +7 -0
- package/dist/lib/browser/ChatContainer-OFCOZ5T2.mjs +12 -0
- package/dist/lib/browser/ChatContainer-OFCOZ5T2.mjs.map +7 -0
- package/dist/lib/browser/{ai-client-6CRYUC6D.mjs → ai-client-AARXEMMJ.mjs} +2 -2
- package/dist/lib/browser/{ai-client-6CRYUC6D.mjs.map → ai-client-AARXEMMJ.mjs.map} +3 -3
- package/dist/lib/browser/{app-graph-builder-IJTTULDP.mjs → app-graph-builder-B4U34VSR.mjs} +32 -1
- package/dist/lib/browser/{app-graph-builder-IJTTULDP.mjs.map → app-graph-builder-B4U34VSR.mjs.map} +3 -3
- package/dist/lib/browser/chunk-5SLV6AUA.mjs +1367 -0
- package/dist/lib/browser/chunk-5SLV6AUA.mjs.map +7 -0
- package/dist/lib/browser/chunk-7XADMUOW.mjs +205 -0
- package/dist/lib/browser/chunk-7XADMUOW.mjs.map +7 -0
- package/dist/lib/browser/{chunk-EKJVAFT2.mjs → chunk-IYSMXX6Q.mjs} +64 -7
- package/dist/lib/{node-esm/chunk-5QUXIXNB.mjs.map → browser/chunk-IYSMXX6Q.mjs.map} +4 -4
- package/dist/lib/browser/chunk-RAVNWHNE.mjs +242 -0
- package/dist/lib/browser/chunk-RAVNWHNE.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +43 -38
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/intent-resolver-754MPV7H.mjs +29 -0
- package/dist/lib/browser/intent-resolver-754MPV7H.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-IGMBLSV7.mjs → react-surface-4QZ6AKBF.mjs} +22 -21
- package/dist/lib/browser/react-surface-4QZ6AKBF.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +9 -3
- package/dist/lib/node/AutomationPanel-LRDEDGXI.cjs +26 -0
- package/dist/lib/node/AutomationPanel-LRDEDGXI.cjs.map +7 -0
- package/dist/lib/node/ChatContainer-6LZX4K2Z.cjs +33 -0
- package/dist/lib/node/ChatContainer-6LZX4K2Z.cjs.map +7 -0
- package/dist/lib/node/{ai-client-A3RRU55B.cjs → ai-client-SA35GN5Q.cjs} +5 -5
- package/dist/lib/node/{ai-client-A3RRU55B.cjs.map → ai-client-SA35GN5Q.cjs.map} +3 -3
- package/dist/lib/node/{app-graph-builder-MF5M4QRS.cjs → app-graph-builder-ENVDOPS4.cjs} +35 -4
- package/dist/lib/node/{app-graph-builder-MF5M4QRS.cjs.map → app-graph-builder-ENVDOPS4.cjs.map} +3 -3
- package/dist/lib/node/chunk-6VMSH4P6.cjs +1364 -0
- package/dist/lib/node/chunk-6VMSH4P6.cjs.map +7 -0
- package/dist/lib/node/{chunk-VEGLN4YN.cjs → chunk-HEYQONXC.cjs} +76 -24
- package/dist/lib/node/chunk-HEYQONXC.cjs.map +7 -0
- package/dist/lib/node/chunk-LU4HQWJD.cjs +226 -0
- package/dist/lib/node/chunk-LU4HQWJD.cjs.map +7 -0
- package/dist/lib/node/{AutomationPanel-RXJDVLCF.cjs → chunk-WWU5FVAO.cjs} +120 -7
- package/dist/lib/node/chunk-WWU5FVAO.cjs.map +7 -0
- package/dist/lib/node/index.cjs +72 -66
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/{intent-resolver-TBHYXBDI.cjs → intent-resolver-CNVBSG4E.cjs} +19 -14
- package/dist/lib/node/intent-resolver-CNVBSG4E.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/{react-surface-BVUZMKYS.cjs → react-surface-5HYLBDC3.cjs} +23 -22
- package/dist/lib/node/react-surface-5HYLBDC3.cjs.map +7 -0
- package/dist/lib/node/types/index.cjs +14 -8
- package/dist/lib/node/types/index.cjs.map +2 -2
- package/dist/lib/node-esm/AutomationPanel-ZV7VEEPP.mjs +9 -0
- package/dist/lib/node-esm/AutomationPanel-ZV7VEEPP.mjs.map +7 -0
- package/dist/lib/node-esm/ChatContainer-PPVMC2FC.mjs +13 -0
- package/dist/lib/node-esm/ChatContainer-PPVMC2FC.mjs.map +7 -0
- package/dist/lib/node-esm/{ai-client-2GBZRHBA.mjs → ai-client-2ZA4TYFZ.mjs} +2 -2
- package/dist/lib/node-esm/{ai-client-2GBZRHBA.mjs.map → ai-client-2ZA4TYFZ.mjs.map} +3 -3
- package/dist/lib/node-esm/{app-graph-builder-5N7OK23B.mjs → app-graph-builder-IYOUCQZT.mjs} +32 -1
- package/dist/lib/node-esm/{app-graph-builder-5N7OK23B.mjs.map → app-graph-builder-IYOUCQZT.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-5QUXIXNB.mjs → chunk-3KB5HRXA.mjs} +64 -7
- package/dist/lib/{browser/chunk-EKJVAFT2.mjs.map → node-esm/chunk-3KB5HRXA.mjs.map} +4 -4
- package/dist/lib/node-esm/chunk-EVTLHDM2.mjs +206 -0
- package/dist/lib/node-esm/chunk-EVTLHDM2.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-MS7OIGVR.mjs +243 -0
- package/dist/lib/node-esm/chunk-MS7OIGVR.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-WISKXX7U.mjs +1368 -0
- package/dist/lib/node-esm/chunk-WISKXX7U.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +43 -38
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-DPJJHFGK.mjs → intent-resolver-RQBXW442.mjs} +18 -13
- package/dist/lib/node-esm/intent-resolver-RQBXW442.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-surface-77S6XJOM.mjs → react-surface-SS5WCRJ2.mjs} +22 -21
- package/dist/lib/node-esm/react-surface-SS5WCRJ2.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +9 -3
- package/dist/types/src/AutomationPlugin.d.ts.map +1 -1
- package/dist/types/src/artifacts.stories.d.ts +10 -24
- package/dist/types/src/artifacts.stories.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +22 -22
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +27 -27
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/components/{ChatContainer.d.ts → ChatContainer/ChatContainer.d.ts} +2 -2
- package/dist/types/src/components/ChatContainer/ChatContainer.d.ts.map +1 -0
- package/dist/types/src/components/ChatContainer/index.d.ts +4 -0
- package/dist/types/src/components/ChatContainer/index.d.ts.map +1 -0
- package/dist/types/src/components/MarkdownViewer/MarkdownViewer.d.ts +14 -0
- package/dist/types/src/components/MarkdownViewer/MarkdownViewer.d.ts.map +1 -0
- package/dist/types/src/components/MarkdownViewer/MarkdownViewer.stories.d.ts +8 -0
- package/dist/types/src/components/MarkdownViewer/MarkdownViewer.stories.d.ts.map +1 -0
- package/dist/types/src/components/MarkdownViewer/index.d.ts +2 -0
- package/dist/types/src/components/MarkdownViewer/index.d.ts.map +1 -0
- package/dist/types/src/components/ServiceRegistry/ServiceRegistry.d.ts +6 -0
- package/dist/types/src/components/ServiceRegistry/ServiceRegistry.d.ts.map +1 -0
- package/dist/types/src/components/ServiceRegistry/ServiceRegistry.stories.d.ts +8 -0
- package/dist/types/src/components/ServiceRegistry/ServiceRegistry.stories.d.ts.map +1 -0
- package/dist/types/src/components/ServiceRegistry/index.d.ts +2 -0
- package/dist/types/src/components/ServiceRegistry/index.d.ts.map +1 -0
- package/dist/types/src/components/Thread/ScrollContainer.d.ts +15 -0
- package/dist/types/src/components/Thread/ScrollContainer.d.ts.map +1 -0
- package/dist/types/src/components/Thread/StatusLine.d.ts +11 -0
- package/dist/types/src/components/Thread/StatusLine.d.ts.map +1 -0
- package/dist/types/src/components/Thread/StatusLine.stories.d.ts +9 -0
- package/dist/types/src/components/Thread/StatusLine.stories.d.ts.map +1 -0
- package/dist/types/src/components/Thread/Tabbed.d.ts +9 -0
- package/dist/types/src/components/Thread/Tabbed.d.ts.map +1 -0
- package/dist/types/src/components/Thread/Tabbed.stories.d.ts +8 -0
- package/dist/types/src/components/Thread/Tabbed.stories.d.ts.map +1 -0
- package/dist/types/src/components/Thread/Thread.d.ts +6 -9
- package/dist/types/src/components/Thread/Thread.d.ts.map +1 -1
- package/dist/types/src/components/Thread/Thread.stories.d.ts +2 -4
- package/dist/types/src/components/Thread/Thread.stories.d.ts.map +1 -1
- package/dist/types/src/components/Thread/ThreadMessage.d.ts +12 -0
- package/dist/types/src/components/Thread/ThreadMessage.d.ts.map +1 -0
- package/dist/types/src/components/Thread/ToggleContainer.d.ts +13 -0
- package/dist/types/src/components/Thread/ToggleContainer.d.ts.map +1 -0
- package/dist/types/src/components/Thread/ToggleContainer.stories.d.ts +9 -0
- package/dist/types/src/components/Thread/ToggleContainer.stories.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +5 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/processor.d.ts +32 -13
- package/dist/types/src/hooks/processor.d.ts.map +1 -1
- package/dist/types/src/hooks/useServiceRegistry.d.ts +3 -0
- package/dist/types/src/hooks/useServiceRegistry.d.ts.map +1 -0
- package/dist/types/src/tools/function.d.ts +5 -0
- package/dist/types/src/tools/function.d.ts.map +1 -0
- package/dist/types/src/tools/index.d.ts +3 -0
- package/dist/types/src/tools/index.d.ts.map +1 -0
- package/dist/types/src/tools/openapi.d.ts +10 -0
- package/dist/types/src/tools/openapi.d.ts.map +1 -0
- package/dist/types/src/tools/openapi.test.d.ts +2 -0
- package/dist/types/src/tools/openapi.test.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +9 -6
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +1 -0
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/registry.d.ts +9 -0
- package/dist/types/src/types/registry.d.ts.map +1 -0
- package/dist/types/src/types/schema.d.ts +131 -7
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +2 -2
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +54 -49
- package/src/AutomationPlugin.tsx +12 -20
- package/src/artifacts.stories.tsx +126 -65
- package/src/capabilities/ai-client.ts +1 -1
- package/src/capabilities/app-graph-builder.ts +31 -2
- package/src/capabilities/intent-resolver.ts +14 -9
- package/src/capabilities/react-surface.tsx +11 -11
- package/src/components/ChatContainer/ChatContainer.tsx +117 -0
- package/src/components/ChatContainer/index.ts +8 -0
- package/src/components/MarkdownViewer/MarkdownViewer.stories.tsx +56 -0
- package/src/components/MarkdownViewer/MarkdownViewer.tsx +79 -0
- package/src/components/MarkdownViewer/index.ts +5 -0
- package/src/components/ServiceRegistry/ServiceRegistry.stories.tsx +48 -0
- package/src/components/ServiceRegistry/ServiceRegistry.tsx +75 -0
- package/src/components/ServiceRegistry/index.ts +5 -0
- package/src/components/Thread/ScrollContainer.tsx +92 -0
- package/src/components/Thread/StatusLine.stories.tsx +52 -0
- package/src/components/Thread/StatusLine.tsx +76 -0
- package/src/components/Thread/Tabbed.stories.tsx +52 -0
- package/src/components/Thread/Tabbed.tsx +72 -0
- package/src/components/Thread/Thread.stories.tsx +145 -97
- package/src/components/Thread/Thread.tsx +115 -108
- package/src/components/Thread/ThreadMessage.tsx +195 -0
- package/src/components/Thread/ToggleContainer.stories.tsx +111 -0
- package/src/components/Thread/ToggleContainer.tsx +103 -0
- package/src/components/index.ts +4 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/processor.ts +100 -60
- package/src/hooks/useServiceRegistry.ts +22 -0
- package/src/tools/function.ts +47 -0
- package/src/tools/index.ts +6 -0
- package/src/tools/openapi.test.ts +227 -0
- package/src/tools/openapi.ts +331 -0
- package/src/translations.ts +8 -6
- package/src/types/index.ts +1 -0
- package/src/types/registry.ts +89 -0
- package/src/types/schema.ts +78 -3
- package/src/types/types.ts +2 -2
- package/dist/lib/browser/AssistantPanel-KO6DZBTU.mjs +0 -340
- package/dist/lib/browser/AssistantPanel-KO6DZBTU.mjs.map +0 -7
- package/dist/lib/browser/AutomationPanel-BMLM533Z.mjs +0 -131
- package/dist/lib/browser/AutomationPanel-BMLM533Z.mjs.map +0 -7
- package/dist/lib/browser/ChatContainer-SIAJFRFF.mjs +0 -300
- package/dist/lib/browser/ChatContainer-SIAJFRFF.mjs.map +0 -7
- package/dist/lib/browser/chunk-C3VRGDR6.mjs +0 -75
- package/dist/lib/browser/chunk-C3VRGDR6.mjs.map +0 -7
- package/dist/lib/browser/chunk-JSNPW6JF.mjs +0 -14
- package/dist/lib/browser/chunk-JSNPW6JF.mjs.map +0 -7
- package/dist/lib/browser/chunk-KPSDH6XZ.mjs +0 -118
- package/dist/lib/browser/chunk-KPSDH6XZ.mjs.map +0 -7
- package/dist/lib/browser/chunk-YZF3SDZL.mjs +0 -139
- package/dist/lib/browser/chunk-YZF3SDZL.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-AHDQ3KQP.mjs +0 -24
- package/dist/lib/browser/intent-resolver-AHDQ3KQP.mjs.map +0 -7
- package/dist/lib/browser/react-surface-IGMBLSV7.mjs.map +0 -7
- package/dist/lib/node/AssistantPanel-PPFS2HKK.cjs +0 -360
- package/dist/lib/node/AssistantPanel-PPFS2HKK.cjs.map +0 -7
- package/dist/lib/node/AutomationPanel-RXJDVLCF.cjs.map +0 -7
- package/dist/lib/node/ChatContainer-GS2SC5OG.cjs +0 -318
- package/dist/lib/node/ChatContainer-GS2SC5OG.cjs.map +0 -7
- package/dist/lib/node/chunk-BUQOZA4N.cjs +0 -97
- package/dist/lib/node/chunk-BUQOZA4N.cjs.map +0 -7
- package/dist/lib/node/chunk-DNLBVFR7.cjs +0 -147
- package/dist/lib/node/chunk-DNLBVFR7.cjs.map +0 -7
- package/dist/lib/node/chunk-TWDGP26W.cjs +0 -172
- package/dist/lib/node/chunk-TWDGP26W.cjs.map +0 -7
- package/dist/lib/node/chunk-VEGLN4YN.cjs.map +0 -7
- package/dist/lib/node/chunk-Z2YFE5SJ.cjs +0 -49
- package/dist/lib/node/chunk-Z2YFE5SJ.cjs.map +0 -7
- package/dist/lib/node/intent-resolver-TBHYXBDI.cjs.map +0 -7
- package/dist/lib/node/react-surface-BVUZMKYS.cjs.map +0 -7
- package/dist/lib/node-esm/AssistantPanel-XSSKKCJY.mjs +0 -341
- package/dist/lib/node-esm/AssistantPanel-XSSKKCJY.mjs.map +0 -7
- package/dist/lib/node-esm/AutomationPanel-GQZZ4UBI.mjs +0 -132
- package/dist/lib/node-esm/AutomationPanel-GQZZ4UBI.mjs.map +0 -7
- package/dist/lib/node-esm/ChatContainer-57ILGC3R.mjs +0 -301
- package/dist/lib/node-esm/ChatContainer-57ILGC3R.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ICHNUP5M.mjs +0 -119
- package/dist/lib/node-esm/chunk-ICHNUP5M.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JCYVS5GG.mjs +0 -76
- package/dist/lib/node-esm/chunk-JCYVS5GG.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-L2B6VGMG.mjs +0 -16
- package/dist/lib/node-esm/chunk-L2B6VGMG.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-U7HXYMPZ.mjs +0 -141
- package/dist/lib/node-esm/chunk-U7HXYMPZ.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-DPJJHFGK.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-77S6XJOM.mjs.map +0 -7
- package/dist/types/src/components/AssistantPanel/AssistantPanel.d.ts +0 -8
- package/dist/types/src/components/AssistantPanel/AssistantPanel.d.ts.map +0 -1
- package/dist/types/src/components/AssistantPanel/index.d.ts +0 -3
- package/dist/types/src/components/AssistantPanel/index.d.ts.map +0 -1
- package/dist/types/src/components/AssistantPanel/system-instructions.d.ts +0 -6
- package/dist/types/src/components/AssistantPanel/system-instructions.d.ts.map +0 -1
- package/dist/types/src/components/ChatContainer.d.ts.map +0 -1
- package/src/components/AssistantPanel/AssistantPanel.tsx +0 -232
- package/src/components/AssistantPanel/index.ts +0 -7
- package/src/components/AssistantPanel/system-instructions.ts +0 -166
- package/src/components/ChatContainer.tsx +0 -80
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { type FC } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type MessageContentBlock, type Message } from '@dxos/artifact';
|
|
8
|
+
import { invariant } from '@dxos/invariant';
|
|
9
|
+
import { Button, ButtonGroup, Icon, type ThemedClassName } from '@dxos/react-ui';
|
|
10
|
+
import { Json } from '@dxos/react-ui-syntax-highlighter';
|
|
11
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
12
|
+
import { safeParseJson } from '@dxos/util';
|
|
13
|
+
|
|
14
|
+
import { StatusLine } from './StatusLine';
|
|
15
|
+
import { ToggleContainer } from './ToggleContainer';
|
|
16
|
+
import { MarkdownViewer } from '../MarkdownViewer';
|
|
17
|
+
|
|
18
|
+
export type ThreadMessageProps = ThemedClassName<{
|
|
19
|
+
message: Message;
|
|
20
|
+
collapse?: boolean;
|
|
21
|
+
debug?: boolean;
|
|
22
|
+
onSuggest?: (text: string) => void;
|
|
23
|
+
onDelete?: (id: string) => void;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
export const ThreadMessage: FC<ThreadMessageProps> = ({
|
|
27
|
+
classNames,
|
|
28
|
+
message,
|
|
29
|
+
collapse,
|
|
30
|
+
debug,
|
|
31
|
+
onSuggest,
|
|
32
|
+
onDelete,
|
|
33
|
+
}) => {
|
|
34
|
+
if (typeof message !== 'object') {
|
|
35
|
+
return <div className={mx(classNames)}>{message}</div>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const { role, content = [] } = message;
|
|
39
|
+
|
|
40
|
+
// TODO(burdon): Factor out tool blocks.
|
|
41
|
+
const tools = content.filter((block) => block.type === 'tool_use' || block.type === 'tool_result');
|
|
42
|
+
if (collapse && tools.length > 0) {
|
|
43
|
+
let request: MessageContentBlock & { type: 'tool_use' };
|
|
44
|
+
const lines = tools.map((tool) => {
|
|
45
|
+
switch (tool.type) {
|
|
46
|
+
case 'tool_use': {
|
|
47
|
+
request = tool;
|
|
48
|
+
// TODO(burdon): Get plugin name.
|
|
49
|
+
return `Calling ${tool.name}...`;
|
|
50
|
+
}
|
|
51
|
+
case 'tool_result': {
|
|
52
|
+
if (!request) {
|
|
53
|
+
return 'Error';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return `Processed ${request.name}`;
|
|
57
|
+
}
|
|
58
|
+
default:
|
|
59
|
+
return 'Error';
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className={mx('flex', classNames)}>
|
|
65
|
+
<div className='w-full p-1 px-2 overflow-hidden rounded-md bg-base'>
|
|
66
|
+
<ToggleContainer title={<StatusLine lines={lines} autoAdvance />} toggle>
|
|
67
|
+
<Json data={content[content.length - 1]} classNames='!p-1 text-xs' />
|
|
68
|
+
</ToggleContainer>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div className={mx('flex flex-col shrink-0 gap-2')}>
|
|
76
|
+
{debug && (
|
|
77
|
+
<div className='text-xs text-subdued'>
|
|
78
|
+
{message.id}{' '}
|
|
79
|
+
{onDelete && (
|
|
80
|
+
<span className='cursor-pointer underline' onClick={() => onDelete(message.id)}>
|
|
81
|
+
delete
|
|
82
|
+
</span>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
)}
|
|
86
|
+
{content.map((block, idx) => (
|
|
87
|
+
<div key={idx} className={mx('flex', classNames, block.type === 'text' && role === 'user' && 'justify-end')}>
|
|
88
|
+
<Block role={role} block={block} onSuggest={onSuggest ?? (() => {})} />
|
|
89
|
+
</div>
|
|
90
|
+
))}
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const Block = ({
|
|
96
|
+
block,
|
|
97
|
+
role,
|
|
98
|
+
onSuggest,
|
|
99
|
+
}: Pick<Message, 'role'> & { block: MessageContentBlock; onSuggest: (text: string) => void }) => {
|
|
100
|
+
const Component = componentMap[block.type] ?? componentMap.default;
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
className={mx(
|
|
104
|
+
'p-1 px-2 overflow-hidden rounded-md',
|
|
105
|
+
(block.type !== 'text' || block.disposition) && 'w-full bg-base',
|
|
106
|
+
block.type === 'text' && role === 'user' && 'bg-blue-200 dark:bg-blue-800',
|
|
107
|
+
)}
|
|
108
|
+
>
|
|
109
|
+
<Component block={block} onSuggest={onSuggest} />
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const titles: Record<string, string> = {
|
|
115
|
+
['cot' as const]: 'Chain of thought',
|
|
116
|
+
|
|
117
|
+
// TODO(burdon): Only show if debugging.
|
|
118
|
+
['tool_use' as const]: 'Tool request',
|
|
119
|
+
['tool_result' as const]: 'Tool result',
|
|
120
|
+
|
|
121
|
+
['artifact' as const]: 'Artifact',
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
type BlockComponent = FC<{ block: MessageContentBlock; onSuggest: (text: string) => void }>;
|
|
125
|
+
|
|
126
|
+
const componentMap: Record<string, BlockComponent> = {
|
|
127
|
+
text: ({ block }) => {
|
|
128
|
+
invariant(block.type === 'text');
|
|
129
|
+
const title = block.disposition ? titles[block.disposition] : undefined;
|
|
130
|
+
if (!title) {
|
|
131
|
+
return (
|
|
132
|
+
<MarkdownViewer content={block.text} classNames={[block.disposition === 'cot' && 'text-sm text-subdued']} />
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<ToggleContainer
|
|
138
|
+
title={title}
|
|
139
|
+
icon={
|
|
140
|
+
block.pending ? (
|
|
141
|
+
<Icon icon={'ph--circle-notch--regular'} classNames='text-subdued ml-2 animate-spin' size={4} />
|
|
142
|
+
) : undefined
|
|
143
|
+
}
|
|
144
|
+
defaultOpen={block.disposition === 'cot'}
|
|
145
|
+
toggle
|
|
146
|
+
>
|
|
147
|
+
<MarkdownViewer content={block.text} classNames={[block.disposition === 'cot' && 'text-sm text-subdued']} />
|
|
148
|
+
</ToggleContainer>
|
|
149
|
+
);
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
json: ({ block, onSuggest }) => {
|
|
153
|
+
invariant(block.type === 'json');
|
|
154
|
+
|
|
155
|
+
switch (block.disposition) {
|
|
156
|
+
case 'suggest': {
|
|
157
|
+
const { text = '' }: { text: string } = safeParseJson(block.json ?? '{}') ?? ({} as any);
|
|
158
|
+
return <Button onClick={() => onSuggest(text)}>{text}</Button>;
|
|
159
|
+
}
|
|
160
|
+
case 'select': {
|
|
161
|
+
const { options = [] }: { options: string[] } = safeParseJson(block.json ?? '{}') ?? ({} as any);
|
|
162
|
+
return (
|
|
163
|
+
<ButtonGroup>
|
|
164
|
+
{options.map((option) => (
|
|
165
|
+
<Button key={option} onClick={() => onSuggest(option)}>
|
|
166
|
+
{option}
|
|
167
|
+
</Button>
|
|
168
|
+
))}
|
|
169
|
+
</ButtonGroup>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
default: {
|
|
173
|
+
const title = block.disposition ? titles[block.disposition] : undefined;
|
|
174
|
+
return (
|
|
175
|
+
<ToggleContainer title={title ?? 'JSON'} toggle>
|
|
176
|
+
<Json data={safeParseJson(block.json ?? block)} classNames='!p-1 text-xs' />
|
|
177
|
+
</ToggleContainer>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
default: ({ block }) => {
|
|
184
|
+
let title = titles[block.type];
|
|
185
|
+
if (block.type === 'tool_use') {
|
|
186
|
+
title = `Tool [${block.name}]`; // TODO(burdon): Get label from tool.
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<ToggleContainer title={title ?? 'JSON'} toggle>
|
|
191
|
+
<Json data={block} classNames='!p-1 text-xs' />
|
|
192
|
+
</ToggleContainer>
|
|
193
|
+
);
|
|
194
|
+
},
|
|
195
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxos-theme';
|
|
6
|
+
|
|
7
|
+
import { computed, type ReadonlySignal, signal } from '@preact/signals-core';
|
|
8
|
+
import { type StoryObj, type Meta } from '@storybook/react';
|
|
9
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
import { faker } from '@dxos/random';
|
|
12
|
+
import { Icon, Input, Toolbar } from '@dxos/react-ui';
|
|
13
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
14
|
+
import { withLayout, withTheme, withSignals } from '@dxos/storybook-utils';
|
|
15
|
+
|
|
16
|
+
import { ToggleContainer, type ToggleContainerProps } from './ToggleContainer';
|
|
17
|
+
import { MarkdownViewer } from '../MarkdownViewer';
|
|
18
|
+
|
|
19
|
+
class Generator {
|
|
20
|
+
private readonly _current = signal<string>(faker.lorem.sentence(5));
|
|
21
|
+
private readonly _lines = signal<string[]>([]);
|
|
22
|
+
private _running: NodeJS.Timeout | undefined;
|
|
23
|
+
|
|
24
|
+
readonly count = computed(() => this._lines.value.length);
|
|
25
|
+
readonly text: ReadonlySignal<string[]> = computed(() => [...this._lines.value, this._current.value]);
|
|
26
|
+
|
|
27
|
+
start() {
|
|
28
|
+
this.stop();
|
|
29
|
+
this._running = setInterval(() => {
|
|
30
|
+
if (this._current.value.length > 0) {
|
|
31
|
+
this._current.value += ' ';
|
|
32
|
+
}
|
|
33
|
+
this._current.value += faker.lorem.words(Math.ceil(Math.random() * 2));
|
|
34
|
+
if (Math.random() > 0.95) {
|
|
35
|
+
this._lines.value = [...this._lines.value, this._current.value + '.'];
|
|
36
|
+
this._current.value = '';
|
|
37
|
+
}
|
|
38
|
+
}, 100);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
stop() {
|
|
42
|
+
if (this._running) {
|
|
43
|
+
clearInterval(this._running);
|
|
44
|
+
this._running = undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const Render = ({ shrinkX, ...props }: ToggleContainerProps) => {
|
|
50
|
+
const generator = useMemo(() => new Generator(), []);
|
|
51
|
+
const [running, setRunning] = useState(false);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (running) {
|
|
54
|
+
generator.start();
|
|
55
|
+
} else {
|
|
56
|
+
generator.stop();
|
|
57
|
+
}
|
|
58
|
+
}, [running]);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div className='flex flex-col w-[500px]'>
|
|
62
|
+
<Toolbar.Root classNames='p-4'>
|
|
63
|
+
<Input.Root>
|
|
64
|
+
<Input.Switch checked={running} onCheckedChange={(checked) => setRunning(checked)} />
|
|
65
|
+
</Input.Root>
|
|
66
|
+
<div className='grow' />
|
|
67
|
+
<div>{generator.count.value}</div>
|
|
68
|
+
</Toolbar.Root>
|
|
69
|
+
<div className='flex p-4'>
|
|
70
|
+
<div className={mx('border border-border rounded-md p-2', !shrinkX && 'w-full')}>
|
|
71
|
+
<ToggleContainer
|
|
72
|
+
{...props}
|
|
73
|
+
shrinkX={shrinkX}
|
|
74
|
+
toggle
|
|
75
|
+
icon={
|
|
76
|
+
running ? (
|
|
77
|
+
<Icon icon={'ph--circle-notch--regular'} classNames='text-subdued ml-2 animate-spin' size={4} />
|
|
78
|
+
) : undefined
|
|
79
|
+
}
|
|
80
|
+
>
|
|
81
|
+
<MarkdownViewer classNames='text-sm' content={generator.text.value.join('\n\n')} />
|
|
82
|
+
</ToggleContainer>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const meta: Meta<typeof ToggleContainer> = {
|
|
90
|
+
title: 'plugins/plugin-automation/ToggleContainer',
|
|
91
|
+
component: ToggleContainer,
|
|
92
|
+
render: Render,
|
|
93
|
+
decorators: [withSignals, withTheme, withLayout({ fullscreen: true, classNames: 'justify-center bg-base' })],
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export default meta;
|
|
97
|
+
|
|
98
|
+
type Story = StoryObj<typeof ToggleContainer>;
|
|
99
|
+
|
|
100
|
+
export const Default: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
title: 'Markdown',
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const Shrink: Story = {
|
|
107
|
+
args: {
|
|
108
|
+
title: 'Markdown',
|
|
109
|
+
shrinkX: true,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { type JSX, type PropsWithChildren, useEffect, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Icon, type ThemedClassName } from '@dxos/react-ui';
|
|
8
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
9
|
+
|
|
10
|
+
export type ToggleContainerProps = ThemedClassName<
|
|
11
|
+
PropsWithChildren<{
|
|
12
|
+
title?: string | JSX.Element;
|
|
13
|
+
icon?: JSX.Element;
|
|
14
|
+
toggle?: boolean;
|
|
15
|
+
defaultOpen?: boolean;
|
|
16
|
+
duration?: number;
|
|
17
|
+
/** Should shrink the width when closed. */
|
|
18
|
+
shrinkX?: boolean;
|
|
19
|
+
}>
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
// TODO(burdon): Externalize toggle state.
|
|
23
|
+
export const ToggleContainer = ({
|
|
24
|
+
title,
|
|
25
|
+
icon,
|
|
26
|
+
toggle,
|
|
27
|
+
defaultOpen,
|
|
28
|
+
duration = 400,
|
|
29
|
+
shrinkX = false,
|
|
30
|
+
children,
|
|
31
|
+
classNames,
|
|
32
|
+
}: ToggleContainerProps) => {
|
|
33
|
+
const [expand, setExpand] = useState(defaultOpen || !toggle);
|
|
34
|
+
const [expandX, setExpandX] = useState(shrinkX ? expand : true);
|
|
35
|
+
const [expandY, setExpandY] = useState(expand);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
let t: NodeJS.Timeout;
|
|
39
|
+
if (expand) {
|
|
40
|
+
if (shrinkX) {
|
|
41
|
+
setExpandX(true);
|
|
42
|
+
}
|
|
43
|
+
t = setTimeout(
|
|
44
|
+
() => {
|
|
45
|
+
setExpandY(true);
|
|
46
|
+
},
|
|
47
|
+
shrinkX ? duration : 0,
|
|
48
|
+
);
|
|
49
|
+
} else {
|
|
50
|
+
setExpandY(false);
|
|
51
|
+
if (shrinkX) {
|
|
52
|
+
t = setTimeout(() => {
|
|
53
|
+
setExpandX(false);
|
|
54
|
+
}, duration);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return () => clearTimeout(t);
|
|
59
|
+
}, [expand]);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className={mx('overflow-hidden', classNames)}>
|
|
63
|
+
{title && (
|
|
64
|
+
<div
|
|
65
|
+
className='flex gap-1 py-1 items-center text-sm text-subdued cursor-pointer select-none'
|
|
66
|
+
onClick={toggle ? () => setExpand((open) => !open) : undefined}
|
|
67
|
+
>
|
|
68
|
+
{toggle && (
|
|
69
|
+
<div className='flex w-[24px] h-[24px] items-center justify-center'>
|
|
70
|
+
<Icon
|
|
71
|
+
size={4}
|
|
72
|
+
icon={'ph--caret-right--regular'}
|
|
73
|
+
style={{ transitionDuration: `${shrinkX ? duration * 2 : duration}ms` }}
|
|
74
|
+
classNames={['transition transition-transform ease-in-out', expand ? 'rotate-90' : 'transform-none']}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
)}
|
|
78
|
+
<div className='flex-1 pis-1 pie-1 truncate'>{title}</div>
|
|
79
|
+
{icon}
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
<div
|
|
83
|
+
style={{ transitionDuration: `${duration}ms` }}
|
|
84
|
+
className={mx(
|
|
85
|
+
'grid transition-[grid-template-columns] ease-in-out',
|
|
86
|
+
expandX ? 'grid-cols-[1fr]' : 'grid-cols-[0fr]',
|
|
87
|
+
)}
|
|
88
|
+
>
|
|
89
|
+
<div className='overflow-hidden'>
|
|
90
|
+
<div
|
|
91
|
+
style={{ transitionDuration: `${duration}ms` }}
|
|
92
|
+
className={mx(
|
|
93
|
+
'grid transition-[grid-template-rows] ease-in-out',
|
|
94
|
+
expandY ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',
|
|
95
|
+
)}
|
|
96
|
+
>
|
|
97
|
+
<div className={mx('flex overflow-hidden transition-opacity')}>{children}</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
};
|
package/src/components/index.ts
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import { lazy } from 'react';
|
|
6
6
|
|
|
7
|
+
export * from './AutomationPanel';
|
|
8
|
+
export * from './ChatContainer';
|
|
9
|
+
export * from './MarkdownViewer';
|
|
7
10
|
export * from './PromptEditor';
|
|
11
|
+
export * from './ServiceRegistry';
|
|
8
12
|
export * from './Thread';
|
|
9
13
|
export * from './TriggerEditor';
|
|
10
14
|
|
|
11
|
-
export const AssistantPanel = lazy(() => import('./AssistantPanel'));
|
|
12
15
|
export const AutomationPanel = lazy(() => import('./AutomationPanel'));
|
|
13
16
|
export const ChatContainer = lazy(() => import('./ChatContainer'));
|
package/src/hooks/index.ts
CHANGED
package/src/hooks/processor.ts
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type Signal, batch, computed, signal } from '@preact/signals-core';
|
|
6
6
|
|
|
7
7
|
import { type PromiseIntentDispatcher } from '@dxos/app-framework';
|
|
8
|
-
import { type Tool, Message } from '@dxos/artifact';
|
|
8
|
+
import { type Tool, Message, type MessageContentBlock } from '@dxos/artifact';
|
|
9
9
|
import {
|
|
10
|
+
isToolUse,
|
|
11
|
+
runTools,
|
|
10
12
|
type AIServiceClientImpl,
|
|
11
13
|
type GenerateRequest,
|
|
12
14
|
type GenerationStream,
|
|
13
|
-
|
|
14
|
-
runTools,
|
|
15
|
+
MixedStreamParser,
|
|
15
16
|
} from '@dxos/assistant';
|
|
16
17
|
import { createStatic } from '@dxos/echo-schema';
|
|
17
18
|
import { invariant } from '@dxos/invariant';
|
|
@@ -31,56 +32,95 @@ declare global {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
type RequestOptions = {
|
|
36
|
+
history?: Message[];
|
|
37
|
+
onComplete?: (messages: Message[]) => void;
|
|
38
|
+
};
|
|
39
|
+
|
|
34
40
|
/**
|
|
35
|
-
* Handles interactions with
|
|
36
|
-
* Manages message history, and executes tools based on AI responses.
|
|
41
|
+
* Handles interactions with the AI service.
|
|
37
42
|
* Maintains a queue of messages and handles streaming responses from the AI service.
|
|
43
|
+
* Executes tools based on AI responses.
|
|
38
44
|
* Supports cancellation of in-progress requests.
|
|
39
45
|
*/
|
|
40
|
-
// TODO(burdon): Tests.
|
|
41
46
|
export class ChatProcessor {
|
|
47
|
+
/** SSE stream parser. */
|
|
48
|
+
private readonly _parser = new MixedStreamParser();
|
|
49
|
+
|
|
50
|
+
/** Current streaming response (iterator). */
|
|
51
|
+
private _stream: GenerationStream | undefined;
|
|
52
|
+
|
|
53
|
+
/** Pending messages (incl. the user request). */
|
|
54
|
+
private readonly _pending: Signal<Message[]> = signal([]);
|
|
55
|
+
|
|
56
|
+
/** Current streaming block (from the AI service). */
|
|
57
|
+
private readonly _block: Signal<MessageContentBlock | undefined> = signal(undefined);
|
|
58
|
+
|
|
42
59
|
/** Prior history from queue. */
|
|
43
60
|
private _history: Message[] = [];
|
|
44
61
|
|
|
45
|
-
/**
|
|
46
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Streaming state.
|
|
64
|
+
* @reactive
|
|
65
|
+
*/
|
|
66
|
+
public readonly streaming: Signal<boolean> = computed(() => this._block.value !== undefined);
|
|
47
67
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Array of Messages (incl. the current message being streamed).
|
|
70
|
+
* @reactive
|
|
71
|
+
*/
|
|
72
|
+
public readonly messages: Signal<Message[]> = computed(() => {
|
|
73
|
+
const messages = [...this._pending.value];
|
|
74
|
+
if (this._block.value) {
|
|
75
|
+
const current = messages.pop();
|
|
76
|
+
invariant(current);
|
|
77
|
+
const { content, ...rest } = current;
|
|
78
|
+
const message = { ...rest, content: [...content, this._block.value] };
|
|
79
|
+
messages.push(message);
|
|
80
|
+
}
|
|
50
81
|
|
|
51
|
-
|
|
52
|
-
|
|
82
|
+
return messages;
|
|
83
|
+
});
|
|
53
84
|
|
|
54
85
|
constructor(
|
|
55
86
|
private readonly _client: AIServiceClientImpl,
|
|
56
87
|
private readonly _tools?: Tool[],
|
|
57
88
|
private readonly _extensions?: ToolContextExtensions,
|
|
58
89
|
private readonly _options: Pick<GenerateRequest, 'model' | 'systemPrompt'> = defaultOptions,
|
|
59
|
-
) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
90
|
+
) {
|
|
91
|
+
// Message complete.
|
|
92
|
+
this._parser.message.on((message) => {
|
|
93
|
+
batch(() => {
|
|
94
|
+
this._pending.value = [...this._pending.value, message];
|
|
95
|
+
this._block.value = undefined;
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Streaming update (happens before message complete).
|
|
100
|
+
this._parser.update.on((block) => {
|
|
101
|
+
batch(() => {
|
|
102
|
+
this._block.value = block;
|
|
103
|
+
});
|
|
104
|
+
});
|
|
67
105
|
}
|
|
68
106
|
|
|
69
107
|
/**
|
|
70
108
|
* Make GPT request.
|
|
71
109
|
*/
|
|
72
|
-
async request(message: string,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
110
|
+
async request(message: string, options: RequestOptions = {}): Promise<Message[]> {
|
|
111
|
+
batch(() => {
|
|
112
|
+
this._history = options.history ?? [];
|
|
113
|
+
this._pending.value = [
|
|
114
|
+
createStatic(Message, {
|
|
115
|
+
role: 'user',
|
|
116
|
+
content: [{ type: 'text', text: message }],
|
|
117
|
+
}),
|
|
118
|
+
];
|
|
119
|
+
this._block.value = undefined;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
await this._generate();
|
|
123
|
+
options.onComplete?.(this._pending.value);
|
|
84
124
|
return this._reset();
|
|
85
125
|
}
|
|
86
126
|
|
|
@@ -90,51 +130,52 @@ export class ChatProcessor {
|
|
|
90
130
|
*/
|
|
91
131
|
async cancel(): Promise<Message[]> {
|
|
92
132
|
log.info('cancelling...');
|
|
93
|
-
this.
|
|
133
|
+
this._stream?.abort();
|
|
94
134
|
return this._reset();
|
|
95
135
|
}
|
|
96
136
|
|
|
97
137
|
private async _reset(): Promise<Message[]> {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
138
|
+
const messages = this._pending.value;
|
|
139
|
+
batch(() => {
|
|
140
|
+
this._history = [];
|
|
141
|
+
this._pending.value = [];
|
|
142
|
+
this._block.value = undefined;
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
return messages;
|
|
103
146
|
}
|
|
104
147
|
|
|
105
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Generate a response from the AI service.
|
|
150
|
+
* Iterates over tool requests.
|
|
151
|
+
*/
|
|
152
|
+
private async _generate() {
|
|
106
153
|
try {
|
|
107
154
|
let more = false;
|
|
108
155
|
do {
|
|
109
|
-
log.info('requesting...', { history: this._history.length,
|
|
110
|
-
this.
|
|
156
|
+
log.info('requesting...', { history: this._history.length, messages: this._pending.value.length });
|
|
157
|
+
this._stream = await this._client.generate({
|
|
111
158
|
...this._options,
|
|
112
159
|
// TODO(burdon): Rename messages or separate history/message.
|
|
113
160
|
history: [...this._history, ...this._pending.value],
|
|
114
161
|
tools: this._tools,
|
|
115
162
|
});
|
|
116
163
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
for await (const event of this._response) {
|
|
121
|
-
log.info('event', { event: event.type });
|
|
122
|
-
this._streaming.value = this._response.accumulatedMessages.map((message) => createStatic(Message, message));
|
|
123
|
-
}
|
|
124
|
-
});
|
|
164
|
+
// Wait until complete.
|
|
165
|
+
await this._parser.parse(this._stream);
|
|
166
|
+
await this._stream.complete();
|
|
125
167
|
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
log.info('response', { messages: messages.length });
|
|
129
|
-
this._pending.value.push(...messages.map((message) => createStatic(Message, message)));
|
|
130
|
-
this._streaming.value = [];
|
|
168
|
+
// Add messages.
|
|
169
|
+
log.info('response', { messages: this._pending.value });
|
|
131
170
|
|
|
132
171
|
// Resolve tool use locally.
|
|
133
172
|
more = false;
|
|
134
|
-
|
|
173
|
+
const message = this._pending.value.at(-1);
|
|
174
|
+
invariant(message);
|
|
175
|
+
if (isToolUse(message)) {
|
|
135
176
|
log.info('tool request...');
|
|
136
177
|
const response = await runTools({
|
|
137
|
-
message:
|
|
178
|
+
message: this._pending.value.at(-1)!,
|
|
138
179
|
tools: this._tools ?? [],
|
|
139
180
|
extensions: this._extensions,
|
|
140
181
|
});
|
|
@@ -142,7 +183,7 @@ export class ChatProcessor {
|
|
|
142
183
|
log.info('tool response', { response });
|
|
143
184
|
switch (response.type) {
|
|
144
185
|
case 'continue': {
|
|
145
|
-
this._pending.value.
|
|
186
|
+
this._pending.value = [...this._pending.value, response.message];
|
|
146
187
|
more = true;
|
|
147
188
|
break;
|
|
148
189
|
}
|
|
@@ -154,8 +195,7 @@ export class ChatProcessor {
|
|
|
154
195
|
log.catch('request failed', { err });
|
|
155
196
|
} finally {
|
|
156
197
|
log.info('done');
|
|
157
|
-
this.
|
|
158
|
-
this._streaming.value = [];
|
|
198
|
+
this._stream = undefined;
|
|
159
199
|
}
|
|
160
200
|
}
|
|
161
201
|
}
|