@assistant-ui/core 0.3.6 → 0.3.7
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/index.d.ts +1 -1
- package/dist/react/RuntimeAdapter.js +1 -1
- package/dist/react/RuntimeAdapter.js.map +1 -1
- package/dist/react/client/Interactables.js +1 -1
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/Tools.d.ts +1 -1
- package/dist/react/client/Tools.js +1 -1
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/index.d.ts +9 -9
- package/dist/react/index.js +4 -4
- package/dist/react/model-context/interactableTool.d.ts +1 -1
- package/dist/react/model-context/useAssistantTool.d.ts +1 -1
- package/dist/react/runtimes/createMessageConverter.d.ts +1 -1
- package/dist/react/runtimes/createRuntimeExtras.d.ts +4 -1
- package/dist/react/runtimes/createRuntimeExtras.d.ts.map +1 -1
- package/dist/react/runtimes/createRuntimeExtras.js +6 -17
- package/dist/react/runtimes/createRuntimeExtras.js.map +1 -1
- package/dist/react/types/scopes/dataRenderers.d.ts +1 -1
- package/dist/react/types/scopes/interactables.d.ts +1 -1
- package/dist/react/types/scopes/tools.d.ts +1 -1
- package/dist/runtime/utils/runtime-extras-brand.d.ts +21 -0
- package/dist/runtime/utils/runtime-extras-brand.d.ts.map +1 -0
- package/dist/runtime/utils/runtime-extras-brand.js +37 -0
- package/dist/runtime/utils/runtime-extras-brand.js.map +1 -0
- package/dist/store/clients/runtime-adapter.d.ts.map +1 -1
- package/dist/store/clients/runtime-adapter.js +1 -1
- package/dist/store/clients/runtime-adapter.js.map +1 -1
- package/dist/store/clients/suggestions.js +1 -1
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-message-client.js +1 -1
- package/dist/store/clients/thread-message-client.js.map +1 -1
- package/dist/store/index.d.ts +10 -1
- package/dist/store/index.js +7 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.js +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.js +1 -1
- package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/package.json +14 -14
- package/src/react/RuntimeAdapter.test.ts +85 -0
- package/src/react/RuntimeAdapter.ts +1 -1
- package/src/react/client/Interactables.test.ts +3 -2
- package/src/react/client/Interactables.ts +4 -4
- package/src/react/client/Tools.ts +4 -4
- package/src/react/index.ts +1 -0
- package/src/react/runtimes/createRuntimeExtras.test.ts +14 -1
- package/src/react/runtimes/createRuntimeExtras.ts +15 -26
- package/src/runtime/utils/runtime-extras-brand.ts +47 -0
- package/src/store/clients/runtime-adapter.ts +2 -5
- package/src/store/clients/suggestions.ts +1 -1
- package/src/store/clients/thread-message-client.ts +1 -1
- package/src/store/index.ts +31 -0
- package/src/store/runtime-clients/composer-runtime-client.ts +2 -5
- package/src/store/runtime-clients/message-runtime-client.ts +2 -5
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +2 -1
- package/src/store/runtime-clients/thread-list-runtime-client.ts +2 -5
- package/src/store/runtime-clients/thread-runtime-client.ts +2 -2
- package/src/tests/framework-neutral-boundary.test.ts +60 -24
- package/LICENSE +0 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Framework-agnostic core runtime for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assistant",
|
|
@@ -58,6 +58,12 @@
|
|
|
58
58
|
"README.md"
|
|
59
59
|
],
|
|
60
60
|
"sideEffects": false,
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "aui-build",
|
|
63
|
+
"test": "vitest run",
|
|
64
|
+
"test:react-compiler": "vitest run --config vitest.react-compiler.config.ts",
|
|
65
|
+
"test:watch": "vitest"
|
|
66
|
+
},
|
|
61
67
|
"dependencies": {
|
|
62
68
|
"assistant-stream": "^0.3.34",
|
|
63
69
|
"nanoid": "^6.0.0"
|
|
@@ -88,18 +94,18 @@
|
|
|
88
94
|
}
|
|
89
95
|
},
|
|
90
96
|
"devDependencies": {
|
|
97
|
+
"@assistant-ui/store": "workspace:*",
|
|
98
|
+
"@assistant-ui/tap": "workspace:*",
|
|
99
|
+
"@assistant-ui/vite": "workspace:*",
|
|
100
|
+
"@assistant-ui/x-buildutils": "workspace:*",
|
|
91
101
|
"@testing-library/react": "^16.3.2",
|
|
92
102
|
"@types/react": "^19.2.17",
|
|
103
|
+
"assistant-cloud": "workspace:*",
|
|
93
104
|
"jsdom": "^29.1.1",
|
|
94
105
|
"react": "^19.2.8",
|
|
95
106
|
"react-dom": "^19.2.8",
|
|
96
107
|
"vitest": "^4.1.10",
|
|
97
|
-
"zustand": "^5.0.14"
|
|
98
|
-
"@assistant-ui/store": "0.3.4",
|
|
99
|
-
"@assistant-ui/tap": "0.9.10",
|
|
100
|
-
"@assistant-ui/vite": "0.0.11",
|
|
101
|
-
"@assistant-ui/x-buildutils": "0.0.21",
|
|
102
|
-
"assistant-cloud": "0.1.38"
|
|
108
|
+
"zustand": "^5.0.14"
|
|
103
109
|
},
|
|
104
110
|
"publishConfig": {
|
|
105
111
|
"access": "public",
|
|
@@ -113,11 +119,5 @@
|
|
|
113
119
|
},
|
|
114
120
|
"bugs": {
|
|
115
121
|
"url": "https://github.com/assistant-ui/assistant-ui/issues"
|
|
116
|
-
},
|
|
117
|
-
"scripts": {
|
|
118
|
-
"build": "aui-build",
|
|
119
|
-
"test": "vitest run",
|
|
120
|
-
"test:react-compiler": "vitest run --config vitest.react-compiler.config.ts",
|
|
121
|
-
"test:watch": "vitest"
|
|
122
122
|
}
|
|
123
|
-
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { flushTapSync } from "@assistant-ui/tap";
|
|
3
|
+
import { AuiConfig, createAssistantClient } from "@assistant-ui/store/client";
|
|
4
|
+
import { RuntimeAdapter } from "../store";
|
|
5
|
+
import { ExternalStoreRuntimeCore } from "../runtimes/internal";
|
|
6
|
+
import { AssistantRuntimeImpl } from "../runtime/internal";
|
|
7
|
+
import type { ExternalStoreAdapter } from "../runtimes/external-store/external-store-adapter";
|
|
8
|
+
|
|
9
|
+
type DemoMessage = { role: "user" | "assistant"; text: string };
|
|
10
|
+
|
|
11
|
+
const createRuntime = (
|
|
12
|
+
overrides?: Partial<ExternalStoreAdapter<DemoMessage>>,
|
|
13
|
+
) => {
|
|
14
|
+
const onNew = vi.fn(async () => {});
|
|
15
|
+
const adapter: ExternalStoreAdapter<DemoMessage> = {
|
|
16
|
+
messages: [{ role: "user", text: "hi" }],
|
|
17
|
+
convertMessage: (message) => ({
|
|
18
|
+
role: message.role,
|
|
19
|
+
content: [{ type: "text", text: message.text }],
|
|
20
|
+
}),
|
|
21
|
+
onNew,
|
|
22
|
+
...overrides,
|
|
23
|
+
};
|
|
24
|
+
const runtime = new AssistantRuntimeImpl(
|
|
25
|
+
new ExternalStoreRuntimeCore(adapter),
|
|
26
|
+
);
|
|
27
|
+
return { runtime, onNew };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe("RuntimeAdapter via the neutral store entry", () => {
|
|
31
|
+
it("mounts a runtime into a standalone client without React", () => {
|
|
32
|
+
const { runtime } = createRuntime();
|
|
33
|
+
const handle = createAssistantClient(
|
|
34
|
+
AuiConfig({ threads: RuntimeAdapter(runtime) }),
|
|
35
|
+
);
|
|
36
|
+
const aui = handle.getClient();
|
|
37
|
+
|
|
38
|
+
const messages = aui.thread.getState().messages;
|
|
39
|
+
expect(messages).toHaveLength(1);
|
|
40
|
+
expect(messages[0]!.content[0]).toMatchObject({
|
|
41
|
+
type: "text",
|
|
42
|
+
text: "hi",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(aui.threads.getState().mainThreadId).toBeDefined();
|
|
46
|
+
expect(aui.tools.getState()).toBeDefined();
|
|
47
|
+
expect(aui.dataRenderers.getState()).toBeDefined();
|
|
48
|
+
|
|
49
|
+
handle.destroy();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("routes composer sends to the external store adapter", async () => {
|
|
53
|
+
const { runtime, onNew } = createRuntime();
|
|
54
|
+
const handle = createAssistantClient(
|
|
55
|
+
AuiConfig({ threads: RuntimeAdapter(runtime) }),
|
|
56
|
+
);
|
|
57
|
+
const aui = handle.getClient();
|
|
58
|
+
|
|
59
|
+
flushTapSync(() => aui.composer.setText("hello"));
|
|
60
|
+
flushTapSync(() => aui.composer.send());
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve));
|
|
62
|
+
|
|
63
|
+
expect(onNew).toHaveBeenCalledTimes(1);
|
|
64
|
+
expect(onNew.mock.calls[0]![0]).toMatchObject({
|
|
65
|
+
content: [{ type: "text", text: "hello" }],
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
handle.destroy();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("registers the client's model context on the runtime", () => {
|
|
72
|
+
const { runtime } = createRuntime();
|
|
73
|
+
const register = vi.spyOn(runtime, "registerModelContextProvider");
|
|
74
|
+
|
|
75
|
+
const handle = createAssistantClient(
|
|
76
|
+
AuiConfig({ threads: RuntimeAdapter(runtime) }),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Dev mode double-mounts the root (StrictMode emulation), so assert
|
|
80
|
+
// presence rather than an exact count
|
|
81
|
+
expect(register).toHaveBeenCalled();
|
|
82
|
+
|
|
83
|
+
handle.destroy();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -9,8 +9,9 @@ import type { ThreadMessage } from "../../types/message";
|
|
|
9
9
|
|
|
10
10
|
const clientHolder: { client: unknown } = { client: null };
|
|
11
11
|
|
|
12
|
-
vi.mock("@assistant-ui/store", async (importOriginal) => {
|
|
13
|
-
const actual =
|
|
12
|
+
vi.mock("@assistant-ui/store/client", async (importOriginal) => {
|
|
13
|
+
const actual =
|
|
14
|
+
await importOriginal<typeof import("@assistant-ui/store/client")>();
|
|
14
15
|
return {
|
|
15
16
|
...actual,
|
|
16
17
|
useAssistantClientRef: () => ({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
|
|
2
2
|
import { resource } from "@assistant-ui/tap";
|
|
3
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
3
4
|
import {
|
|
4
|
-
useAssistantClientRef,
|
|
5
|
-
type ClientOutput,
|
|
6
5
|
attachTransformScopes,
|
|
7
|
-
|
|
6
|
+
useAssistantClientRef,
|
|
7
|
+
} from "@assistant-ui/store/client";
|
|
8
8
|
import type {
|
|
9
9
|
Unstable_InteractablesState,
|
|
10
10
|
Unstable_InteractableRegistration,
|
|
@@ -13,7 +13,7 @@ import type {
|
|
|
13
13
|
Unstable_InteractablesConfig,
|
|
14
14
|
} from "../types/scopes/interactables";
|
|
15
15
|
import { toJSONSchema, toPartialJSONSchema } from "assistant-stream";
|
|
16
|
-
import { ModelContext } from "../../store";
|
|
16
|
+
import { ModelContext } from "../../store/clients/model-context-client";
|
|
17
17
|
import {
|
|
18
18
|
buildInteractableModelContext,
|
|
19
19
|
type PartialJSONSchema,
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
withKey,
|
|
6
6
|
type ResourceElement,
|
|
7
7
|
} from "@assistant-ui/tap";
|
|
8
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
8
9
|
import {
|
|
9
|
-
useAssistantClientRef,
|
|
10
|
-
type ClientOutput,
|
|
11
10
|
attachTransformScopes,
|
|
12
|
-
|
|
11
|
+
useAssistantClientRef,
|
|
12
|
+
} from "@assistant-ui/store/client";
|
|
13
13
|
import type { McpAppResourceOutput, ToolsState } from "../types/scopes/tools";
|
|
14
14
|
import type { Tool } from "assistant-stream";
|
|
15
15
|
import {
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
type Toolkit,
|
|
19
19
|
} from "../model-context/toolbox";
|
|
20
20
|
import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
|
|
21
|
-
import { ModelContext } from "../../store";
|
|
21
|
+
import { ModelContext } from "../../store/clients/model-context-client";
|
|
22
22
|
|
|
23
23
|
export type { McpAppResourceOutput };
|
|
24
24
|
|
package/src/react/index.ts
CHANGED
|
@@ -228,6 +228,7 @@ export {
|
|
|
228
228
|
} from "./runtimes/useStreamingTiming";
|
|
229
229
|
export {
|
|
230
230
|
createRuntimeExtras,
|
|
231
|
+
unstable_createRuntimeExtrasFromBrand,
|
|
231
232
|
type RuntimeExtras,
|
|
232
233
|
} from "./runtimes/createRuntimeExtras";
|
|
233
234
|
export { RemoteThreadListHookInstanceManager } from "./runtimes/RemoteThreadListHookInstanceManager";
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import type { AssistantClient } from "@assistant-ui/store";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createRuntimeExtras,
|
|
5
|
+
unstable_createRuntimeExtrasFromBrand,
|
|
6
|
+
} from "./createRuntimeExtras";
|
|
7
|
+
import { createRuntimeExtrasBrand } from "../../runtime/utils/runtime-extras-brand";
|
|
4
8
|
|
|
5
9
|
type Extras = { value: number; greet: () => string };
|
|
6
10
|
|
|
@@ -55,4 +59,13 @@ describe("createRuntimeExtras", () => {
|
|
|
55
59
|
|
|
56
60
|
expect(() => channel.get(clientWith(undefined))).toThrow("useTestRuntime");
|
|
57
61
|
});
|
|
62
|
+
|
|
63
|
+
it("reads extras provided through a standalone brand instance", () => {
|
|
64
|
+
const brand = createRuntimeExtrasBrand<Extras>("useTestRuntime");
|
|
65
|
+
const channel = unstable_createRuntimeExtrasFromBrand(brand);
|
|
66
|
+
const branded = brand.provide({ value: 7, greet: () => "hi" });
|
|
67
|
+
|
|
68
|
+
expect(channel.is(branded)).toBe(true);
|
|
69
|
+
expect(channel.get(clientWith(branded)).value).toBe(7);
|
|
70
|
+
});
|
|
58
71
|
});
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { useAuiState } from "@assistant-ui/store";
|
|
4
4
|
import type { AssistantClient } from "@assistant-ui/store";
|
|
5
|
+
import {
|
|
6
|
+
createRuntimeExtrasBrand,
|
|
7
|
+
type RuntimeExtrasBrand,
|
|
8
|
+
} from "../../runtime/utils/runtime-extras-brand";
|
|
5
9
|
|
|
6
10
|
/** @deprecated Internal API for external-store adapter authors. Not part of the public API; may change or be removed without notice. */
|
|
7
11
|
export type RuntimeExtras<T extends object> = {
|
|
@@ -17,33 +21,10 @@ export type RuntimeExtras<T extends object> = {
|
|
|
17
21
|
};
|
|
18
22
|
|
|
19
23
|
/** @deprecated Internal API for external-store adapter authors. Not part of the public API; may change or be removed without notice. */
|
|
20
|
-
export const
|
|
21
|
-
|
|
24
|
+
export const unstable_createRuntimeExtrasFromBrand = <T extends object>(
|
|
25
|
+
brand: RuntimeExtrasBrand<T>,
|
|
22
26
|
): RuntimeExtras<T> => {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const is = (extras: unknown): extras is T =>
|
|
26
|
-
typeof extras === "object" && extras !== null && brand in extras;
|
|
27
|
-
|
|
28
|
-
const assert = (extras: unknown): T => {
|
|
29
|
-
if (!is(extras))
|
|
30
|
-
throw new Error(
|
|
31
|
-
`The current thread is not backed by the ${runtimeName} runtime.`,
|
|
32
|
-
);
|
|
33
|
-
return extras;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const provide = (value: T): T => {
|
|
37
|
-
Object.defineProperty(value, brand, {
|
|
38
|
-
value: true,
|
|
39
|
-
enumerable: false,
|
|
40
|
-
configurable: true,
|
|
41
|
-
});
|
|
42
|
-
return value;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const tryGet = (extras: unknown): T | undefined =>
|
|
46
|
-
is(extras) ? extras : undefined;
|
|
27
|
+
const { provide, is, tryGet, assert } = brand;
|
|
47
28
|
|
|
48
29
|
const get = (client: AssistantClient): T =>
|
|
49
30
|
assert(client.thread.getState().extras);
|
|
@@ -66,3 +47,11 @@ export const createRuntimeExtras = <T extends object>(
|
|
|
66
47
|
|
|
67
48
|
return { provide, is, tryGet, get, use: use as RuntimeExtras<T>["use"] };
|
|
68
49
|
};
|
|
50
|
+
|
|
51
|
+
/** @deprecated Internal API for external-store adapter authors. Not part of the public API; may change or be removed without notice. */
|
|
52
|
+
export const createRuntimeExtras = <T extends object>(
|
|
53
|
+
runtimeName: string,
|
|
54
|
+
): RuntimeExtras<T> =>
|
|
55
|
+
unstable_createRuntimeExtrasFromBrand(
|
|
56
|
+
createRuntimeExtrasBrand<T>(runtimeName),
|
|
57
|
+
);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** @deprecated Internal API for external-store adapter authors. Not part of the public API; may change or be removed without notice. */
|
|
2
|
+
export type RuntimeExtrasBrand<T extends object> = {
|
|
3
|
+
provide: (value: T) => T;
|
|
4
|
+
is: (extras: unknown) => extras is T;
|
|
5
|
+
tryGet: (extras: unknown) => T | undefined;
|
|
6
|
+
assert: (extras: unknown) => T;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates the framework-neutral half of a runtime extras channel: the brand
|
|
11
|
+
* symbol with its provide/read primitives. A runtime factory provides extras
|
|
12
|
+
* through the brand on any framework; the React entry wraps the same brand
|
|
13
|
+
* with a `use()` hook. The symbol is per-instance, so the adapter package
|
|
14
|
+
* creates the brand once and every binding imports that instance.
|
|
15
|
+
*
|
|
16
|
+
* @deprecated Internal API for external-store adapter authors. Not part of the public API; may change or be removed without notice.
|
|
17
|
+
*/
|
|
18
|
+
export const createRuntimeExtrasBrand = <T extends object>(
|
|
19
|
+
runtimeName: string,
|
|
20
|
+
): RuntimeExtrasBrand<T> => {
|
|
21
|
+
const brand = Symbol(`${runtimeName} extras`);
|
|
22
|
+
|
|
23
|
+
const is = (extras: unknown): extras is T =>
|
|
24
|
+
typeof extras === "object" && extras !== null && brand in extras;
|
|
25
|
+
|
|
26
|
+
const assert = (extras: unknown): T => {
|
|
27
|
+
if (!is(extras))
|
|
28
|
+
throw new Error(
|
|
29
|
+
`The current thread is not backed by the ${runtimeName} runtime.`,
|
|
30
|
+
);
|
|
31
|
+
return extras;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const provide = (value: T): T => {
|
|
35
|
+
Object.defineProperty(value, brand, {
|
|
36
|
+
value: true,
|
|
37
|
+
enumerable: false,
|
|
38
|
+
configurable: true,
|
|
39
|
+
});
|
|
40
|
+
return value;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const tryGet = (extras: unknown): T | undefined =>
|
|
44
|
+
is(extras) ? extras : undefined;
|
|
45
|
+
|
|
46
|
+
return { provide, is, tryGet, assert };
|
|
47
|
+
};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type ScopesConfig,
|
|
4
|
-
type AssistantClient,
|
|
5
|
-
} from "@assistant-ui/store";
|
|
1
|
+
import type { AssistantClient, ScopesConfig } from "@assistant-ui/store";
|
|
2
|
+
import { Derived } from "@assistant-ui/store/client";
|
|
6
3
|
import { ModelContext } from "./model-context-client";
|
|
7
4
|
import { Suggestions } from "./suggestions";
|
|
8
5
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { resource, withKey } from "@assistant-ui/tap";
|
|
3
3
|
import type { ClientOutput } from "@assistant-ui/store";
|
|
4
|
-
import { useClientLookup } from "@assistant-ui/store";
|
|
4
|
+
import { useClientLookup } from "@assistant-ui/store/client";
|
|
5
5
|
import type { SuggestionsState } from "../scopes/suggestions";
|
|
6
6
|
import type { SuggestionState } from "../scopes/suggestion";
|
|
7
7
|
|
|
@@ -7,7 +7,7 @@ import type { Attachment } from "../../types/attachment";
|
|
|
7
7
|
import { useMemo, useState } from "react";
|
|
8
8
|
import { useResource, resource, withKey } from "@assistant-ui/tap";
|
|
9
9
|
import type { ClientOutput } from "@assistant-ui/store";
|
|
10
|
-
import { useClientLookup } from "@assistant-ui/store";
|
|
10
|
+
import { useClientLookup } from "@assistant-ui/store/client";
|
|
11
11
|
import type { MessageState } from "../scopes/message";
|
|
12
12
|
import type { PartState } from "../scopes/part";
|
|
13
13
|
import { NoOpComposerClient } from "./no-op-composer-client";
|
package/src/store/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference path="./scope-registration.ts" />
|
|
2
|
+
/// <reference path="../react/types/store-augmentation.ts" />
|
|
2
3
|
|
|
3
4
|
// scopes
|
|
4
5
|
export type {
|
|
@@ -77,6 +78,36 @@ export type {
|
|
|
77
78
|
ChainOfThoughtPart,
|
|
78
79
|
} from "./scopes/chain-of-thought";
|
|
79
80
|
|
|
81
|
+
// runtime wiring
|
|
82
|
+
export { RuntimeAdapter } from "../react/RuntimeAdapter";
|
|
83
|
+
export {
|
|
84
|
+
useExternalMessageConverter,
|
|
85
|
+
convertExternalMessages,
|
|
86
|
+
type JoinStrategy,
|
|
87
|
+
} from "../react/runtimes/external-message-converter";
|
|
88
|
+
export {
|
|
89
|
+
useStreamingTiming,
|
|
90
|
+
type StreamingTimingAccessors,
|
|
91
|
+
type StreamingTimingOptions,
|
|
92
|
+
type StreamingTimingState,
|
|
93
|
+
} from "../react/runtimes/useStreamingTiming";
|
|
94
|
+
export {
|
|
95
|
+
createRuntimeExtrasBrand,
|
|
96
|
+
type RuntimeExtrasBrand,
|
|
97
|
+
} from "../runtime/utils/runtime-extras-brand";
|
|
98
|
+
export { defineToolkit } from "../react/model-context/define-toolkit";
|
|
99
|
+
export {
|
|
100
|
+
defineMcpToolkit,
|
|
101
|
+
type McpToolkitDefinition,
|
|
102
|
+
type McpToolkitEntry,
|
|
103
|
+
type McpToolkitToolConfig,
|
|
104
|
+
} from "../react/model-context/define-mcp-toolkit";
|
|
105
|
+
export type {
|
|
106
|
+
Toolkit,
|
|
107
|
+
ToolkitDefinition,
|
|
108
|
+
ToolkitDefinitionEntry,
|
|
109
|
+
} from "../react/model-context/toolbox";
|
|
110
|
+
|
|
80
111
|
// clients
|
|
81
112
|
export { NoOpComposerClient } from "./clients/no-op-composer-client";
|
|
82
113
|
export { Suggestions, type SuggestionConfig } from "./clients/suggestions";
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type { Unsubscribe } from "../../types/unsubscribe";
|
|
2
2
|
import { useMemo, useEffect } from "react";
|
|
3
3
|
import { useResource, resource, withKey } from "@assistant-ui/tap";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
useAssistantEmit,
|
|
7
|
-
useClientLookup,
|
|
8
|
-
} from "@assistant-ui/store";
|
|
4
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
5
|
+
import { useAssistantEmit, useClientLookup } from "@assistant-ui/store/client";
|
|
9
6
|
import type {
|
|
10
7
|
ComposerRuntime,
|
|
11
8
|
EditComposerRuntime,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
2
|
import { useResource, withKey, resource } from "@assistant-ui/tap";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
useClientLookup,
|
|
6
|
-
useClientResource,
|
|
7
|
-
} from "@assistant-ui/store";
|
|
3
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
4
|
+
import { useClientLookup, useClientResource } from "@assistant-ui/store/client";
|
|
8
5
|
import type { MessageRuntime } from "../../runtime/api/message-runtime";
|
|
9
6
|
import { useSubscribable } from "./useSubscribable";
|
|
10
7
|
import { liveRef } from "./liveRef";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Unsubscribe } from "../../types/unsubscribe";
|
|
2
2
|
import { useEffect, useMemo } from "react";
|
|
3
3
|
import { resource } from "@assistant-ui/tap";
|
|
4
|
-
import {
|
|
4
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
5
|
+
import { useAssistantEmit } from "@assistant-ui/store/client";
|
|
5
6
|
import type {
|
|
6
7
|
ThreadListItemEventType,
|
|
7
8
|
ThreadListItemRuntime,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { useResource, withKey, resource } from "@assistant-ui/tap";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
useClientLookup,
|
|
6
|
-
useClientResource,
|
|
7
|
-
} from "@assistant-ui/store";
|
|
3
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
4
|
+
import { useClientLookup, useClientResource } from "@assistant-ui/store/client";
|
|
8
5
|
import type { ThreadListRuntime } from "../../runtime/api/thread-list-runtime";
|
|
9
6
|
import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
|
|
10
7
|
import { useSubscribable } from "./useSubscribable";
|
|
@@ -4,12 +4,12 @@ import type { ThreadRuntime } from "../../runtime/api/thread-runtime";
|
|
|
4
4
|
import { useMemo, useEffect, type RefObject } from "react";
|
|
5
5
|
import { useResource, resource, withKey } from "@assistant-ui/tap";
|
|
6
6
|
import { liveRef } from "./liveRef";
|
|
7
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
7
8
|
import {
|
|
8
|
-
type ClientOutput,
|
|
9
9
|
useAssistantEmit,
|
|
10
10
|
useClientLookup,
|
|
11
11
|
useClientResource,
|
|
12
|
-
} from "@assistant-ui/store";
|
|
12
|
+
} from "@assistant-ui/store/client";
|
|
13
13
|
import { ComposerClient } from "./composer-runtime-client";
|
|
14
14
|
import { MessageClient } from "./message-runtime-client";
|
|
15
15
|
import { useSubscribable } from "./useSubscribable";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { existsSync, readFileSync,
|
|
3
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { dirname, join, relative, resolve } from "node:path";
|
|
5
5
|
|
|
6
6
|
const SRC_DIR = resolve(__dirname, "..");
|
|
@@ -108,19 +108,6 @@ function walkFrom(entry: string): { forbidden: string[]; jsxFiles: string[] } {
|
|
|
108
108
|
return { forbidden, jsxFiles };
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
function findFiles(dir: string, ext: string[]): string[] {
|
|
112
|
-
const results: string[] = [];
|
|
113
|
-
for (const entry of readdirSync(dir)) {
|
|
114
|
-
const full = join(dir, entry);
|
|
115
|
-
if (statSync(full).isDirectory()) {
|
|
116
|
-
results.push(...findFiles(full, ext));
|
|
117
|
-
} else if (ext.some((e) => full.endsWith(e))) {
|
|
118
|
-
results.push(full);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return results;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
111
|
function nonTypeImportNames(clause: string): string[] {
|
|
125
112
|
const names: string[] = [];
|
|
126
113
|
const trimmed = clause.trim();
|
|
@@ -183,15 +170,60 @@ describe("framework neutral boundary", () => {
|
|
|
183
170
|
).toEqual([]);
|
|
184
171
|
});
|
|
185
172
|
|
|
186
|
-
it("
|
|
187
|
-
const storeDir = resolve(SRC_DIR, "store");
|
|
188
|
-
const files = findFiles(storeDir, [".ts"]).filter(
|
|
189
|
-
(f) => !f.includes(".test."),
|
|
190
|
-
);
|
|
173
|
+
it("the store entry graphs stay hostable inside a tap root", () => {
|
|
191
174
|
const violations: string[] = [];
|
|
175
|
+
const jsxFiles: string[] = [];
|
|
176
|
+
const visited = new Set<string>();
|
|
177
|
+
const pending = [
|
|
178
|
+
resolve(SRC_DIR, "store/index.ts"),
|
|
179
|
+
resolve(SRC_DIR, "store/internal.ts"),
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
// Walks the runtime graph only: type-only imports are erased at build, so
|
|
183
|
+
// they neither carry runtime dependencies nor get traversed. This is also
|
|
184
|
+
// why type imports may keep using the @assistant-ui/store barrel: the
|
|
185
|
+
// augmentations target that specifier, and splitting types across entries
|
|
186
|
+
// would fork the ScopeRegistry seen by src-mapped consumers.
|
|
187
|
+
const RUNTIME_IMPORT_RE =
|
|
188
|
+
/(?:^|\n)\s*(?:import|export)\s+(?!type\b)(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\*|\w+(?:\s*,\s*(?:\{[^}]*\}|\*\s+as\s+\w+))?)\s+from\s+)?["']([^"']+)["']/g;
|
|
189
|
+
|
|
190
|
+
const collectRuntimeImports = (content: string): string[] => {
|
|
191
|
+
const specs: string[] = [];
|
|
192
|
+
for (const re of [RUNTIME_IMPORT_RE, DYNAMIC_IMPORT_RE]) {
|
|
193
|
+
re.lastIndex = 0;
|
|
194
|
+
let match: RegExpExecArray | null;
|
|
195
|
+
while ((match = re.exec(content)) !== null) {
|
|
196
|
+
specs.push(match[1]!);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return specs;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
while (pending.length > 0) {
|
|
203
|
+
const file = pending.pop()!;
|
|
204
|
+
if (visited.has(file)) continue;
|
|
205
|
+
visited.add(file);
|
|
206
|
+
if (file.endsWith(".tsx")) jsxFiles.push(relative(SRC_DIR, file));
|
|
192
207
|
|
|
193
|
-
for (const file of files) {
|
|
194
208
|
const content = readFileSync(file, "utf-8");
|
|
209
|
+
|
|
210
|
+
for (const spec of collectRuntimeImports(content)) {
|
|
211
|
+
if (spec === "react/jsx-runtime") {
|
|
212
|
+
violations.push(
|
|
213
|
+
`${relative(SRC_DIR, file)} imports "react/jsx-runtime"`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (spec === "@assistant-ui/store") {
|
|
217
|
+
violations.push(
|
|
218
|
+
`${relative(SRC_DIR, file)} value-imports the "@assistant-ui/store" barrel; use "@assistant-ui/store/client"`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
const resolved = resolveRelative(file, spec);
|
|
222
|
+
if (resolved && !visited.has(resolved)) {
|
|
223
|
+
pending.push(resolved);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
195
227
|
FROM_REACT_RE.lastIndex = 0;
|
|
196
228
|
let match: RegExpExecArray | null;
|
|
197
229
|
while ((match = FROM_REACT_RE.exec(content)) !== null) {
|
|
@@ -210,12 +242,16 @@ describe("framework neutral boundary", () => {
|
|
|
210
242
|
|
|
211
243
|
expect(
|
|
212
244
|
violations,
|
|
213
|
-
`
|
|
214
|
-
`
|
|
215
|
-
`
|
|
216
|
-
`useContext, createContext).\n` +
|
|
245
|
+
`The store entry graphs run inside tap roots on every framework, so they may ` +
|
|
246
|
+
`only use react names the tap shim dispatches, never react/jsx-runtime, and ` +
|
|
247
|
+
`never the @assistant-ui/store barrel (whose module scope requires React).\n` +
|
|
217
248
|
`Violations:\n` +
|
|
218
249
|
violations.map((f) => ` - ${f}`).join("\n"),
|
|
219
250
|
).toEqual([]);
|
|
251
|
+
expect(
|
|
252
|
+
jsxFiles,
|
|
253
|
+
`The JSX transform injects react/jsx-runtime at build time, so the store entry graphs must not contain .tsx files:\n` +
|
|
254
|
+
jsxFiles.map((f) => ` - ${f}`).join("\n"),
|
|
255
|
+
).toEqual([]);
|
|
220
256
|
});
|
|
221
257
|
});
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 AgentbaseAI Inc.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|