assistant-ui 0.0.116 → 0.0.118
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/codemods/utils/createTransformer.d.ts +13 -16
- package/dist/codemods/utils/createTransformer.d.ts.map +1 -1
- package/dist/codemods/utils/resolveBinding.d.ts +3 -0
- package/dist/codemods/utils/resolveBinding.d.ts.map +1 -0
- package/dist/codemods/utils/resolveBinding.js +78 -0
- package/dist/codemods/utils/resolveBinding.js.map +1 -0
- package/dist/codemods/v0-11/content-part-to-message-part.d.ts +1 -3
- package/dist/codemods/v0-11/content-part-to-message-part.d.ts.map +1 -1
- package/dist/codemods/v0-12/assistant-api-to-aui.d.ts +1 -3
- package/dist/codemods/v0-12/assistant-api-to-aui.d.ts.map +1 -1
- package/dist/codemods/v0-12/assistant-api-to-aui.js +51 -99
- package/dist/codemods/v0-12/assistant-api-to-aui.js.map +1 -1
- package/dist/codemods/v0-12/event-names-to-camelcase.d.ts +1 -3
- package/dist/codemods/v0-12/event-names-to-camelcase.d.ts.map +1 -1
- package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts +1 -3
- package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts.map +1 -1
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.d.ts +1 -3
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.d.ts.map +1 -1
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.js +33 -5
- package/dist/codemods/v0-15/aui-accessor-calls-to-properties.js.map +1 -1
- package/dist/codemods/v0-8/ui-package-split.d.ts +1 -3
- package/dist/codemods/v0-8/ui-package-split.d.ts.map +1 -1
- package/dist/codemods/v0-9/edge-package-split.d.ts +1 -3
- package/dist/codemods/v0-9/edge-package-split.d.ts.map +1 -1
- package/dist/commands/add.d.ts +13 -16
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +3 -3
- package/dist/commands/agent.d.ts +1 -4
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +16 -13
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/create.d.ts +43 -39
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +40 -26
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/doctor.d.ts +17 -20
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/info.d.ts +4 -6
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +3 -3
- package/dist/commands/init.d.ts +8 -10
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +3 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts +1 -4
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +2 -2
- package/dist/commands/update.d.ts +1 -4
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +1 -1
- package/dist/commands/upgrade.d.ts +7 -10
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/agent-skill.d.ts +11 -10
- package/dist/lib/agent-skill.d.ts.map +1 -1
- package/dist/lib/agent-skill.js +78 -2
- package/dist/lib/agent-skill.js.map +1 -1
- package/dist/lib/create-project.d.ts +33 -32
- package/dist/lib/create-project.d.ts.map +1 -1
- package/dist/lib/create-project.js +91 -5
- package/dist/lib/create-project.js.map +1 -1
- package/dist/lib/handle-cli-error.d.ts +1 -4
- package/dist/lib/handle-cli-error.d.ts.map +1 -1
- package/dist/lib/install-ai-sdk-lib.d.ts +1 -4
- package/dist/lib/install-ai-sdk-lib.d.ts.map +1 -1
- package/dist/lib/install-edge-lib.d.ts +1 -4
- package/dist/lib/install-edge-lib.d.ts.map +1 -1
- package/dist/lib/run-spawn.d.ts +17 -19
- package/dist/lib/run-spawn.d.ts.map +1 -1
- package/dist/lib/run-spawn.js +25 -10
- package/dist/lib/run-spawn.js.map +1 -1
- package/dist/lib/transform-options.d.ts +5 -8
- package/dist/lib/transform-options.d.ts.map +1 -1
- package/dist/lib/transform.d.ts +13 -16
- package/dist/lib/transform.d.ts.map +1 -1
- package/dist/lib/transform.js +19 -35
- package/dist/lib/transform.js.map +1 -1
- package/dist/lib/upgrade.d.ts +3 -6
- package/dist/lib/upgrade.d.ts.map +1 -1
- package/dist/lib/upgrade.js +6 -11
- package/dist/lib/upgrade.js.map +1 -1
- package/dist/lib/utils/config.d.ts +18 -21
- package/dist/lib/utils/config.d.ts.map +1 -1
- package/dist/lib/utils/file-scanner.d.ts +12 -15
- package/dist/lib/utils/file-scanner.d.ts.map +1 -1
- package/dist/lib/utils/logger.d.ts +7 -10
- package/dist/lib/utils/logger.d.ts.map +1 -1
- package/dist/lib/utils/package-installer.d.ts +7 -10
- package/dist/lib/utils/package-installer.d.ts.map +1 -1
- package/dist/lib/utils/package-json.d.ts +1 -4
- package/dist/lib/utils/package-json.d.ts.map +1 -1
- package/dist/lib/utils/package-manager.d.ts +9 -12
- package/dist/lib/utils/package-manager.d.ts.map +1 -1
- package/dist/lib/utils/package-manager.js +13 -2
- package/dist/lib/utils/package-manager.js.map +1 -1
- package/dist/lib/utils/registry.d.ts +5 -8
- package/dist/lib/utils/registry.d.ts.map +1 -1
- package/dist/lib/utils/workspace.d.ts +2 -5
- package/dist/lib/utils/workspace.d.ts.map +1 -1
- package/dist/program.d.ts +1 -4
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +6 -6
- package/dist/run.d.ts +1 -4
- package/dist/run.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/codemods/utils/resolveBinding.test.ts +107 -0
- package/src/codemods/utils/resolveBinding.ts +130 -0
- package/src/codemods/v0-12/__tests__/assistant-api-to-aui.test.ts +256 -0
- package/src/codemods/v0-12/assistant-api-to-aui.ts +125 -225
- package/src/codemods/v0-15/__tests__/aui-accessor-calls-to-properties.test.ts +101 -0
- package/src/codemods/v0-15/aui-accessor-calls-to-properties.ts +60 -5
- package/src/commands/agent.ts +15 -22
- package/src/commands/create.ts +53 -20
- package/src/commands/init.ts +1 -2
- package/src/lib/agent-skill.ts +103 -1
- package/src/lib/create-project.ts +99 -4
- package/src/lib/run-spawn.test.ts +47 -0
- package/src/lib/run-spawn.ts +29 -17
- package/src/lib/transform-files.test.ts +71 -0
- package/src/lib/transform.test.ts +69 -1
- package/src/lib/transform.ts +23 -38
- package/src/lib/upgrade.ts +9 -13
- package/src/lib/utils/package-manager.ts +24 -1
- package/plugin/.claude-plugin/plugin.json +0 -8
- package/plugin/skills/assistant-ui/SKILL.md +0 -199
- package/plugin/skills/assistant-ui/shipables.json +0 -22
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
1
|
+
import { describe, expect, it, onTestFinished, vi } from "vitest";
|
|
2
|
+
import { mkdtempSync, writeFileSync, rmSync, readFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
2
6
|
|
|
3
7
|
const mocks = vi.hoisted(() => ({
|
|
4
8
|
runSpawnCapture: vi.fn(),
|
|
@@ -13,6 +17,63 @@ import { transform } from "./transform";
|
|
|
13
17
|
import { SpawnExitError } from "./run-spawn";
|
|
14
18
|
|
|
15
19
|
describe("transform", () => {
|
|
20
|
+
it.each(["parse", "transform"])(
|
|
21
|
+
"rejects real jscodeshift %s failures",
|
|
22
|
+
async (kind) => {
|
|
23
|
+
const directory = mkdtempSync(join(tmpdir(), "aui-transform-errors-"));
|
|
24
|
+
onTestFinished(() => rmSync(directory, { recursive: true, force: true }));
|
|
25
|
+
const file = join(directory, "app.tsx");
|
|
26
|
+
const source =
|
|
27
|
+
kind === "parse"
|
|
28
|
+
? 'import "@assistant-ui/react"; const broken = ;'
|
|
29
|
+
: 'import "@assistant-ui/react"; const value = 1;';
|
|
30
|
+
writeFileSync(file, source);
|
|
31
|
+
const codemod = join(directory, "transform.cjs");
|
|
32
|
+
writeFileSync(
|
|
33
|
+
codemod,
|
|
34
|
+
kind === "parse"
|
|
35
|
+
? "module.exports = (file, api) => api.jscodeshift(file.source).toSource();"
|
|
36
|
+
: 'module.exports = () => { throw new Error("fixture transform failure"); };',
|
|
37
|
+
);
|
|
38
|
+
const actual =
|
|
39
|
+
await vi.importActual<typeof import("./run-spawn")>("./run-spawn");
|
|
40
|
+
const require = createRequire(import.meta.url);
|
|
41
|
+
mocks.runSpawnCapture.mockImplementationOnce(
|
|
42
|
+
(_command: string, args: string[]) => {
|
|
43
|
+
const runnerArgs = args.slice(1);
|
|
44
|
+
runnerArgs[runnerArgs.indexOf("-t") + 1] = codemod;
|
|
45
|
+
return actual.runSpawnCapture(process.execPath, [
|
|
46
|
+
require.resolve("jscodeshift/bin/jscodeshift.js"),
|
|
47
|
+
...runnerArgs,
|
|
48
|
+
"--run-in-band",
|
|
49
|
+
]);
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const failure = transform(
|
|
54
|
+
"v0-12/assistant-api-to-aui",
|
|
55
|
+
directory,
|
|
56
|
+
{},
|
|
57
|
+
{
|
|
58
|
+
logStatus: false,
|
|
59
|
+
relevantFiles: [file],
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
await expect(failure).rejects.toBeInstanceOf(SpawnExitError);
|
|
63
|
+
await expect(failure).rejects.toThrow(
|
|
64
|
+
"Codemod 'v0-12/assistant-api-to-aui' failed",
|
|
65
|
+
);
|
|
66
|
+
await expect(failure).rejects.toThrow(
|
|
67
|
+
kind === "parse" ? "Transformation error" : "fixture transform failure",
|
|
68
|
+
);
|
|
69
|
+
await expect(failure).rejects.toMatchObject({
|
|
70
|
+
stdout: expect.stringContaining("Transformation error"),
|
|
71
|
+
});
|
|
72
|
+
expect(readFileSync(file, "utf8")).toBe(source);
|
|
73
|
+
},
|
|
74
|
+
15_000,
|
|
75
|
+
);
|
|
76
|
+
|
|
16
77
|
it("runs codemods asynchronously and reports progress", async () => {
|
|
17
78
|
mocks.runSpawnCapture.mockResolvedValue({
|
|
18
79
|
code: 0,
|
|
@@ -62,7 +123,14 @@ describe("transform", () => {
|
|
|
62
123
|
);
|
|
63
124
|
|
|
64
125
|
await expect(failure).rejects.toBeInstanceOf(SpawnExitError);
|
|
126
|
+
await expect(failure).rejects.toThrow(
|
|
127
|
+
"Codemod 'v0-8/ui-package-split' failed",
|
|
128
|
+
);
|
|
65
129
|
await expect(failure).rejects.toThrow("SyntaxError: Broken input");
|
|
130
|
+
await expect(failure).rejects.toMatchObject({
|
|
131
|
+
stdout: "Processing file app.tsx\n",
|
|
132
|
+
stderr: "SyntaxError: Broken input\n",
|
|
133
|
+
});
|
|
66
134
|
expect(onProgress).not.toHaveBeenCalled();
|
|
67
135
|
});
|
|
68
136
|
|
package/src/lib/transform.ts
CHANGED
|
@@ -7,19 +7,23 @@ import { sync as globSync } from "glob";
|
|
|
7
7
|
import { runSpawnCapture, SpawnExitError, SpawnSignalError } from "./run-spawn";
|
|
8
8
|
|
|
9
9
|
const log = debug("codemod:transform");
|
|
10
|
-
const error = debug("codemod:transform:error");
|
|
11
10
|
|
|
12
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
12
|
const __dirname = path.dirname(__filename);
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
|
-
* Gets
|
|
17
|
-
*
|
|
15
|
+
* Gets relevant source files from an explicit file or directory target.
|
|
16
|
+
* Directory scans only include files containing "assistant-ui".
|
|
18
17
|
*/
|
|
19
|
-
export function getRelevantFiles(
|
|
18
|
+
export function getRelevantFiles(source: string): string[] {
|
|
19
|
+
const target = path.resolve(source);
|
|
20
|
+
if (fs.statSync(target).isFile()) {
|
|
21
|
+
return /\.(js|jsx|ts|tsx)$/.test(target) ? [target] : [];
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
const pattern = "**/*.{js,jsx,ts,tsx}";
|
|
21
25
|
const files = globSync(pattern, {
|
|
22
|
-
cwd,
|
|
26
|
+
cwd: target,
|
|
23
27
|
ignore: [
|
|
24
28
|
"**/node_modules/**",
|
|
25
29
|
"**/dist/**",
|
|
@@ -27,26 +31,25 @@ export function getRelevantFiles(cwd: string): string[] {
|
|
|
27
31
|
"**/*.min.js",
|
|
28
32
|
"**/*.bundle.js",
|
|
29
33
|
],
|
|
30
|
-
});
|
|
34
|
+
}).map((file) => path.join(target, file));
|
|
31
35
|
|
|
32
|
-
// Filter files to only include those containing "assistant-ui"
|
|
33
36
|
const relevantFiles = files.filter((file) => {
|
|
34
37
|
try {
|
|
35
|
-
const content = fs.readFileSync(
|
|
38
|
+
const content = fs.readFileSync(file, "utf8");
|
|
36
39
|
return content.includes("assistant-ui");
|
|
37
40
|
} catch {
|
|
38
41
|
return false;
|
|
39
42
|
}
|
|
40
43
|
});
|
|
41
44
|
|
|
42
|
-
return relevantFiles
|
|
45
|
+
return relevantFiles;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
/**
|
|
46
49
|
* Counts the number of files that need to be processed
|
|
47
50
|
*/
|
|
48
|
-
export function countFilesToProcess(
|
|
49
|
-
return getRelevantFiles(
|
|
51
|
+
export function countFilesToProcess(source: string): number {
|
|
52
|
+
return getRelevantFiles(source).length;
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
function buildCommand(
|
|
@@ -62,6 +65,7 @@ function buildCommand(
|
|
|
62
65
|
...targetFiles,
|
|
63
66
|
"--parser",
|
|
64
67
|
"tsx",
|
|
68
|
+
"--fail-on-error",
|
|
65
69
|
];
|
|
66
70
|
|
|
67
71
|
if (options.dry) {
|
|
@@ -89,23 +93,6 @@ export type TransformErrors = {
|
|
|
89
93
|
summary: string;
|
|
90
94
|
}[];
|
|
91
95
|
|
|
92
|
-
function parseErrors(transform: string, output: string): TransformErrors {
|
|
93
|
-
const errors: TransformErrors = [];
|
|
94
|
-
const errorRegex = /ERR (.+) Transformation error/g;
|
|
95
|
-
const syntaxErrorRegex = /SyntaxError: .+/g;
|
|
96
|
-
|
|
97
|
-
for (const match of output.matchAll(errorRegex)) {
|
|
98
|
-
const filename = match[1]!;
|
|
99
|
-
const syntaxErrorMatch = syntaxErrorRegex.exec(output);
|
|
100
|
-
if (syntaxErrorMatch) {
|
|
101
|
-
const summary = syntaxErrorMatch[0];
|
|
102
|
-
errors.push({ transform, filename, summary });
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return errors;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
96
|
export async function transform(
|
|
110
97
|
codemod: string,
|
|
111
98
|
source: string,
|
|
@@ -138,7 +125,13 @@ export async function transform(
|
|
|
138
125
|
throw new SpawnSignalError(result.signal, false);
|
|
139
126
|
}
|
|
140
127
|
if (result.code !== 0) {
|
|
141
|
-
|
|
128
|
+
const failure = new SpawnExitError(
|
|
129
|
+
result.code || 1,
|
|
130
|
+
result.stderr,
|
|
131
|
+
result.stdout,
|
|
132
|
+
);
|
|
133
|
+
failure.message = `Codemod '${codemod}' failed\n${failure.message}`;
|
|
134
|
+
throw failure;
|
|
142
135
|
}
|
|
143
136
|
|
|
144
137
|
const { stdout } = result;
|
|
@@ -148,13 +141,5 @@ export async function transform(
|
|
|
148
141
|
options.onProgress(processedFiles);
|
|
149
142
|
}
|
|
150
143
|
|
|
151
|
-
|
|
152
|
-
if (options.logStatus && errors.length > 0) {
|
|
153
|
-
errors.forEach(({ transform, filename, summary }) => {
|
|
154
|
-
error(
|
|
155
|
-
`Error applying codemod [codemod=${transform}, path=${filename}, summary=${summary}]`,
|
|
156
|
-
);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
return errors;
|
|
144
|
+
return [];
|
|
160
145
|
}
|
package/src/lib/upgrade.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
|
-
import { transform,
|
|
2
|
+
import { transform, getRelevantFiles } from "./transform";
|
|
3
3
|
import type { TransformOptions } from "./transform-options";
|
|
4
4
|
import { SingleBar, Presets } from "cli-progress";
|
|
5
5
|
import installEdgeLib from "./install-edge-lib";
|
|
@@ -16,13 +16,12 @@ const bundle = [
|
|
|
16
16
|
];
|
|
17
17
|
|
|
18
18
|
const log = debug("codemod:upgrade");
|
|
19
|
-
const error = debug("codemod:upgrade:error");
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
21
|
* Runs the upgrade cycle:
|
|
23
22
|
* - Runs each codemod in the bundle.
|
|
24
23
|
* - Displays progress using cli-progress.
|
|
25
|
-
* -
|
|
24
|
+
* - Outside dry mode, checks for new package imports and prompts for install.
|
|
26
25
|
*/
|
|
27
26
|
export async function upgrade(options: TransformOptions) {
|
|
28
27
|
const cwd = process.cwd();
|
|
@@ -48,14 +47,13 @@ export async function upgrade(options: TransformOptions) {
|
|
|
48
47
|
);
|
|
49
48
|
|
|
50
49
|
bar.start(totalWork, 0, { status: "Starting..." });
|
|
51
|
-
const allErrors: TransformErrors = [];
|
|
52
50
|
|
|
53
51
|
try {
|
|
54
52
|
for (const codemod of bundle) {
|
|
55
53
|
bar.update(completedWork, { status: `Running ${codemod}...` });
|
|
56
54
|
|
|
57
55
|
// Use a custom progress callback to update the progress bar
|
|
58
|
-
|
|
56
|
+
await transform(codemod, cwd, options, {
|
|
59
57
|
logStatus: false,
|
|
60
58
|
onProgress: (processedFiles: number) => {
|
|
61
59
|
completedWork = bundle.indexOf(codemod) * fileCount + processedFiles;
|
|
@@ -66,24 +64,22 @@ export async function upgrade(options: TransformOptions) {
|
|
|
66
64
|
relevantFiles, // Pass the pre-computed relevant files
|
|
67
65
|
});
|
|
68
66
|
|
|
69
|
-
allErrors.push(...errors);
|
|
70
67
|
completedWork = (bundle.indexOf(codemod) + 1) * fileCount;
|
|
71
68
|
bar.update(completedWork, { status: `Completed ${codemod}` });
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
bar.update(totalWork, {
|
|
71
|
+
bar.update(totalWork, {
|
|
72
|
+
status: options.dry ? "Preview complete" : "Checking dependencies...",
|
|
73
|
+
});
|
|
75
74
|
} finally {
|
|
76
75
|
bar.stop();
|
|
77
76
|
}
|
|
78
77
|
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
error(`codemod=${transform}, path=${filename}, summary=${summary}`);
|
|
83
|
-
});
|
|
78
|
+
if (options.dry) {
|
|
79
|
+
logger.success("Dry run complete. No files were changed.");
|
|
80
|
+
return;
|
|
84
81
|
}
|
|
85
82
|
|
|
86
|
-
// After codemods run, check if files import from the new packages and prompt for install.
|
|
87
83
|
logger.info("Checking for package dependencies...");
|
|
88
84
|
await installEdgeLib();
|
|
89
85
|
await installAiSdkLib();
|
|
@@ -9,13 +9,36 @@ export type PackageManagerName = "npm" | "pnpm" | "yarn" | "bun";
|
|
|
9
9
|
|
|
10
10
|
export function askQuestion(query: string): Promise<string> {
|
|
11
11
|
return new Promise((resolve) => {
|
|
12
|
+
// A stream only reaches EOF once, so a run that already consumed stdin gets
|
|
13
|
+
// no further `end` and an interface built over it would wait on a `close`
|
|
14
|
+
// that cannot arrive. An upgrade asks up to three questions.
|
|
15
|
+
if (process.stdin.readableEnded) {
|
|
16
|
+
resolve("");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
12
19
|
const rl = readline.createInterface({
|
|
13
20
|
input: process.stdin,
|
|
14
21
|
output: process.stdout,
|
|
15
22
|
});
|
|
16
|
-
|
|
23
|
+
// stdin at EOF (a piped or CI run) emits `close` without a `line`, so the
|
|
24
|
+
// question callback alone would leave this pending forever and the process
|
|
25
|
+
// would exit 0 with the remaining work silently skipped. An empty answer is
|
|
26
|
+
// what pressing Enter sends, so EOF lands on the prompt's own default.
|
|
27
|
+
// A final answer with no trailing newline arrives as `line` instead of
|
|
28
|
+
// through the callback, and has to win over that default.
|
|
29
|
+
// Ctrl-C in raw mode is delivered as this event rather than as a signal,
|
|
30
|
+
// and without a listener readline answers it by closing — which the EOF
|
|
31
|
+
// default would then read as approval. A cancelled prompt declines.
|
|
32
|
+
let cancelled = false;
|
|
33
|
+
rl.on("SIGINT", () => {
|
|
34
|
+
cancelled = true;
|
|
17
35
|
rl.close();
|
|
36
|
+
});
|
|
37
|
+
rl.on("line", resolve);
|
|
38
|
+
rl.on("close", () => resolve(cancelled ? "n" : ""));
|
|
39
|
+
rl.question(query, (answer) => {
|
|
18
40
|
resolve(answer);
|
|
41
|
+
rl.close();
|
|
19
42
|
});
|
|
20
43
|
});
|
|
21
44
|
}
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: assistant-ui
|
|
3
|
-
description: Add, configure, and integrate assistant-ui components in React apps. Use when developers ask to add a chat thread, set up a runtime, integrate with AI SDK, configure tools, or build AI chat interfaces with assistant-ui.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# assistant-ui
|
|
7
|
-
|
|
8
|
-
Use this skill to help users build AI chat interfaces with assistant-ui.
|
|
9
|
-
|
|
10
|
-
## Step 1: Check Project Setup
|
|
11
|
-
|
|
12
|
-
Check if the project has `components.json` (shadcn config) and `@assistant-ui/react` installed.
|
|
13
|
-
|
|
14
|
-
If assistant-ui is not yet set up, run:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npx assistant-ui init --yes
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
This initializes shadcn and installs the default assistant-ui chat components.
|
|
21
|
-
|
|
22
|
-
## Step 2: Add Components
|
|
23
|
-
|
|
24
|
-
Install components via the shadcn registry:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npx shadcn@latest add "https://r.assistant-ui.com/base/chat/b/ai-sdk-quick-start/json"
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
For Radix-styled projects (`components.json` style not starting with `base-`), use `https://r.assistant-ui.com/chat/b/ai-sdk-quick-start/json` instead.
|
|
31
|
-
|
|
32
|
-
Available component presets:
|
|
33
|
-
|
|
34
|
-
| Preset | Registry URL |
|
|
35
|
-
|--------|-------------|
|
|
36
|
-
| AI SDK Quick Start | `https://r.assistant-ui.com/base/chat/b/ai-sdk-quick-start/json` |
|
|
37
|
-
|
|
38
|
-
You can also add individual assistant-ui components with the assistant-ui CLI, which picks the right flavor from `components.json`:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npx assistant-ui add thread
|
|
42
|
-
npx assistant-ui add markdown-text
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
To use the shadcn CLI directly instead, add the assistant-ui registry to `components.json`:
|
|
46
|
-
|
|
47
|
-
```json
|
|
48
|
-
{
|
|
49
|
-
"registries": {
|
|
50
|
-
"@assistant-ui": "https://r.assistant-ui.com/styles/{style}/{name}.json"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Then add components with the namespaced form:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
npx shadcn@latest add @assistant-ui/thread
|
|
59
|
-
npx shadcn@latest add @assistant-ui/markdown-text
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Step 3: Runtime Setup
|
|
63
|
-
|
|
64
|
-
assistant-ui requires a runtime. The most common setup uses AI SDK:
|
|
65
|
-
|
|
66
|
-
### AI SDK Runtime (recommended)
|
|
67
|
-
|
|
68
|
-
Install the integration package:
|
|
69
|
-
```bash
|
|
70
|
-
npm install @assistant-ui/ai-sdk
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Create a chat API route (Next.js App Router):
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
// app/api/chat/route.ts
|
|
77
|
-
import { openai } from "@ai-sdk/openai";
|
|
78
|
-
import { streamText } from "ai";
|
|
79
|
-
|
|
80
|
-
export const maxDuration = 30;
|
|
81
|
-
|
|
82
|
-
export async function POST(req: Request) {
|
|
83
|
-
const { messages, config } = await req.json();
|
|
84
|
-
|
|
85
|
-
const result = streamText({
|
|
86
|
-
model: openai("gpt-5.6-luna"),
|
|
87
|
-
messages,
|
|
88
|
-
...config,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return result.toDataStreamResponse();
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Create the assistant component:
|
|
96
|
-
|
|
97
|
-
```tsx
|
|
98
|
-
"use client";
|
|
99
|
-
|
|
100
|
-
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
101
|
-
import { useChatRuntime } from "@assistant-ui/ai-sdk";
|
|
102
|
-
import { Thread } from "@/components/assistant-ui/elements/thread.aui";
|
|
103
|
-
|
|
104
|
-
export const Assistant = () => {
|
|
105
|
-
const runtime = useChatRuntime({
|
|
106
|
-
api: "/api/chat",
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<AssistantRuntimeProvider runtime={runtime}>
|
|
111
|
-
<Thread />
|
|
112
|
-
</AssistantRuntimeProvider>
|
|
113
|
-
);
|
|
114
|
-
};
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Step 4: Tools (optional)
|
|
118
|
-
|
|
119
|
-
To add tool calling support, define tools on the backend and render them on the frontend:
|
|
120
|
-
|
|
121
|
-
### Backend tool (AI SDK):
|
|
122
|
-
|
|
123
|
-
```ts
|
|
124
|
-
import { streamText, tool } from "ai";
|
|
125
|
-
import { z } from "zod";
|
|
126
|
-
|
|
127
|
-
const result = streamText({
|
|
128
|
-
model: openai("gpt-5.6-luna"),
|
|
129
|
-
messages,
|
|
130
|
-
tools: {
|
|
131
|
-
get_weather: tool({
|
|
132
|
-
description: "Get weather for a location",
|
|
133
|
-
parameters: z.object({
|
|
134
|
-
location: z.string(),
|
|
135
|
-
}),
|
|
136
|
-
execute: async ({ location }) => {
|
|
137
|
-
return { temperature: 72, condition: "sunny", location };
|
|
138
|
-
},
|
|
139
|
-
}),
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Frontend tool UI:
|
|
145
|
-
|
|
146
|
-
Create a toolkit with a renderer for the tool. The tool executes on the backend, so the entry uses `externalTool()` and only attaches UI:
|
|
147
|
-
|
|
148
|
-
```tsx
|
|
149
|
-
// app/toolkit.tsx
|
|
150
|
-
"use generative";
|
|
151
|
-
|
|
152
|
-
import { defineToolkit, externalTool } from "@assistant-ui/react";
|
|
153
|
-
|
|
154
|
-
export default defineToolkit({
|
|
155
|
-
get_weather: {
|
|
156
|
-
execute: externalTool(),
|
|
157
|
-
render: ({ args, result }) => {
|
|
158
|
-
return (
|
|
159
|
-
<div>
|
|
160
|
-
<p>Weather for {args?.location}</p>
|
|
161
|
-
{result && <p>{result.temperature}F, {result.condition}</p>}
|
|
162
|
-
</div>
|
|
163
|
-
);
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Register the toolkit in your assistant component:
|
|
170
|
-
|
|
171
|
-
```tsx
|
|
172
|
-
import { AssistantRuntimeProvider, Tools, useAui } from "@assistant-ui/react";
|
|
173
|
-
import toolkit from "@/app/toolkit";
|
|
174
|
-
|
|
175
|
-
const aui = useAui({
|
|
176
|
-
tools: Tools({ toolkit }),
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
<AssistantRuntimeProvider aui={aui} runtime={runtime}>
|
|
180
|
-
<Thread />
|
|
181
|
-
</AssistantRuntimeProvider>
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
Do not use `makeAssistantToolUI`, `useAssistantToolUI`, `makeAssistantTool`, or `useAssistantTool`; they are deprecated in favor of toolkits.
|
|
185
|
-
|
|
186
|
-
## Key Packages
|
|
187
|
-
|
|
188
|
-
| Package | Purpose |
|
|
189
|
-
|---------|---------|
|
|
190
|
-
| `@assistant-ui/react` | Core React components and primitives |
|
|
191
|
-
| `@assistant-ui/ai-sdk` | Vercel AI SDK integration |
|
|
192
|
-
| `@assistant-ui/react-markdown` | Markdown rendering |
|
|
193
|
-
| `@assistant-ui/react-syntax-highlighter` | Code highlighting |
|
|
194
|
-
| `@assistant-ui/ui` | Pre-built shadcn/ui component set |
|
|
195
|
-
| `@assistant-ui/styles` | Pre-built CSS for non-Tailwind users |
|
|
196
|
-
|
|
197
|
-
## Environment Variables
|
|
198
|
-
|
|
199
|
-
For OpenAI-based setups, ensure `OPENAI_API_KEY` is set in `.env.local`.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "1.0.0",
|
|
3
|
-
"keywords": [
|
|
4
|
-
"assistant-ui",
|
|
5
|
-
"chat",
|
|
6
|
-
"ai",
|
|
7
|
-
"chatbot",
|
|
8
|
-
"react",
|
|
9
|
-
"ai-sdk",
|
|
10
|
-
"shadcn",
|
|
11
|
-
"thread",
|
|
12
|
-
"copilot",
|
|
13
|
-
"assistant"
|
|
14
|
-
],
|
|
15
|
-
"categories": ["frameworks", "ai-ml"],
|
|
16
|
-
"author": {
|
|
17
|
-
"name": "Yonom",
|
|
18
|
-
"github": "Yonom"
|
|
19
|
-
},
|
|
20
|
-
"repository": "https://github.com/assistant-ui/assistant-ui",
|
|
21
|
-
"homepage": "https://www.assistant-ui.com"
|
|
22
|
-
}
|