chatkit-bun 0.0.2
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/README.md +202 -0
- package/package.json +40 -0
- package/src/actions.ts +39 -0
- package/src/agents/accumulate.ts +43 -0
- package/src/agents/annotations.ts +157 -0
- package/src/agents/context.ts +190 -0
- package/src/agents/converter.ts +290 -0
- package/src/agents/index.ts +25 -0
- package/src/agents/stream.ts +1053 -0
- package/src/agents/types.ts +30 -0
- package/src/agents/workflows.ts +220 -0
- package/src/errors.ts +19 -0
- package/src/http.ts +60 -0
- package/src/index.ts +11 -0
- package/src/serialization.ts +75 -0
- package/src/server.ts +874 -0
- package/src/sqlite-store.ts +400 -0
- package/src/store.ts +98 -0
- package/src/types/core.ts +322 -0
- package/src/types/server.ts +396 -0
- package/src/widgets/components.ts +188 -0
- package/src/widgets/diff.ts +151 -0
- package/src/widgets/index.ts +6 -0
- package/src/widgets/serialization.ts +46 -0
- package/src/widgets/stream.ts +104 -0
- package/src/widgets/template.ts +180 -0
- package/src/widgets/types.ts +52 -0
- package/types/actions.d.ts +19 -0
- package/types/agents/accumulate.d.ts +4 -0
- package/types/agents/annotations.d.ts +21 -0
- package/types/agents/context.d.ts +35 -0
- package/types/agents/converter.d.ts +60 -0
- package/types/agents/index.d.ts +9 -0
- package/types/agents/stream.d.ts +4 -0
- package/types/agents/types.d.ts +26 -0
- package/types/agents/workflows.d.ts +34 -0
- package/types/errors.d.ts +11 -0
- package/types/http.d.ts +6 -0
- package/types/index.d.ts +11 -0
- package/types/serialization.d.ts +8 -0
- package/types/server.d.ts +73 -0
- package/types/sqlite-store.d.ts +43 -0
- package/types/store.d.ts +45 -0
- package/types/types/core.d.ts +1220 -0
- package/types/types/server.d.ts +5841 -0
- package/types/widgets/components.d.ts +144 -0
- package/types/widgets/diff.d.ts +7 -0
- package/types/widgets/index.d.ts +6 -0
- package/types/widgets/serialization.d.ts +2 -0
- package/types/widgets/stream.d.ts +10 -0
- package/types/widgets/template.d.ts +19 -0
- package/types/widgets/types.d.ts +24 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import type { AgentInputItem } from "@openai/agents";
|
|
2
|
+
|
|
3
|
+
import type { Attachment, ThreadItem, UserMessageContent } from "../types/core";
|
|
4
|
+
import { serializeWidget } from "../widgets";
|
|
5
|
+
|
|
6
|
+
export type UserMessageItem = Extract<ThreadItem, { type: "user_message" }>;
|
|
7
|
+
export type AssistantMessageItem = Extract<ThreadItem, { type: "assistant_message" }>;
|
|
8
|
+
export type ClientToolCallItem = Extract<ThreadItem, { type: "client_tool_call" }>;
|
|
9
|
+
export type WidgetItem = Extract<ThreadItem, { type: "widget" }>;
|
|
10
|
+
export type GeneratedImageItem = Extract<ThreadItem, { type: "generated_image" }>;
|
|
11
|
+
export type StructuredInputItem = Extract<ThreadItem, { type: "structured_input" }>;
|
|
12
|
+
export type TaskItem = Extract<ThreadItem, { type: "task" }>;
|
|
13
|
+
export type WorkflowItem = Extract<ThreadItem, { type: "workflow" }>;
|
|
14
|
+
export type HiddenContextItem = Extract<ThreadItem, { type: "hidden_context_item" }>;
|
|
15
|
+
export type SDKHiddenContextItem = Extract<ThreadItem, { type: "sdk_hidden_context" }>;
|
|
16
|
+
export type EndOfTurnItem = Extract<ThreadItem, { type: "end_of_turn" }>;
|
|
17
|
+
export type UserMessageTagContent = Extract<UserMessageContent, { type: "input_tag" }>;
|
|
18
|
+
|
|
19
|
+
export type AgentUserMessageItem = Extract<AgentInputItem, { role: "user" }>;
|
|
20
|
+
export type AgentMessageContentPart = Exclude<AgentUserMessageItem["content"], string>[number];
|
|
21
|
+
export type ThreadItemConverterResult = AgentInputItem | AgentInputItem[] | null | undefined;
|
|
22
|
+
|
|
23
|
+
function normalizeInput(input: ThreadItemConverterResult): AgentInputItem[] {
|
|
24
|
+
if (input == null) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
return Array.isArray(input) ? input : [input];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function userInputMessage(content: AgentUserMessageItem["content"]): AgentInputItem {
|
|
31
|
+
return { type: "message", role: "user", content };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function customTaskText(task: Extract<TaskItem["task"], { type: "custom" }>): string | null {
|
|
35
|
+
const title = task.title ?? "";
|
|
36
|
+
const content = task.content ?? "";
|
|
37
|
+
if (!title && !content) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return title && content ? `${title}: ${content}` : title || content;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function taskMessage(text: string): AgentInputItem {
|
|
44
|
+
return userInputMessage([
|
|
45
|
+
{
|
|
46
|
+
type: "input_text",
|
|
47
|
+
text: `A message was displayed to the user that the following task was performed:\n<Task>\n${text}\n</Task>`,
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class ThreadItemConverter {
|
|
53
|
+
attachmentToMessageContent(_attachment: Attachment): AgentMessageContentPart | Promise<AgentMessageContentPart> {
|
|
54
|
+
throw new Error(
|
|
55
|
+
"An Attachment was included in a UserMessageItem but ThreadItemConverter.attachmentToMessageContent was not implemented",
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
tagToMessageContent(_tag: UserMessageTagContent): AgentMessageContentPart | Promise<AgentMessageContentPart> {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"A Tag was included in a UserMessageItem but ThreadItemConverter.tagToMessageContent was not implemented",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
generatedImageToInput(item: GeneratedImageItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
66
|
+
if (!item.image) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return userInputMessage([
|
|
70
|
+
{ type: "input_text", text: "The following image was generated by the agent." },
|
|
71
|
+
{ type: "input_image", image: item.image.url, detail: "auto" },
|
|
72
|
+
]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
hiddenContextToInput(item: HiddenContextItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
76
|
+
if (typeof item.content !== "string") {
|
|
77
|
+
throw new Error(
|
|
78
|
+
"HiddenContextItems with non-string content were present but ThreadItemConverter.hiddenContextToInput was not implemented for non-string content",
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return this.sdkHiddenContextToInput({ ...item, type: "sdk_hidden_context", content: item.content });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
sdkHiddenContextToInput(item: SDKHiddenContextItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
85
|
+
return userInputMessage([
|
|
86
|
+
{
|
|
87
|
+
type: "input_text",
|
|
88
|
+
text:
|
|
89
|
+
"Hidden context for the agent (not shown to the user):\n" +
|
|
90
|
+
`<HiddenContext>\n${item.content}\n</HiddenContext>`,
|
|
91
|
+
},
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
taskToInput(item: TaskItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
96
|
+
if (item.task.type !== "custom") {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const text = customTaskText(item.task);
|
|
100
|
+
return text ? taskMessage(text) : null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
workflowToInput(item: WorkflowItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
104
|
+
return item.workflow.tasks.flatMap((task) => {
|
|
105
|
+
if (task.type !== "custom") {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
const text = customTaskText(task);
|
|
109
|
+
return text ? [taskMessage(text)] : [];
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async widgetToInput(item: WidgetItem): Promise<ThreadItemConverterResult> {
|
|
114
|
+
const widget = serializeWidget(item.widget as Parameters<typeof serializeWidget>[0]);
|
|
115
|
+
return userInputMessage([
|
|
116
|
+
{
|
|
117
|
+
type: "input_text",
|
|
118
|
+
text: `The following graphical UI widget (id: ${item.id}) was displayed to the user:${JSON.stringify(widget)}`,
|
|
119
|
+
},
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
structuredInputToInput(item: StructuredInputItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
124
|
+
const lines = item.inputs.map((input) => {
|
|
125
|
+
if (!input.answer) {
|
|
126
|
+
return `- ${input.question}: unanswered`;
|
|
127
|
+
}
|
|
128
|
+
if (input.answer.skipped) {
|
|
129
|
+
return `- ${input.question}: skipped`;
|
|
130
|
+
}
|
|
131
|
+
return `- ${input.question}: ${input.answer.values.join(", ")}`;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return userInputMessage([
|
|
135
|
+
{
|
|
136
|
+
type: "input_text",
|
|
137
|
+
text:
|
|
138
|
+
`A structured input request was displayed to the user with the following status: ${item.status}\n` +
|
|
139
|
+
"<StructuredInput>\n" +
|
|
140
|
+
lines.join("\n") +
|
|
141
|
+
"\n</StructuredInput>",
|
|
142
|
+
},
|
|
143
|
+
]);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async userMessageToInput(item: UserMessageItem, isLastMessage = true): Promise<ThreadItemConverterResult> {
|
|
147
|
+
const messageTextParts: string[] = [];
|
|
148
|
+
const tagParts: UserMessageTagContent[] = [];
|
|
149
|
+
|
|
150
|
+
for (const part of item.content) {
|
|
151
|
+
if (part.type === "input_text") {
|
|
152
|
+
messageTextParts.push(part.text);
|
|
153
|
+
} else {
|
|
154
|
+
messageTextParts.push(`@${part.text}`);
|
|
155
|
+
tagParts.push(part);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const userMessage = userInputMessage([
|
|
160
|
+
{ type: "input_text", text: messageTextParts.join("") },
|
|
161
|
+
...(await Promise.all(item.attachments.map((attachment) => this.attachmentToMessageContent(attachment)))),
|
|
162
|
+
]);
|
|
163
|
+
const contextMessages: AgentInputItem[] = [];
|
|
164
|
+
|
|
165
|
+
if (item.quoted_text && isLastMessage) {
|
|
166
|
+
contextMessages.push(
|
|
167
|
+
userInputMessage([
|
|
168
|
+
{
|
|
169
|
+
type: "input_text",
|
|
170
|
+
text: `The user is referring to this in particular: \n${item.quoted_text}`,
|
|
171
|
+
},
|
|
172
|
+
]),
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (tagParts.length > 0) {
|
|
177
|
+
const seen = new Set<string>();
|
|
178
|
+
const uniqueTags = tagParts.filter((tag) => {
|
|
179
|
+
if (seen.has(tag.text)) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
seen.add(tag.text);
|
|
183
|
+
return true;
|
|
184
|
+
});
|
|
185
|
+
const tagContent = await Promise.all(uniqueTags.map((tag) => this.tagToMessageContent(tag)));
|
|
186
|
+
contextMessages.push(
|
|
187
|
+
userInputMessage([
|
|
188
|
+
{
|
|
189
|
+
type: "input_text",
|
|
190
|
+
text:
|
|
191
|
+
"# User-provided context for @-mentions\n" +
|
|
192
|
+
"- When referencing resolved entities, use their canonical names **without** '@'.\n" +
|
|
193
|
+
"- The '@' form appears only in user text and should not be echoed.",
|
|
194
|
+
},
|
|
195
|
+
...tagContent,
|
|
196
|
+
]),
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return [userMessage, ...contextMessages];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
assistantMessageToInput(item: AssistantMessageItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
204
|
+
return {
|
|
205
|
+
type: "message",
|
|
206
|
+
role: "assistant",
|
|
207
|
+
status: "completed",
|
|
208
|
+
content: item.content.map((content) => ({ type: "output_text", text: content.text })),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
clientToolCallToInput(item: ClientToolCallItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
213
|
+
if (item.status === "pending") {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
return [
|
|
217
|
+
{
|
|
218
|
+
type: "function_call",
|
|
219
|
+
name: item.name,
|
|
220
|
+
callId: item.call_id,
|
|
221
|
+
arguments: JSON.stringify(item.arguments),
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
type: "function_call_result",
|
|
225
|
+
name: item.name,
|
|
226
|
+
callId: item.call_id,
|
|
227
|
+
status: "completed",
|
|
228
|
+
output: JSON.stringify(item.output ?? null),
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
endOfTurnToInput(_item: EndOfTurnItem): ThreadItemConverterResult | Promise<ThreadItemConverterResult> {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async toAgentInput(threadItems: ThreadItem | readonly ThreadItem[]): Promise<AgentInputItem[]> {
|
|
238
|
+
const items = Array.isArray(threadItems) ? [...threadItems] : [threadItems];
|
|
239
|
+
const lastUserMessageIndex = items.findLastIndex((item) => item.type === "user_message");
|
|
240
|
+
const output: AgentInputItem[] = [];
|
|
241
|
+
|
|
242
|
+
for (const [index, item] of items.entries()) {
|
|
243
|
+
switch (item.type) {
|
|
244
|
+
case "user_message":
|
|
245
|
+
output.push(...normalizeInput(await this.userMessageToInput(item, index === lastUserMessageIndex)));
|
|
246
|
+
break;
|
|
247
|
+
case "assistant_message":
|
|
248
|
+
output.push(...normalizeInput(await this.assistantMessageToInput(item)));
|
|
249
|
+
break;
|
|
250
|
+
case "widget":
|
|
251
|
+
output.push(...normalizeInput(await this.widgetToInput(item)));
|
|
252
|
+
break;
|
|
253
|
+
case "generated_image":
|
|
254
|
+
output.push(...normalizeInput(await this.generatedImageToInput(item)));
|
|
255
|
+
break;
|
|
256
|
+
case "hidden_context_item":
|
|
257
|
+
output.push(...normalizeInput(await this.hiddenContextToInput(item)));
|
|
258
|
+
break;
|
|
259
|
+
case "sdk_hidden_context":
|
|
260
|
+
output.push(...normalizeInput(await this.sdkHiddenContextToInput(item)));
|
|
261
|
+
break;
|
|
262
|
+
case "client_tool_call":
|
|
263
|
+
output.push(...normalizeInput(await this.clientToolCallToInput(item)));
|
|
264
|
+
break;
|
|
265
|
+
case "structured_input":
|
|
266
|
+
output.push(...normalizeInput(await this.structuredInputToInput(item)));
|
|
267
|
+
break;
|
|
268
|
+
case "task":
|
|
269
|
+
output.push(...normalizeInput(await this.taskToInput(item)));
|
|
270
|
+
break;
|
|
271
|
+
case "workflow":
|
|
272
|
+
output.push(...normalizeInput(await this.workflowToInput(item)));
|
|
273
|
+
break;
|
|
274
|
+
case "end_of_turn":
|
|
275
|
+
output.push(...normalizeInput(await this.endOfTurnToInput(item)));
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return output;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const defaultThreadItemConverter = new ThreadItemConverter();
|
|
287
|
+
|
|
288
|
+
export function simpleToAgentInput(threadItems: ThreadItem | readonly ThreadItem[]): Promise<AgentInputItem[]> {
|
|
289
|
+
return defaultThreadItemConverter.toAgentInput(threadItems);
|
|
290
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export { ResponseStreamConverter, defaultResponseStreamConverter } from "./annotations";
|
|
2
|
+
export type { ResponseStreamConverterOptions } from "./annotations";
|
|
3
|
+
export { accumulateText } from "./accumulate";
|
|
4
|
+
export type { AccumulatableTextWidget } from "./accumulate";
|
|
5
|
+
export { ThreadItemConverter, simpleToAgentInput } from "./converter";
|
|
6
|
+
export type {
|
|
7
|
+
AgentMessageContentPart,
|
|
8
|
+
AgentUserMessageItem,
|
|
9
|
+
AssistantMessageItem,
|
|
10
|
+
ClientToolCallItem,
|
|
11
|
+
EndOfTurnItem,
|
|
12
|
+
GeneratedImageItem,
|
|
13
|
+
HiddenContextItem,
|
|
14
|
+
SDKHiddenContextItem,
|
|
15
|
+
StructuredInputItem,
|
|
16
|
+
TaskItem,
|
|
17
|
+
ThreadItemConverterResult,
|
|
18
|
+
UserMessageItem,
|
|
19
|
+
UserMessageTagContent,
|
|
20
|
+
WidgetItem,
|
|
21
|
+
WorkflowItem,
|
|
22
|
+
} from "./converter";
|
|
23
|
+
export { AgentContext, ClientToolCall } from "./context";
|
|
24
|
+
export { streamAgentResponse } from "./stream";
|
|
25
|
+
export type { AgentContextOptions, AgentStreamInput, StreamAgentResponseOptions } from "./types";
|