ai-test-kit 0.0.1
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/LICENSE +21 -0
- package/README.md +924 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +1 -0
- package/dist/language/index.d.mts +218 -0
- package/dist/language/index.mjs +363 -0
- package/dist/tokenize-C-Zp26iY.mjs +13 -0
- package/dist/ui/index.d.mts +2302 -0
- package/dist/ui/index.mjs +266 -0
- package/package.json +71 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { t as tokenize } from "../tokenize-C-Zp26iY.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/parts.ts
|
|
4
|
+
/**
|
|
5
|
+
* Builds the {@link UIParts} namespace bound to a message's `DATA` and `TOOLS` types. The runtime is
|
|
6
|
+
* identical for every binding; the type parameters only sharpen `data` and `tool`. Use the top-level
|
|
7
|
+
* {@link UIParts} for the loose default, or `fromUIMessage` to bind.
|
|
8
|
+
*/
|
|
9
|
+
const createUIParts = () => ({
|
|
10
|
+
text: (text, opts) => ({
|
|
11
|
+
type: "text",
|
|
12
|
+
text,
|
|
13
|
+
...opts
|
|
14
|
+
}),
|
|
15
|
+
reasoning: (text, opts) => ({
|
|
16
|
+
type: "reasoning",
|
|
17
|
+
text,
|
|
18
|
+
...opts
|
|
19
|
+
}),
|
|
20
|
+
sourceUrl: (args) => ({
|
|
21
|
+
type: "source-url",
|
|
22
|
+
...args
|
|
23
|
+
}),
|
|
24
|
+
sourceDocument: (args) => ({
|
|
25
|
+
type: "source-document",
|
|
26
|
+
...args
|
|
27
|
+
}),
|
|
28
|
+
file: (args) => ({
|
|
29
|
+
type: "file",
|
|
30
|
+
...args
|
|
31
|
+
}),
|
|
32
|
+
stepStart: () => ({ type: "step-start" }),
|
|
33
|
+
data: (name, data, opts = {}) => ({
|
|
34
|
+
type: `data-${name}`,
|
|
35
|
+
data,
|
|
36
|
+
...opts
|
|
37
|
+
}),
|
|
38
|
+
tool: (name, invocation) => ({
|
|
39
|
+
type: `tool-${name}`,
|
|
40
|
+
...invocation
|
|
41
|
+
}),
|
|
42
|
+
dynamicTool: (args) => ({
|
|
43
|
+
type: "dynamic-tool",
|
|
44
|
+
...args
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
/** Builders for `UIMessagePart`s, with loose default types. Use `fromUIMessage` to bind to a message type. */
|
|
48
|
+
const UIParts = createUIParts();
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/ui/chunks.ts
|
|
52
|
+
/**
|
|
53
|
+
* Builds the {@link UIChunks} namespace bound to a message's `METADATA` and `DATA` types. The runtime
|
|
54
|
+
* is identical for every binding; the type parameters only sharpen `data`, `start`, `finish`, and
|
|
55
|
+
* `messageMetadata`. Use the top-level {@link UIChunks} for the loose default, or `fromUIMessage` to bind.
|
|
56
|
+
*/
|
|
57
|
+
const createUIChunks = () => ({
|
|
58
|
+
textStart: (args) => ({
|
|
59
|
+
type: "text-start",
|
|
60
|
+
...args
|
|
61
|
+
}),
|
|
62
|
+
textDelta: (args) => ({
|
|
63
|
+
type: "text-delta",
|
|
64
|
+
...args
|
|
65
|
+
}),
|
|
66
|
+
textEnd: (args) => ({
|
|
67
|
+
type: "text-end",
|
|
68
|
+
...args
|
|
69
|
+
}),
|
|
70
|
+
reasoningStart: (args) => ({
|
|
71
|
+
type: "reasoning-start",
|
|
72
|
+
...args
|
|
73
|
+
}),
|
|
74
|
+
reasoningDelta: (args) => ({
|
|
75
|
+
type: "reasoning-delta",
|
|
76
|
+
...args
|
|
77
|
+
}),
|
|
78
|
+
reasoningEnd: (args) => ({
|
|
79
|
+
type: "reasoning-end",
|
|
80
|
+
...args
|
|
81
|
+
}),
|
|
82
|
+
error: (errorText) => ({
|
|
83
|
+
type: "error",
|
|
84
|
+
errorText
|
|
85
|
+
}),
|
|
86
|
+
toolInputStart: (args) => ({
|
|
87
|
+
type: "tool-input-start",
|
|
88
|
+
...args
|
|
89
|
+
}),
|
|
90
|
+
toolInputDelta: (args) => ({
|
|
91
|
+
type: "tool-input-delta",
|
|
92
|
+
...args
|
|
93
|
+
}),
|
|
94
|
+
toolInputAvailable: (args) => ({
|
|
95
|
+
type: "tool-input-available",
|
|
96
|
+
...args
|
|
97
|
+
}),
|
|
98
|
+
toolInputError: (args) => ({
|
|
99
|
+
type: "tool-input-error",
|
|
100
|
+
...args
|
|
101
|
+
}),
|
|
102
|
+
toolApprovalRequest: (args) => ({
|
|
103
|
+
type: "tool-approval-request",
|
|
104
|
+
...args
|
|
105
|
+
}),
|
|
106
|
+
toolOutputAvailable: (args) => ({
|
|
107
|
+
type: "tool-output-available",
|
|
108
|
+
...args
|
|
109
|
+
}),
|
|
110
|
+
toolOutputError: (args) => ({
|
|
111
|
+
type: "tool-output-error",
|
|
112
|
+
...args
|
|
113
|
+
}),
|
|
114
|
+
toolOutputDenied: (args) => ({
|
|
115
|
+
type: "tool-output-denied",
|
|
116
|
+
...args
|
|
117
|
+
}),
|
|
118
|
+
sourceUrl: (args) => ({
|
|
119
|
+
type: "source-url",
|
|
120
|
+
...args
|
|
121
|
+
}),
|
|
122
|
+
sourceDocument: (args) => ({
|
|
123
|
+
type: "source-document",
|
|
124
|
+
...args
|
|
125
|
+
}),
|
|
126
|
+
file: (args) => ({
|
|
127
|
+
type: "file",
|
|
128
|
+
...args
|
|
129
|
+
}),
|
|
130
|
+
data: (name, data, opts = {}) => ({
|
|
131
|
+
type: `data-${name}`,
|
|
132
|
+
data,
|
|
133
|
+
...opts
|
|
134
|
+
}),
|
|
135
|
+
startStep: () => ({ type: "start-step" }),
|
|
136
|
+
finishStep: () => ({ type: "finish-step" }),
|
|
137
|
+
start: (args) => ({
|
|
138
|
+
type: "start",
|
|
139
|
+
...args
|
|
140
|
+
}),
|
|
141
|
+
finish: (args) => ({
|
|
142
|
+
type: "finish",
|
|
143
|
+
...args
|
|
144
|
+
}),
|
|
145
|
+
abort: (args) => ({
|
|
146
|
+
type: "abort",
|
|
147
|
+
...args
|
|
148
|
+
}),
|
|
149
|
+
messageMetadata: (messageMetadata) => ({
|
|
150
|
+
type: "message-metadata",
|
|
151
|
+
messageMetadata
|
|
152
|
+
}),
|
|
153
|
+
text: (text, { id = "1", length, separator } = {}) => [
|
|
154
|
+
{
|
|
155
|
+
type: "text-start",
|
|
156
|
+
id
|
|
157
|
+
},
|
|
158
|
+
...tokenize(text, {
|
|
159
|
+
length,
|
|
160
|
+
separator
|
|
161
|
+
}).map((delta) => ({
|
|
162
|
+
type: "text-delta",
|
|
163
|
+
id,
|
|
164
|
+
delta
|
|
165
|
+
})),
|
|
166
|
+
{
|
|
167
|
+
type: "text-end",
|
|
168
|
+
id
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
reasoning: (text, { id = "1", length, separator } = {}) => [
|
|
172
|
+
{
|
|
173
|
+
type: "reasoning-start",
|
|
174
|
+
id
|
|
175
|
+
},
|
|
176
|
+
...tokenize(text, {
|
|
177
|
+
length,
|
|
178
|
+
separator
|
|
179
|
+
}).map((delta) => ({
|
|
180
|
+
type: "reasoning-delta",
|
|
181
|
+
id,
|
|
182
|
+
delta
|
|
183
|
+
})),
|
|
184
|
+
{
|
|
185
|
+
type: "reasoning-end",
|
|
186
|
+
id
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
toolInput: (args) => [
|
|
190
|
+
{
|
|
191
|
+
type: "tool-input-start",
|
|
192
|
+
toolCallId: args.toolCallId,
|
|
193
|
+
toolName: args.toolName
|
|
194
|
+
},
|
|
195
|
+
...tokenize(JSON.stringify(args.input), { length: args.length }).map((inputTextDelta) => ({
|
|
196
|
+
type: "tool-input-delta",
|
|
197
|
+
toolCallId: args.toolCallId,
|
|
198
|
+
inputTextDelta
|
|
199
|
+
})),
|
|
200
|
+
{
|
|
201
|
+
type: "tool-input-available",
|
|
202
|
+
toolCallId: args.toolCallId,
|
|
203
|
+
toolName: args.toolName,
|
|
204
|
+
input: args.input
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
});
|
|
208
|
+
/** Builders for `UIMessageChunk`s, with loose default types. Use `fromUIMessage` to bind to a message type. */
|
|
209
|
+
const UIChunks = createUIChunks();
|
|
210
|
+
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/ui/message.ts
|
|
213
|
+
/** Monotonic counter backing the auto-generated message ids. */
|
|
214
|
+
let messageCounter = 0;
|
|
215
|
+
/** Returns the next unique auto-generated message id. */
|
|
216
|
+
const nextMessageId = () => {
|
|
217
|
+
messageCounter += 1;
|
|
218
|
+
return `mock-message-${messageCounter}`;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Builds the {@link UIMessages} namespace bound to a message's `METADATA`, `DATA`, and `TOOLS` types.
|
|
222
|
+
* Each role helper accepts a `string` shortcut (becomes a single text part) or a full array of parts.
|
|
223
|
+
* Use the top-level {@link UIMessages} for the loose default, or `fromUIMessage` to bind.
|
|
224
|
+
*/
|
|
225
|
+
const createUIMessages = () => {
|
|
226
|
+
/** Normalizes a string shortcut into a single text part, or passes an array of parts through. */
|
|
227
|
+
const toParts = (content) => typeof content === "string" ? [{
|
|
228
|
+
type: "text",
|
|
229
|
+
text: content
|
|
230
|
+
}] : content;
|
|
231
|
+
/** Assembles a message of the given role from content and options. */
|
|
232
|
+
const build = (role, content, opts) => ({
|
|
233
|
+
id: opts.id ?? nextMessageId(),
|
|
234
|
+
role,
|
|
235
|
+
parts: toParts(content),
|
|
236
|
+
...opts.metadata !== void 0 ? { metadata: opts.metadata } : {}
|
|
237
|
+
});
|
|
238
|
+
return {
|
|
239
|
+
user: (content, opts = {}) => build("user", content, opts),
|
|
240
|
+
assistant: (content, opts = {}) => build("assistant", content, opts),
|
|
241
|
+
system: (content, opts = {}) => build("system", content, opts)
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
/** Builders for `UIMessage`s, with loose default types. Use `fromUIMessage` to bind to a message type. */
|
|
245
|
+
const UIMessages = createUIMessages();
|
|
246
|
+
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/ui/from-ui-message.ts
|
|
249
|
+
/**
|
|
250
|
+
* Binds the UI builders to a concrete `UIMessage` type, so `data`/`tool`/`messageMetadata` and message
|
|
251
|
+
* metadata infer their names and payloads from that type. Returns typed `UIParts`, `UIChunks`, and
|
|
252
|
+
* `UIMessages` namespaces; for loose, untyped builders use the top-level exports instead.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* const { UIParts, UIChunks, UIMessages } = fromUIMessage<MyUIMessage>();
|
|
256
|
+
* UIChunks.data('weather', { city: 'Tokyo' }); // name and payload typed
|
|
257
|
+
* UIMessages.assistant([UIParts.text('hi')]);
|
|
258
|
+
*/
|
|
259
|
+
const fromUIMessage = () => ({
|
|
260
|
+
UIParts: createUIParts(),
|
|
261
|
+
UIChunks: createUIChunks(),
|
|
262
|
+
UIMessages: createUIMessages()
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
//#endregion
|
|
266
|
+
export { UIChunks, UIMessages, UIParts, createUIChunks, createUIMessages, createUIParts, fromUIMessage };
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-test-kit",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Test utilities for the AI SDK: mock models, content and stream-part builders, fully type-safe",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Chris Cook",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/zirkelc/ai-test-kit.git"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"types": "dist/index.d.mts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": "./dist/index.mjs",
|
|
19
|
+
"./language": "./dist/language/index.mjs",
|
|
20
|
+
"./ui": "./dist/ui/index.mjs",
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"prepublishOnly": "pnpm build",
|
|
28
|
+
"build": "tsdown",
|
|
29
|
+
"test": "vitest",
|
|
30
|
+
"lint": "oxlint --fix",
|
|
31
|
+
"lint:ci": "oxlint",
|
|
32
|
+
"format": "oxfmt --write",
|
|
33
|
+
"format:ci": "oxfmt --check",
|
|
34
|
+
"prepare": "husky"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@ai-sdk/provider": "^3.0.10",
|
|
38
|
+
"@ai-sdk/provider-utils": "^4.0.27",
|
|
39
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
40
|
+
"@total-typescript/tsconfig": "^1.0.4",
|
|
41
|
+
"@types/node": "^25.2.3",
|
|
42
|
+
"ai": "^6.0.197",
|
|
43
|
+
"husky": "^9.1.7",
|
|
44
|
+
"lint-staged": "^16.2.7",
|
|
45
|
+
"oxfmt": "^0.30.0",
|
|
46
|
+
"oxlint": "^1.45.0",
|
|
47
|
+
"oxlint-tsgolint": "^0.11.5",
|
|
48
|
+
"pkg-pr-new": "^0.0.63",
|
|
49
|
+
"publint": "^0.3.17",
|
|
50
|
+
"tsdown": "^0.20.3",
|
|
51
|
+
"tsx": "^4.21.0",
|
|
52
|
+
"typescript": "^5.9.3",
|
|
53
|
+
"vitest": "^4.0.18"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@ai-sdk/provider": "^3.0.0",
|
|
57
|
+
"@ai-sdk/provider-utils": "^4.0.0",
|
|
58
|
+
"ai": "5.x || 6.x",
|
|
59
|
+
"vitest": ">=3"
|
|
60
|
+
},
|
|
61
|
+
"lint-staged": {
|
|
62
|
+
"*.{js,ts,tsx,jsx}": [
|
|
63
|
+
"pnpm lint",
|
|
64
|
+
"pnpm format"
|
|
65
|
+
],
|
|
66
|
+
"*.{json,jsonc}": [
|
|
67
|
+
"pnpm format"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"packageManager": "pnpm@10.29.2"
|
|
71
|
+
}
|