@assistant-ui/core 0.1.8 → 0.1.9
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/adapters/attachment.d.ts +4 -0
- package/dist/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/attachment.js +1 -1
- package/dist/adapters/attachment.js.map +1 -1
- package/dist/react/client/Interactables.d.ts +3 -0
- package/dist/react/client/Interactables.d.ts.map +1 -0
- package/dist/react/client/Interactables.js +173 -0
- package/dist/react/client/Interactables.js.map +1 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/model-context/makeInteractable.d.ts +10 -0
- package/dist/react/model-context/makeInteractable.d.ts.map +1 -0
- package/dist/react/model-context/makeInteractable.js +10 -0
- package/dist/react/model-context/makeInteractable.js.map +1 -0
- package/dist/react/model-context/useInteractable.d.ts +16 -0
- package/dist/react/model-context/useInteractable.d.ts.map +1 -0
- package/dist/react/model-context/useInteractable.js +36 -0
- package/dist/react/model-context/useInteractable.js.map +1 -0
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +2 -0
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/types/scopes/interactables.d.ts +39 -0
- package/dist/react/types/scopes/interactables.d.ts.map +1 -0
- package/dist/react/types/scopes/interactables.js +2 -0
- package/dist/react/types/scopes/interactables.js.map +1 -0
- package/dist/react/types/store-augmentation.d.ts +2 -0
- package/dist/react/types/store-augmentation.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +33 -8
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.js +12 -5
- package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
- package/dist/store/scopes/composer.d.ts +5 -0
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/adapters/attachment.ts +1 -1
- package/src/react/client/Interactables.ts +233 -0
- package/src/react/index.ts +19 -0
- package/src/react/model-context/makeInteractable.ts +21 -0
- package/src/react/model-context/useInteractable.ts +73 -0
- package/src/react/primitives/message/MessageParts.tsx +2 -0
- package/src/react/types/scopes/interactables.ts +44 -0
- package/src/react/types/store-augmentation.ts +2 -0
- package/src/runtime/base/base-composer-runtime-core.ts +45 -9
- package/src/runtime/interfaces/composer-runtime-core.ts +4 -1
- package/src/store/runtime-clients/composer-runtime-client.ts +18 -7
- package/src/store/scopes/composer.ts +5 -0
|
@@ -440,6 +440,8 @@ const EmptyPartsImpl: FC<MessagePartComponentProps> = ({ components }) => {
|
|
|
440
440
|
|
|
441
441
|
if (components?.Empty) return <components.Empty status={status} />;
|
|
442
442
|
|
|
443
|
+
if (status.type !== "running") return null;
|
|
444
|
+
|
|
443
445
|
return (
|
|
444
446
|
<EmptyPartFallback
|
|
445
447
|
status={status}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Tool } from "assistant-stream";
|
|
2
|
+
import type { Unsubscribe } from "../../..";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Schema type matching Tool["parameters"] from assistant-stream.
|
|
6
|
+
* Accepts both StandardSchemaV1 and JSONSchema7.
|
|
7
|
+
*/
|
|
8
|
+
export type InteractableStateSchema = NonNullable<
|
|
9
|
+
Extract<Tool, { parameters: unknown }>["parameters"]
|
|
10
|
+
>;
|
|
11
|
+
|
|
12
|
+
export type InteractableDefinition = {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
stateSchema: InteractableStateSchema;
|
|
17
|
+
state: unknown;
|
|
18
|
+
selected?: boolean | undefined;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type InteractableRegistration = {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
stateSchema: InteractableStateSchema;
|
|
26
|
+
initialState: unknown;
|
|
27
|
+
selected?: boolean | undefined;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type InteractablesState = {
|
|
31
|
+
/** Keyed by instance id */
|
|
32
|
+
definitions: Record<string, InteractableDefinition>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type InteractablesMethods = {
|
|
36
|
+
getState(): InteractablesState;
|
|
37
|
+
register(def: InteractableRegistration): Unsubscribe;
|
|
38
|
+
setState(id: string, updater: (prev: unknown) => unknown): void;
|
|
39
|
+
setSelected(id: string, selected: boolean): void;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type InteractablesClientSchema = {
|
|
43
|
+
methods: InteractablesMethods;
|
|
44
|
+
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { ToolsClientSchema } from "./scopes/tools";
|
|
2
2
|
import type { DataRenderersClientSchema } from "./scopes/dataRenderers";
|
|
3
|
+
import type { InteractablesClientSchema } from "./scopes/interactables";
|
|
3
4
|
|
|
4
5
|
declare module "@assistant-ui/store" {
|
|
5
6
|
interface ScopeRegistry {
|
|
6
7
|
tools: ToolsClientSchema;
|
|
7
8
|
dataRenderers: DataRenderersClientSchema;
|
|
9
|
+
interactables: InteractablesClientSchema;
|
|
8
10
|
}
|
|
9
11
|
}
|
|
@@ -9,7 +9,10 @@ import type { QuoteInfo } from "../../types/quote";
|
|
|
9
9
|
import type { Unsubscribe } from "../../types/unsubscribe";
|
|
10
10
|
import type { RunConfig } from "../../types/message";
|
|
11
11
|
import { BaseSubscribable } from "../../subscribable/subscribable";
|
|
12
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
type AttachmentAdapter,
|
|
14
|
+
fileMatchesAccept,
|
|
15
|
+
} from "../../adapters/attachment";
|
|
13
16
|
import type {
|
|
14
17
|
ComposerRuntimeCore,
|
|
15
18
|
ComposerRuntimeEventType,
|
|
@@ -216,6 +219,17 @@ export abstract class BaseComposerRuntimeCore
|
|
|
216
219
|
const adapter = this.getAttachmentAdapter();
|
|
217
220
|
if (!adapter) throw new Error("Attachments are not supported");
|
|
218
221
|
|
|
222
|
+
if (
|
|
223
|
+
!fileMatchesAccept(
|
|
224
|
+
{ name: fileOrAttachment.name, type: fileOrAttachment.type },
|
|
225
|
+
adapter.accept,
|
|
226
|
+
)
|
|
227
|
+
) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`File type ${fileOrAttachment.type || "unknown"} is not accepted. Accepted types: ${adapter.accept}`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
219
233
|
const upsertAttachment = (a: PendingAttachment) => {
|
|
220
234
|
const idx = this._attachments.findIndex(
|
|
221
235
|
(attachment) => attachment.id === a.id,
|
|
@@ -233,17 +247,39 @@ export abstract class BaseComposerRuntimeCore
|
|
|
233
247
|
this._notifySubscribers();
|
|
234
248
|
};
|
|
235
249
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
250
|
+
let lastAttachment: PendingAttachment | undefined;
|
|
251
|
+
try {
|
|
252
|
+
const promiseOrGenerator = adapter.add({ file: fileOrAttachment });
|
|
253
|
+
if (Symbol.asyncIterator in promiseOrGenerator) {
|
|
254
|
+
for await (const r of promiseOrGenerator) {
|
|
255
|
+
lastAttachment = r;
|
|
256
|
+
upsertAttachment(r);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
lastAttachment = await promiseOrGenerator;
|
|
260
|
+
upsertAttachment(lastAttachment);
|
|
240
261
|
}
|
|
241
|
-
}
|
|
242
|
-
|
|
262
|
+
} catch (e) {
|
|
263
|
+
if (lastAttachment) {
|
|
264
|
+
upsertAttachment({
|
|
265
|
+
...lastAttachment,
|
|
266
|
+
status: { type: "incomplete", reason: "error" },
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
this._notifyEventSubscribers("attachmentAddError");
|
|
271
|
+
} catch {
|
|
272
|
+
// prevent subscriber errors from masking the adapter error
|
|
273
|
+
}
|
|
274
|
+
throw e;
|
|
243
275
|
}
|
|
244
276
|
|
|
245
|
-
|
|
246
|
-
|
|
277
|
+
const hasError =
|
|
278
|
+
lastAttachment?.status.type === "incomplete" &&
|
|
279
|
+
lastAttachment.status.reason === "error";
|
|
280
|
+
this._notifyEventSubscribers(
|
|
281
|
+
hasError ? "attachmentAddError" : "attachmentAdd",
|
|
282
|
+
);
|
|
247
283
|
}
|
|
248
284
|
|
|
249
285
|
async removeAttachment(attachmentId: string) {
|
|
@@ -5,7 +5,10 @@ import type { Unsubscribe } from "../../types/unsubscribe";
|
|
|
5
5
|
import type { RunConfig } from "../../types/message";
|
|
6
6
|
import type { DictationAdapter } from "../../adapters/speech";
|
|
7
7
|
|
|
8
|
-
export type ComposerRuntimeEventType =
|
|
8
|
+
export type ComposerRuntimeEventType =
|
|
9
|
+
| "send"
|
|
10
|
+
| "attachmentAdd"
|
|
11
|
+
| "attachmentAddError";
|
|
9
12
|
|
|
10
13
|
export type DictationState = {
|
|
11
14
|
readonly status: DictationAdapter.Status;
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
ComposerRuntime,
|
|
17
17
|
EditComposerRuntime,
|
|
18
18
|
} from "../../runtime/api/composer-runtime";
|
|
19
|
-
import { ComposerRuntimeEventType } from "../../runtime/interfaces/composer-runtime-core";
|
|
20
19
|
import { ComposerState } from "../scopes/composer";
|
|
21
20
|
import { AttachmentRuntimeClient } from "./attachment-runtime-client";
|
|
22
21
|
import { tapSubscribable } from "./tap-subscribable";
|
|
@@ -54,12 +53,7 @@ export const ComposerClient = resource(
|
|
|
54
53
|
const unsubscribers: Unsubscribe[] = [];
|
|
55
54
|
|
|
56
55
|
// Subscribe to composer events
|
|
57
|
-
const
|
|
58
|
-
"send",
|
|
59
|
-
"attachmentAdd",
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
for (const event of composerEvents) {
|
|
56
|
+
for (const event of ["send", "attachmentAdd"] as const) {
|
|
63
57
|
const unsubscribe = runtime.unstable_on(event, () => {
|
|
64
58
|
emit(`composer.${event}`, {
|
|
65
59
|
threadId: threadIdRef.current,
|
|
@@ -69,6 +63,23 @@ export const ComposerClient = resource(
|
|
|
69
63
|
unsubscribers.push(unsubscribe);
|
|
70
64
|
}
|
|
71
65
|
|
|
66
|
+
// attachmentAddError carries the failed attachment ID
|
|
67
|
+
unsubscribers.push(
|
|
68
|
+
runtime.unstable_on("attachmentAddError", () => {
|
|
69
|
+
const errorAttachment = runtime
|
|
70
|
+
.getState()
|
|
71
|
+
.attachments.findLast(
|
|
72
|
+
(a) =>
|
|
73
|
+
a.status.type === "incomplete" && a.status.reason === "error",
|
|
74
|
+
);
|
|
75
|
+
emit("composer.attachmentAddError", {
|
|
76
|
+
threadId: threadIdRef.current,
|
|
77
|
+
...(messageIdRef && { messageId: messageIdRef.current }),
|
|
78
|
+
...(errorAttachment && { attachmentId: errorAttachment.id }),
|
|
79
|
+
});
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
|
|
72
83
|
return () => {
|
|
73
84
|
for (const unsub of unsubscribers) unsub();
|
|
74
85
|
};
|
|
@@ -90,6 +90,11 @@ export type ComposerMeta = {
|
|
|
90
90
|
export type ComposerEvents = {
|
|
91
91
|
"composer.send": { threadId: string; messageId?: string };
|
|
92
92
|
"composer.attachmentAdd": { threadId: string; messageId?: string };
|
|
93
|
+
"composer.attachmentAddError": {
|
|
94
|
+
threadId: string;
|
|
95
|
+
messageId?: string;
|
|
96
|
+
attachmentId?: string;
|
|
97
|
+
};
|
|
93
98
|
};
|
|
94
99
|
|
|
95
100
|
export type ComposerClientSchema = {
|